Ubuntu-非root用户可以在chroot监狱中运行进程吗?


18

非root用户是否可以在Ubuntu上运行chroot进程?


这个旧的FreeBSD线程涵盖了相同的问题:lists.freebsd.org/pipermail/freebsd-security/2003-April/…简短的回答:不,您不能在非root chroot监狱中以root身份运行进程。
大卫·哈里森

chroot监狱特定于bsd。linux中的chroot并非监狱。最后,我检查了无法以chroot用户身份。
xenoterracide

1
@xenoterracide Jails是特定于BSD的,但是chroot在Linux社区中通常被称为“ chroot监狱”。很困惑。
pehrs 10-4-25

2
您想做什么,为什么?诸如fakechroot和schroot之类的工具可以根据您的要求提供可行的替代方案。
Zoredache

如何“扎根”一个过程而不扎根的问题上,还有更多相关的讨论以更多可行或尝试的方法来解决列出的任务。
imz-伊万·扎哈拉里舍夫(Ivan Zakharyaschev),2011年

Answers:


12

在Linux上,chroot(2)系统调用只能由特权进程进行。流程所需的功能是CAP_SYS_CHROOT。

您不能chroot作为用户的原因很简单。假设您有一个setuid程序(如sudo),它会检查/ etc / sudoers是否允许您执行某些操作。现在,使用您自己的/ etc / sudoers将其放在chroot chroot中。突然,您立即进行特权升级。

可以将程序设计为chroot本身并作为setuid进程运行,但这通常被认为是不好的设计。chroot的额外安全性不会激发setuid的安全性问题。


3
有了Linux 中命名空间的新可能性,也许可以创建(取消共享)一个新的“用户”命名空间,其中将有一个“嵌入式”根用户,然后执行chroot
imz-伊万·扎哈拉里舍夫(Ivan Zakharyaschev)2013年

1
@ imz--IvanZakharyaschev你是完全正确的,我希望你不要介意我将其写为一个容易测试的答案的自由。
2014年

@hvd太好了!它必须非常有用,因为它演示了如何通过具体命令使用陌生的Linux新功能。
imz –伊万·扎哈拉里舍夫(Ivan Zakharyaschev)2014年

6

@ imz--IvanZakharyaschev对pehrs的回答发表评论说,引入命名空间可能是可能的,但是尚未对此进行测试并将其发布为答案。是的,的确使非root用户可以使用chroot。

给定一个static-linked dash和static-linked busybox,以及一个bash以非root用户身份运行的shell:

$ mkdir root
$ cp /path/to/dash root
$ cp /path/to/busybox root
$ unshare -r bash -c 'chroot root /dash -c "/busybox ls -al /"'
total 2700
drwxr-xr-x    2 0        0             4096 Dec  2 19:16 .
drwxr-xr-x    2 0        0             4096 Dec  2 19:16 ..
drwxr-xr-x    1 0        0          1905240 Dec  2 19:15 busybox
drwxr-xr-x    1 0        0           847704 Dec  2 19:15 dash

在该命名空间的根用户ID被映射到该命名空间的非根用户ID以外,反之亦然,这就是为什么由当前用户所拥有的用户ID作为资0正则系统显示的文件ls -al root,而不unshare,确实将其显示为当前用户所有。


注意:众所周知,能够使用的进程chroot能够脱离chroot。由于unshare -r可以将chroot权限授予普通用户,因此,如果在chroot环境内部允许,则存在安全风险。实际上,它是不允许的,并且失败:

取消共享:取消共享失败:不允许操作

匹配unshare(2)文档:

EPERM(从Linux 3.9开始)

标志中指定了CLONE_NEWUSER,并且调用方在chroot环境中(即,调用方的根目录与它所在的装载名称空间的根目录不匹配)。


在安装名称空间中运行pivot_root与chroot具有相似的效果,但避免了与用户名称空间的冲突。
蒂莫西·鲍德温

1
如果它们是在相同或子PID名称空间和用户名称空间中具有相同UID的外部进程,则可以通过降入/ proc来逃脱chroot或安装名称空间。
蒂莫西·鲍德温

2

这些天来,您希望使用LXC(Linux容器)而不是chroot / BSD监狱。它位于chroot和虚拟机之间,为您提供了许多安全控制和常规可配置性。我相信,作为用户运行它所需要做的就是成为拥有必要文件/设备的组的成员,但其中可能还涉及功能/系统权限。无论哪种方式,它都应该非常可行,因为LXC是很新的,在将SELinux等添加到Linux内核很久之后。

另外,请记住,您只能以root用户身份编写脚本,但可以使用sudo授予用户安全运行这些脚本的权限(如果需要,可以没有密码,但请确保脚本是安全的)。


1

fakeroot / fakechroot的组合提供了类似chroot的模拟需求,用于满足简单的需求,例如生成tar归档文件,其中文件似乎由root拥有。Fakechroot的联机帮助页是http://linux.die.net/man/1/fakechroot

虽然您没有任何新的权限,但是如果您在调用之前拥有目录(例如,伪发行版)

fakechroot fakeroot chroot ~/fake-distro some-command

现在,它会寻找某些命令,就像您是root一样,并在false-distro中拥有所有内容。


这是一个好主意,但似乎无法处理符号链接。我~/fake-distro使用busybox(符号链接lsmv和其他常用实用程序到/bin/busybox。如果我明确地打电话/bin/busybox mv ...,事情就解决了,但是如果我打电话/bin/mv ...我就得到了sh: /bin/mv: not foundexport FAKECHROOT_EXCLUDE_PATH=/在运行fakechroot之前进行设置可以修复该症状,但随后在其他符号链接(例如/usr/bin/vim -> /usr/bin/vim.vim)上会中断。
Ponkadoodle

也许FAKECHROOT_EXCLUDE_PATH = /:/ usr会有所帮助,然后呢?
sylvainulg

1

似乎使用用户命名空间实际上可以在没有root的情况下chroot。这是一个示例程序,演示了这是可能的。我才刚刚开始探索linux名称空间的工作原理,所以我不确定这是否是最佳实践。

另存为user_chroot.cc。用编译g++ -o user_chroot user_chroot.cc。用法是./user_chroot /path/to/new_rootfs

// references:
// [1]: http://man7.org/linux/man-pages/man7/user_namespaces.7.html
// [2]: http://man7.org/linux/man-pages/man2/unshare.2.html

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

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

int main(int argc, char** argv) {
    if(argc < 2) {
        printf("Usage: %s <rootfs>\n", argv[0]);
    }

    int uid = getuid();
    int gid = getgid();
    printf("Before unshare, uid=%d, gid=%d\n", uid, gid);

    // First, unshare the user namespace and assume admin capability in the
    // new namespace
    int err = unshare(CLONE_NEWUSER);
    if(err) {
        printf("Failed to unshare user namespace\n");
        return 1;
    }

    // write a uid/gid map
    char file_path_buf[100];
    int pid = getpid();
    printf("My pid: %d\n", pid);

    sprintf(file_path_buf, "/proc/%d/uid_map", pid);
    int fd = open(file_path_buf, O_WRONLY);
    if(fd == -1) {
        printf("Failed to open %s for write [%d] %s\n", file_path_buf, errno, 
               strerror(errno));
    } else {
        printf("Writing : %s (fd=%d)\n", file_path_buf, fd);
        err = dprintf(fd, "%d %d 1\n", uid, uid);
        if(err == -1) {
            printf("Failed to write contents [%d]: %s\n", errno, 
                   strerror(errno));
        }
        close(fd);
    }

    sprintf(file_path_buf, "/proc/%d/setgroups", pid);
    fd = open(file_path_buf, O_WRONLY);
    if(fd == -1) {
        printf("Failed to open %s for write [%d] %s\n", file_path_buf, errno, 
               strerror(errno));
    } else {
        dprintf(fd, "deny\n");
        close(fd);
    }

    sprintf(file_path_buf, "/proc/%d/gid_map", pid);
    fd = open(file_path_buf, O_WRONLY);
    if(fd == -1) {
        printf("Failed to open %s for write [%d] %s\n", file_path_buf, errno, 
               strerror(errno));
    } else {
        printf("Writing : %s (fd=%d)\n", file_path_buf, fd);
        err = dprintf(fd, "%d %d 1\n", gid, gid);
        if(err == -1) {
            printf("Failed to write contents [%d]: %s\n", errno, 
                   strerror(errno));
        }
        close(fd);
    }

    // Now chroot into the desired directory
    err = chroot(argv[1]);
    if(err) {
        printf("Failed to chroot\n");
        return 1;
    }

    // Now drop admin in our namespace
    err = setresuid(uid, uid, uid);
    if(err) {
        printf("Failed to set uid\n");
    }

    err = setresgid(gid, gid, gid);
    if(err) {
        printf("Failed to set gid\n");
    }

    // and start a shell
    char argv0[] = "bash";
    char* new_argv[] = {
        argv0,
        NULL
    };

    err = execvp("/bin/bash", new_argv);
    if(err) {
        perror("Failed to start shell");
        return -1;
    }
}

我已经在由multistrap生成的最小rootfs(作为非root用户执行)上进行了测试。一些系统文件,例如/etc/passwd/etc/groups从主机rootfs复制到来宾rootfs。


Failed to unshare user namespace在Linux 4.12.10(Arch Linux)上对我失败。
Ponkadoodle

@wallacoloo可能将printf()修改为perror()并查看实际错误是什么。请参阅man7.org/linux/man-pages/man2/unshare.2.html,以了解由于unshare调用失败而可能导致的错误代码。:您也可以尝试哪些可能有更好的错误消息这条巨蟒版本github.com/cheshirekow/uchroot
cheshirekow

1
其实@wallacoloo这听起来像弓禁用unpriviledged用户的命名空间在它的内核构建:lists.archlinux.org/pipermail/arch-general/2017-February/...
cheshirekow

0

否。如果我没记错的话,chroot会执行一些内核级的操作来阻止它。我不记得那是什么东西。在弄乱Gentoo的Catalyst Build工具时,我进行了调查(而gentoo上的chroot与ubuntu上的chroot相同)。尽管无需密码就可以实现它……但是这些事情留给了潜在的安全漏洞,并确保您知道自己在做什么。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.