1樓:Yanan Xie
高一的時候(2023年)維護過一段時間的Vijos,在我接手前評測端並沒有任何保護措施,也很少出問題(懷念那個時候大家的單純美好)。後來使用者量快速變多了之後就有不少使用者來找麻煩。
因為評測服務是乙個.Net的service,最初所有被評測的程式都是以system許可權執行的(想想都有點可怕)。後來專門為被測試程式建了乙個低許可權的使用者分組並限制執行記憶體。
結果發現還是有使用者往一些奇怪的地方寫東西,維護起來比較麻煩。於是最後就把整個評測端移到虛擬機器裡面去了。那個時候的虛擬機器IO效能比較差,尤其是readln能比read慢個好幾倍。。。
2樓:Jim Liu
我們大學的時候做的OJ對於這個問題處理極其簡單:
1、使用乙個許可權極度少的windows賬號,除了乙個隨機名字的臨時目錄以外其他什麼路徑許可權都沒有。
2、遮蔽掉windows.h。和一堆標頭檔案。
那是懵懂時期,僅供參考
3樓:Belleve
最徹底的做法是用 bochs + 定做乙個最小化的作業系統,編譯器完全設定為交叉編譯,編譯完了用 bochs 跑,用虛擬的串列埠 IO。這樣做出來的是能防小人的,比如要是有人把某函式指標指向的記憶體裡故意寫 int 80h,這方法能保證防住。
4樓:馬巨集菩
其實這就是在做乙個沙盒,而乙個可靠的沙盒不是那麼簡單的。我簡單說一些高中時寫 OJ 獲得的經驗,拋磚引玉。
幾個錯誤做法:
所有的字串過濾都是耍流氓,坑人坑自己:C語言強大的巨集幾乎沒有繞不過的字串過濾,而且誤傷也是很常見的(我就見過小白 OIer 問為什麼程式老是被判非法,結果一看裡頭有個變數叫做 fork )。
手工審計標頭檔案,去掉某些標頭檔案或者注釋掉一些部分是辛苦且無用的:做了這樣的工作之後,你就幾乎再也不會想去公升級編譯器及標頭檔案了,更可怕的是——這個工作需要你對語言、編譯器、聯結器有一定程度的了解,而我認為擁有足夠了解的人都應該知道這是不靠譜的:就算沒有標頭檔案、沒有了函式原型,呼叫系統呼叫的方法還是有一大把而且都不是很麻煩。
準備工作:
熟悉你的目標系統(Windows or Linux):
必須要了解這個平台下的原生系統呼叫 API 是怎麼使用的(不然你要怎麼遮蔽?),最好可以了解到彙編層面。
必須要了解這個平台下的使用者系統、許可權控制、資源限制。
最好要了解一下程序跟蹤/除錯/監控工具或者系統呼叫,例如 Linux 下的 ptrace 。
最好要了解目標系統提供的各種沙盒限制功能。
了解你的程式語言及工具鏈:
必須要了解你的目標語言的特性,及其在一般的 OI / ACM 比賽中的規定、限制。
必須要了解你的工具鏈的功能及各種引數。
擁有足夠的程式設計功底,對於這樣小的程式,應當嚴格杜絕緩衝區溢位之類的 bug 。
然後我再說說我的做法,在其中大家就可以看到上面列的這些「準備知識」是如何派上用場的。我的目標平台是 Linux ,目標語言是 Pascal 、 C 、 C++ 。
我採取了以下措施:
作業系統層面:
時間、資源的限制:
記憶體:我使用了 rlimit 進行控制,同時也方便在執行結束後獲得記憶體使用情況的資料,不過有乙個「缺點」就是如果是宣告了乙個超大的空間但從未訪問使用就不會被統計進來(經過觀察發現很多 ACM 或者 OI 比賽也都是這麼處理的,所以應該不算是乙個問題)。
檔案控制代碼:同樣可以通過 rlimit 來實現,以保證程式不要開啟太多檔案。不過其實檔案這一塊問題是比較多的,如果可行的話最好還是使用 stdio 然後管道重定向,完全禁止程式的檔案 IO 操作。
訪問控制:
通過 chroot 建立乙個 jail ,將程式限制在指定目錄中執行。由於是比賽程式,使用的動態鏈結庫很有限,所以直接靜態編譯,從而使得執行目錄中連 .so 都不需要。
進行必要的許可權控制,例如將輸入檔案和程式檔案本身設定為程式的執行使用者唯讀不可寫。
許可權控制:
監控程式使用 root 許可權執行, 完成必要準備後 fork 並切換為受限使用者(比如 nobody )來執行程式。
rlimit 設定的都是 hard limit ,非 root 無法修改。
正確設定執行使用者之後,之前由 root 創造的 jail 受限使用者是無法逃出的。
系統呼叫控制:
上面這些(尤其是第一步)是有很大問題,就算不是 root ,也還能做到很多事情。且不說 fork 之類的,光是那個 alarm ,就可以很輕鬆的把計時器取消了或者乾脆主動接收這個訊號。所以最根本的還是需要使用 ptrace 之類的偵錯程式附著上程式,監控所有的系統呼叫,進行白名單 + 計數器(比如 exec 和 open )過濾。
這一步其實是最麻煩的(不同平台的系統呼叫號不一樣,我們使用的是 strace 專案裡頭整理的呼叫號)。
更進一步:
如果你對作業系統更熟悉,那麼還有一些更有趣的事情可以做。比如 Linux 下的 seccomp 功能(seccomp - Wikipedia , Chrome Linux 版就在沙盒中使用了這個技術 ),尤其是後期加入了 seccomp-bpf 之後變得更加易用。還比如 SELinux 也可以作為 defend-by-depth 的一環。
另外, cgroup 其實也可以用得上。
編譯層面:
很多編譯工具都提供了強大的引數控制,允許你進行包括禁用內嵌 ASM 、限制連線路徑之類的一些操作。通讀一遍 manpage 肯定會有幫助的。
小心編譯期間的一些「高階功能」,比如 C 的 include 其實是有很多巧妙的用法,試試看在 Linux 下 #include "/dev/random" 或者 #include "/dev/tty" 之類的(這兩個東西會把網路上不少二流 OJ 直接卡死……)。
不要使用 root 使用者編譯,越複雜的程式越容易有 bug ,萬一哪天出個編譯器的 0day ……
考慮給編譯過程同樣進行時間、資源限制以作為額外防護手段。
架構層面:
執行在虛擬機器/容器中
快照心跳檢測
你會發現,其實主要的限制都是在作業系統層面完成的。我認為,這樣做才能帶來更高的安全性,因為引發、啟動危險操作的方法有很多,很難一一杜絕(包括原始碼分析、編譯時限制等),但最後要讓這些危險操作起效幾乎都需要落回系統呼叫上,所以直接從這裡下手也許會是個更好的辦法。
最後是我之前寫的沙盒專案,寫得很醜,尤其是 ptrace 一塊目前還比較坑(64位系統下好像還無法正常工作),總的來講還只能算是乙個 demo 而已:Hexcles/Eevee · GitHub
5樓:
How do sites like codepad.org and ideone.com sandbox your program?
下面有個回答講得很詳細
6樓:肖進
使用的是windows作業系統。
使用乙個無許可權的使用者,僅僅允許讀取與執行目標檔案目錄,其它全部設為拒絕訪問。
使用job限制執行緒與程序的建立,物理記憶體的使用。
服務執行在host only模式的虛擬機器中,隔絕廣域網。
如何解釋醋是鹼性食品?
Gushoushou 設定食物酸鹼性的定義為 食物在體內消化後最終代謝產物的酸鹼性,這裡有兩個關鍵指標 1 食物,即食物初始的化學組成 2 最終代謝點,即食物被徹底消化後的狀態。醋的釀造原料多為穀物,穀物主要成分,第一是碳 氫 氧等有機體的主成分,其次是氮 磷 硫等非金屬元素,第三是鉀 鈣 鈉等金屬...
如何解 辣 ?
守公子 來,我用親身經歷告訴你怎麼解辣。酒類,伏特加,特別辣的時候恰一口伏特加,瞬間嘴裡就沒有辣味了。飲料類,冰糖雪梨,特別辣的時候喝一口,就瞬間神清氣爽。我為什麼會知道?我乙個衢州人,在蘇杭混了五六年,回家吃飯很頭疼好嗎 月半木公 說那些化學原理都木有用,實踐才能出真知!我是東北人,本來不能吃辣,...
我想知道厲害的人做題是如何思考的,是如何解決問題的。想知道具體過程是如何操作的?
蔡軍 這個問題,其實對我來說有點超綱來著,因為我做題厲害但是一直不知道怎麼教別人。我只說說我個人的經歷,具體精細化的拆分步驟可能要等哪位教育學大大下場了。自認還算是學霸 高中及以前 但是總有一種 自然而然 的感覺。每次假期包括高考完,家人都讓我去開補習班賺點外快,每次我都拒絕了 我不知道怎麼教啊,我...