开发者

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

开发者 https://www.devze.com 2022-12-22 17:22 出处:网络
Changing a Linux C++ program which gives the user limited file access.Thus the program chroots itself to a sandbox with the files the user can get at.All worked well.

Changing a Linux C++ program which gives the user limited file access. Thus the program chroots itself to a sandbox with the files the user can get at. 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 fo开发者_运维百科r the couple that might be required.

Is there any way to get at the files?


Copy them into the sandbox or open them all before chrooting. 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.

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

The you can access the files through /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


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. You can then use the so-called *at functions (e.g. openat(), renameat(), etc.) to get at the individual files. Basically you are opening the files relative to the already open directory file descriptors rather than the chrooted directory.

Whether this is a safe thing to do is open to question but it should work in 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

mkdir /tmp/jail

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


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.

This is a hack, and it may be easy to get wrong, negating any benefit of a chroot. Like paxdiablo says, you're trying to get around the whole purpose of a chroot sandbox, so your options are very, very limited.

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号