更改Linux C++程序,使用戶有限的文件訪問權限。因此,程序chroots本身到用戶可以獲取的文件的沙箱。一切運作良好。如何(合法)在將自己放入chroot沙箱後訪問文件?
但是,現在程序需要根據自己的需要訪問某些文件(而不是用戶的),但它們不在沙盒中。我知道chroot允許在chroot之前訪問打開之前的文件,但在這種情況下,需要的文件可能在幾百個之中,所以將它們全部打開僅用於可能需要的配對顯然是不切實際的。
有沒有什麼辦法可以得到這些文件?
更改Linux C++程序,使用戶有限的文件訪問權限。因此,程序chroots本身到用戶可以獲取的文件的沙箱。一切運作良好。如何(合法)在將自己放入chroot沙箱後訪問文件?
但是,現在程序需要根據自己的需要訪問某些文件(而不是用戶的),但它們不在沙盒中。我知道chroot允許在chroot之前訪問打開之前的文件,但在這種情況下,需要的文件可能在幾百個之中,所以將它們全部打開僅用於可能需要的配對顯然是不切實際的。
有沒有什麼辦法可以得到這些文件?
如果您需要訪問的文件位於幾個目錄中,您可以在之前打開那些目錄,然後您將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環境
這些文件位於3個目錄中。 – ValenceElectron 2010-03-14 03:28:48
這似乎原則上工作。我會更多地測試它,並由一些人來運行它,但這對我們來說可能是一個很好的短期解決方案。謝謝! – ValenceElectron 2010-03-14 05:25:59
除非有什麼可以防止openat()接受包含「../」的相對路徑名,並且在手冊頁中沒有看到任何效果,否則這會完全破壞您的監獄。 – pra 2010-03-15 13:07:45
將它們複製到沙箱中或在chroot
之前打開它們。認真。如果有辦法做到這一點,將有一種方法可以讓它無法進入,從而允許其他訪問並使你的保護無用。
沙盒的整個目的是防止你試圖達到的目標。
如果文件全部位於1個目錄中,則可以使用mount將它們綁定到沙箱中的目錄。
mount --bind /path/to/files /sandbox/files
您可以通過/sandbox/files/
訪問文件。如果你不想讓用戶看到它們,那麼做mount --bind /path/to/files /sandbox/.files
這樣.files
目錄是隱藏的
用戶沒有訪問/ sandbox /文件嗎? – ValenceElectron 2010-03-14 02:52:55
如果該程序是他們與沙盒進行交互的唯一方式,那麼您可以通過程序界面禁止訪問。 – m42a 2010-03-14 02:58:05
我想你應該能夠將你的程序分成兩部分,一部分是chroot和一部分不是並且通過您選擇的IPC機制從非chroot的部分獲得chroot的部分請求文件的內容。
這是一個黑客攻擊,它可能很容易出錯,否定了chroot的任何好處。就像paxdiablo說的那樣,你試圖繞過chroot沙箱的全部目的,所以你的選擇非常非常有限。
也許如果你更多地解釋了你想要完成的事情,我們可能會提供一些其他的想法。例如,SELinux和AppArmor比chroot更加靈活,並且可以爲您提供所需的安全性。
這些都是有效的選擇,我會用它們,如果這是事情的主角,但我希望有一些需要較少手術的東西。人們可以希望,對吧? – ValenceElectron 2010-03-14 03:07:30
你不能複製的文件呢? – fabrizioM 2010-03-14 02:35:48
不,有太多的用戶不應該看到它們,並且它們會被其他程序更新。 – ValenceElectron 2010-03-14 02:38:06