非root用户是否可以在Ubuntu上运行chroot进程?
非root用户是否可以在Ubuntu上运行chroot进程?
Answers:
在Linux上,chroot(2)系统调用只能由特权进程进行。流程所需的功能是CAP_SYS_CHROOT。
您不能chroot作为用户的原因很简单。假设您有一个setuid程序(如sudo),它会检查/ etc / sudoers是否允许您执行某些操作。现在,使用您自己的/ etc / sudoers将其放在chroot chroot中。突然,您立即进行特权升级。
可以将程序设计为chroot本身并作为setuid进程运行,但这通常被认为是不好的设计。chroot的额外安全性不会激发setuid的安全性问题。
chroot
。
@ 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环境中(即,调用方的根目录与它所在的装载名称空间的根目录不匹配)。
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(符号链接ls
)mv
和其他常用实用程序到/bin/busybox
。如果我明确地打电话/bin/busybox mv ...
,事情就解决了,但是如果我打电话/bin/mv ...
我就得到了sh: /bin/mv: not found
。export FAKECHROOT_EXCLUDE_PATH=/
在运行fakechroot之前进行设置可以修复该症状,但随后在其他符号链接(例如/usr/bin/vim -> /usr/bin/vim.vim
)上会中断。
似乎使用用户命名空间实际上可以在没有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)上对我失败。
unshare
调用失败而可能导致的错误代码。:您也可以尝试哪些可能有更好的错误消息这条巨蟒版本github.com/cheshirekow/uchroot