2010-03-14 40 views
4

更改Linux C++程序,使用戶有限的文件訪問權限。因此,程序chroots本身到用戶可以獲取的文件的沙箱。一切運作良好。如何(合法)在將自己放入chroot沙箱後訪問文件?

但是,現在程序需要根據自己的需要訪問某些文件(而不是用戶的),但它們不在沙盒中。我知道chroot允許在chroot之前訪問打開之前的文件,但在這種情況下,需要的文件可能在幾百個之中,所以將它們全部打開僅用於可能需要的配對顯然是不切實際的。

有沒有什麼辦法可以得到這些文件?

+0

你不能複製的文件呢? – fabrizioM 2010-03-14 02:35:48

+0

不,有太多的用戶不應該看到它們,並且它們會被其他程序更新。 – ValenceElectron 2010-03-14 02:38:06

回答

2

如果您需要訪問的文件位於幾個目錄中,您可以在之前打開那些目錄,然後您將chroot並保存文件描述符。然後,您可以使用所謂的*功能(例如openat(),renameat()等)來獲取單個文件。基本上你打開文件相對到已打開的目錄文件描述符而不是chrooted目錄。

這是否是一件安全的事情值得商榷,但它應該在Linux中運行。

編輯:這是醜陋的一面,但它似乎工作。你應該比我有更多的漏洞。我還沒有測試過如何刪除權限等等。

#include <iostream> 
#include <string> 

using namespace std; 

#include <cstdio> 
#include <cstdlib> 
#include <cerrno> 
#include <cstring> 

#include <unistd.h> 
#include <fcntl.h> 
#include <dirent.h> 
#include <sys/types.h> 
#include <sys/stat.h> 


int main(int argc, char *argv[]) 
{ 
    if (argc < 4) 
    { 
     cerr << "USAGE: " << argv[0] << " <jail directory> <freeworld directory> <filename>\n"; 
     exit(EXIT_FAILURE); 
    } 

    const string JAILDIR(argv[1]); 
    const string FREEDIR(argv[2]); 
    string freefilename(argv[3]); 

    while (freefilename[0] == '/') 
     freefilename.erase(0, 1); 

    DIR *pDir; 

    if ((pDir = opendir(FREEDIR.c_str())) == NULL) 
    { 
     perror("Could not open outside dir"); 
     exit(EXIT_FAILURE); 
    } 

    int freeFD = dirfd(pDir); 

    //cd to jail dir 
    if (chdir(JAILDIR.c_str()) == -1) 
    { 
     perror("cd before chroot"); 
     exit(EXIT_FAILURE); 
    } 

    //lock in jail 
    if (chroot(JAILDIR.c_str()) < 0) 
    { 
     cerr << "Failed to chroot to " << JAILDIR << " - " << strerror(errno) << endl; 
     exit(EXIT_FAILURE); 
    } 

    // 
    //in jail, won't work 
    // 

    string JailFile(FREEDIR); 
    JailFile += "/"; 
    JailFile += freefilename; 

    int jailFD; 

    if ((jailFD = open(JailFile.c_str(), O_RDONLY)) == -1) 
    { 
     cout << "as expected, could not open " << JailFile << endl; 
     perror("exected open fail"); 
    } 
    else 
    { 
     cout << "defying all logic, opened " << JailFile << endl; 
     exit(EXIT_FAILURE); 
    } 

    // 
    //using this works 
    // 

    if ((jailFD = openat(freeFD, freefilename.c_str(), O_RDONLY)) == -1) 
    { 
     cout << "example did not work. Could not open " << freefilename << " Sorry!" << endl; 
     exit(EXIT_FAILURE); 
    } 
    else 
     cout << "opened " << freefilename << " from inside jail" << endl; 

    char  buff[255]; 
    ssize_t numread; 

    while (1) 
    { 
     if ((numread = read(jailFD, buff, sizeof(buff) - 1)) == -1) 
     { 
      perror("read"); 
      exit(EXIT_FAILURE); 
     } 

     if (numread == 0) 
      break; 

     buff[numread] = '\0'; 
     cout << buff << endl; 
    } 

    return 0; 
} 

測試:

回聲的 「Hello World」>/tmp目錄/的MyStuff。DAT

的mkdir/tmp目錄/監獄

須藤./myprog的/ tmp /監獄/ tmp目錄mystuff.dat在chroot環境

+0

這些文件位於3個目錄中。 – ValenceElectron 2010-03-14 03:28:48

+0

這似乎原則上工作。我會更多地測試它,並由一些人來運行它,但這對我們來說可能是一個很好的短期解決方案。謝謝! – ValenceElectron 2010-03-14 05:25:59

+1

除非有什麼可以防止openat()接受包含「../」的相對路徑名,並且在手冊頁中沒有看到任何效果,否則這會完全破壞您的監獄。 – pra 2010-03-15 13:07:45

8

將它們複製到沙箱中或在chroot之前打開它們。認真。如果有辦法做到這一點,將有一種方法可以讓它無法進入,從而允許其他訪問並使你的保護無用。

沙盒的整個目的是防止你試圖達到的目標。

2

如果文件全部位於1個目錄中,則可以使用mount將它們綁定到沙箱中的目錄。

mount --bind /path/to/files /sandbox/files 

您可以通過/sandbox/files/訪問文件。如果你不想讓用戶看到它們,那麼做mount --bind /path/to/files /sandbox/.files這樣.files目錄是隱藏的

+1

用戶沒有訪問/ sandbox /文件嗎? – ValenceElectron 2010-03-14 02:52:55

+1

如果該程序是他們與沙盒進行交互的唯一方式,那麼您可以通過程序界面禁止訪問。 – m42a 2010-03-14 02:58:05

2

我想你應該能夠將你的程序分成兩部分,一部分是chroot和一部分不是並且通過您選擇的IPC機制從非chroot的部分獲得chroot的部分請求文件的內容。

這是一個黑客攻擊,它可能很容易出錯,否定了chroot的任何好處。就像paxdiablo說的那樣,你試圖繞過chroot沙箱的全部目的,所以你的選擇非常非常有限。

也許如果你更多地解釋了你想要完成的事情,我們可能會提供一些其他的想法。例如,SELinux和AppArmor比chroot更加靈活,並且可以爲您提供所需的安全性。

+0

這些都是有效的選擇,我會用它們,如果這是事情的主角,但我希望有一些需要較少手術的東西。人們可以希望,對吧? – ValenceElectron 2010-03-14 03:07:30

相關問題