2017-02-11 87 views
4

我需要運行用戶提交的應用程序。我的代碼如下所示:如何在Python中限制子進程stdout和stderr的大小

def run_app(app_path): 
    inp = open("app.in", "r") 
    otp = open("app.out", "w") 

    return subprocess.call(app_path, stdout=otp, stdin=inp) 

現在,由於我無法控制用戶將要提交的內容,所以我想限制應用程序輸出的大小。其他事情如試圖訪問未經授權的系統資源和濫用CPU週期正受到執法規則的限制。允許運行的最大時間由父進程處理(在python中)。現在,流氓應用程序仍然可以嘗試通過向標準輸出寫入大量數據來淹沒服務器系統,因爲知道stdout將被保存到文件中。

我不想在內核模式下使用AppArmors RLIMIT或stdout/stderr文件。能夠使用標準庫從python執行它會很棒。

我目前正在考慮創建文件的子類,並在每次寫入時檢查已經寫入數據流的數據量。或者創建一個最大長度設置的內存映射文件。

但我覺得可能有更簡單的方法來限制文件大小我還沒有看到它。

+1

你可以通過['head'](https://linux.die.net/man/1/head)管道輸出嗎? – Leon

+0

@Leon頭將工作。我正在尋找一些說outp.maxsize = 10000的東西。這種方式非常簡單。我最終可能會使用RLIMIT或一位朋友共享一個關於/ etc/security/limits的鏈接 - 要麼需要更多的配置。 –

回答

2

子類化file或創建其他僞文件的Python對象根本不起作用,因爲該文件將在子進程中消耗 - 因此它必須是一個O.S.文件,而不是Python類對象。子進程不會將您的Python對象發送給其他進程使用。

儘管Python對內存映射文件具有本地和簡單的支持,但通過mmap模塊,內存映射並不意味着:您可以指定鏡像到內存的文件的大小,但不是完全限制寫入文件:多餘的數據將被簡單地寫入磁盤並且不被映射。 (再次,你傳遞給子進程的磁盤文件,而不是mmap對象)。有可能在某個時候創建​​一個帶有標記值的文件,並讓線程檢查標記是否被覆蓋,此時它可能會終止子進程 - 但我懷疑這是否可靠。

然後,有磁盤活動監視工具,例如inotify:您可以使用pyinotify訪問您的主進程上的一個處理程序,只要訪問該文件就會調用該處理程序。缺點:沒有'文件寫入'事件 - 只是'文件'處理 - 我不確定是否有任何可能的事件會由增量寫入文件觸發。而且,如果子進程在一次系統調用中完成所有的寫入操作,那麼無論如何你都會被通知得太晚。

所以,我能想到的工作是:在人爲限制的文件系統中創建一個文件。這樣,當超過最大尺寸時,操作系統將阻止寫入。

在Linux下,你可以預先創建所需的大小+一些開銷文件,就可以創建一個FS,並與「環」接口掛載它 - 然後就創建一個文件系統內的stdout和sterr文件,並致電您的子女過程。

您可以預先創建並預裝一個根據需要使用的文件系統池 - 或者,您甚至可以動態創建它們 - 但這需要創建FS主機文件,創建文件 - 系統結構(mkfs)並加載它 - 所有這些都可能造成很大的開銷。總而言之,也許你更好地簡單地使用Apparmor自己的rlimit設置。

+0

關於文件和mmap的好處。我沒有想到從本地文件句柄將輸出流引入python空間的開銷。 您對限制文件系統的想法可能是一個選項 - 我可以在大小限制內創建一個內存fs - 這樣我就不需要將更大的文件保存到任何磁盤。我還不確定是否需要保留該文件供將來參考 - 在這種情況下,我可能會複製到最終位置。我正在重新考慮apparmor解決方案,因爲我只需要在現有配置中添加簡單規則。 –

相關問題