4

更改赋予用户有限文件访问权限的 Linux C++ 程序。因此,程序将自身chroot到一个沙箱,其中包含用户可以获取的文件。一切运作良好。

然而,现在程序需要访问一些文件以满足自己的需要(而不是用户的),但它们在沙箱之外。我知道 chroot 允许访问在 chroot之前打开的文件,但在这种情况下,所需的文件可能是数百个中的几个,因此只为可能需要的一对打开它们显然是不切实际的。

有什么办法可以获取文件吗?

4

4 回答 4

8

将它们复制到沙箱中或在chrooting 之前将它们全部打开。严重地。如果有办法做到这一点,就会有一种方法可以替代它以允许其他访问并使您的保护无用。

沙盒的全部意义在于防止您想要实现的目标。

于 2010-03-14T02:36:52.453 回答
3

如果文件都在 1 个目录中,您可以使用 mount 将它们绑定到沙箱内的目录。

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

您可以通过/sandbox/files/. 如果您不希望用户看到它们,请mount --bind /path/to/files /sandbox/.files隐藏.files目录

于 2010-03-14T02:51:13.377 回答
2

我想你应该能够将你的程序分成两部分,一个是 chroot'ed,一个不是,并且通过 chroot'ed 部分从非 chroot'ed 部分请求文件的内容您选择的 IPC 机制。

这是一个 hack,很容易出错,从而否定 chroot 的任何好处。就像 paxdiablo 说的那样,你试图绕过 chroot 沙箱的全部目的,所以你的选择非常非常有限。

也许如果你解释一下你想要完成的事情,我们也许可以提供一些其他的想法。例如,SELinux 和 AppArmor 比 chroot 更灵活,可能能够为您提供您所寻求的安全性。

于 2010-03-14T02:51:33.370 回答
2

如果您需要访问的文件位于几个目录中,您可以在 chroot之前打开这些目录并保存文件描述符。然后,您可以使用所谓的 *at 函数(例如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/监狱

sudo ./myprog /tmp/jail /tmp mystuff.dat

于 2010-03-14T02:54:56.280 回答