简体   繁体   English

如何(合法地)将自己放入chroot沙箱后访问文件?

[英]How to (legitimately) access files after putting self into chrooted sandbox?

Changing a Linux C++ program which gives the user limited file access. 更改Linux C ++程序,为用户提供有限的文件访问权限。 Thus the program chroots itself to a sandbox with the files the user can get at. 因此,程序自己chroot到一个沙箱,其中包含用户可以获得的文件。 All worked well. 一切顺利。

Now, however, the program needs to access some files for its own needs ( not the user's) but they are outside the sandbox. 但是,现在,程序需要根据自己的需要访问某些文件( 而不是用户),但它们位于沙箱之外。 I know chroot allows access to files opened before the chroot but in this case the needed files could a few among many hundreds so it is obviously impractical to open them all just for the couple that might be required. 我知道chroot允许访问在chroot 之前打开的文件,但在这种情况下,所需的文件可能会有数百个,所以打开它们对于可能需要的那对夫妇来说显然是不切实际的。

Is there any way to get at the files? 有办法获取文件吗?

Copy them into the sandbox or open them all before chroot ing. 将它们复制到沙箱中或在chroot之前打开它们。 Seriously. 认真。 If there was a way to do this, there would be a way to suborn it to allow other access and make your protection useless. 如果有办法做到这一点,那么就有办法让它变得允许其他访问并使你的保护无用。

The whole point of the sandbox is to prevent exactly what you're trying to achieve. 沙箱的重点是要完全避免你想要实现的目标。

If the files are all in 1 directory, you could use mount to bind them to a directory inside the sandbox. 如果文件都在1目录中,则可以使用mount将它们绑定到沙箱中的目录。

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

The you can access the files through /sandbox/files/ . 您可以通过/sandbox/files/访问这些文件。 If you don't want the user to see them, do mount --bind /path/to/files /sandbox/.files so the .files directory is hidden 如果您不希望用户看到它们,请将mount --bind /path/to/files /sandbox/.files以便隐藏.files目录

I guess that you ought to be able to split your program into two parts, one which is chroot'ed and one which isn't, and have the chroot'ed portion request files' contents from the non-chroot'ed portion via the IPC mechanism of your choice. 我想你应该能够把你的程序分成两部分,一部分是chroot'ed而另一部分是chroot'ed,并且chroot'ed部分请求文件的内容来自非chroot'ed部分,通过您选择的IPC机制。

This is a hack, and it may be easy to get wrong, negating any benefit of a chroot. 这是一个黑客,它可能很容易出错,否定chroot的任何好处。 Like paxdiablo says, you're trying to get around the whole purpose of a chroot sandbox, so your options are very, very limited. 就像paxdiablo说的那样,你试图绕过chroot沙箱的整个目的,所以你的选择非常非常有限。

Maybe if you explained a bit more what you're trying to accomplish, we might be able to offer some other ideas. 也许如果你再解释一下你想要完成的事情,我们或许可以提供一些其他的想法。 For example, SELinux and AppArmor are more flexible than chroot and may be able to give you the security you seek. 例如,SELinux和AppArmor比chroot更灵活,并且可以为您提供所需的安全性。

If the files you need to access are within a few directories you could open those directories before you chroot and save the file descriptors. 如果您需要访问的文件位于几个目录中,则可以 chroot并保存文件描述符之前打开这些目录。 You can then use the so-called *at functions (eg openat() , renameat() , etc.) to get at the individual files. 然后,您可以使用所谓的* at函数(例如openat()renameat()等)来获取单个文件。 Basically you are opening the files relative to the already open directory file descriptors rather than the chrooted directory. 基本上,您打开的文件对于已打开的目录文件描述符而不是chrooted目录。

Whether this is a safe thing to do is open to question but it should work in Linux. 这是否是一件安全的事情是值得商榷的,但它应该适用于Linux。

EDIT: This is on the ugly side but it seems to work. 编辑:这是丑陋的一面,但它似乎工作。 You should poke around a lot more for vulnerabilities than I have. 你应该为我的漏洞找到更多的漏洞。 I haven't tested how dropping privileges and so forth will effect things. 我还没有测试权限下降等等会影响到什么。

#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;
}

To test: 去测试:

echo "Hello World" >/tmp/mystuff.dat echo“Hello World”> /tmp/mystuff.dat

mkdir /tmp/jail mkdir / tmp / jail

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM