设置后取消共享 --map-root-user 切换到原始 uid/用户名

spa*_*awn 9 linux users root namespace unshare

我正在使用 unshare 来创建每个进程的挂载,它运行得非常好

unshare -m --map-root-user
Run Code Online (Sandbox Code Playgroud)

但是,在创建了我的绑定安装之后

mount --bind src dst
Run Code Online (Sandbox Code Playgroud)

我想将 UID 更改为我的原始用户,以便whoami(和其他人)像echo $USER这样响应我的用户名。

我已经尝试过Simulate chroot with unshare的答案

但是,在做su – user1之后chroot /,我得到

su: Authentication failure
(Ignored)
setgid: Invalid argument
Run Code Online (Sandbox Code Playgroud)

我已经在 Ubuntu 18.04 Beta、Debian stretch、openSUSE-Leap-42.3 上测试过这个。全部都是一样。我猜自从这个答案起作用以来,内核中发生了一些变化。

什么是可行且正确的方法来做到这一点(当然没有真正的根)?

A.B*_*A.B 6

unshare(1)命令无法做到这一点:

-r, --map-root-用户
[...] 作为一个纯粹的便利功能,它不支持更复杂的用例,例如映射多个 UID 和 GID 范围。

补充组(如有)(video , ...)无论如何都会丢失(或映射到nogroup)。

通过再次更改为第二个新用户命名空间,可以恢复映射。这需要一个自定义程序,因为unshare(1)不会这样做。这是一个非常简约的 C 程序作为概念证明(仅限一个用户:uid/gid 1000/1000,零故障检查)。我们称它为revertuid.c

#define _GNU_SOURCE
#include <sched.h>

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

#include <unistd.h>

int main(int argc, char *argv[]) {
    int fd;

    unshare(CLONE_NEWUSER);
    fd=open("/proc/self/setgroups",O_WRONLY);
    write(fd,"deny",4);
    close(fd);
    fd=open("/proc/self/uid_map",O_WRONLY);
    write(fd,"1000 0 1",8);
    close(fd);
    fd=open("/proc/self/gid_map",O_WRONLY);
    write(fd,"1000 0 1",8);
    close(fd);
    execvp(argv[1],argv+1);
}
Run Code Online (Sandbox Code Playgroud)

它只是对 所做的映射进行反向映射unshare -r -m,这是不可避免的,以便能够成为 root 并使用mount,如下所示:

$ strace unshare -r -m /bin/sleep 1 2>&1 |sed -n '/^unshare/,/^execve/p'
unshare(CLONE_NEWNS|CLONE_NEWUSER)      = 0
open("/proc/self/setgroups", O_WRONLY)  = 3
write(3, "deny", 4)                     = 4
close(3)                                = 0
open("/proc/self/uid_map", O_WRONLY)    = 3
write(3, "0 1000 1", 8)                 = 8
close(3)                                = 0
open("/proc/self/gid_map", O_WRONLY)    = 3
write(3, "0 1000 1", 8)                 = 8
close(3)                                = 0
execve("/bin/sleep", ["/bin/sleep", "1"], [/* 18 vars */]) = 0
Run Code Online (Sandbox Code Playgroud)

所以这给出了:

user@stretch-amd64:~$ gcc -o revertuid revertuid.c
user@stretch-amd64:~$ mkdir -p /tmp/src /tmp/dst
user@stretch-amd64:~$ touch /tmp/src/file
user@stretch-amd64:~$ ls /tmp/dst
user@stretch-amd64:~$ id
uid=1000(user) gid=1000(user) groups=1000(user)
user@stretch-amd64:~$ unshare -r -m
root@stretch-amd64:~# mount --bind /tmp/src /tmp/dst
root@stretch-amd64:~# ls /tmp/dst
file
root@stretch-amd64:~# exec ./revertuid bash
user@stretch-amd64:~$ ls /tmp/dst
file
user@stretch-amd64:~$ id
uid=1000(user) gid=1000(user) groups=1000(user)
Run Code Online (Sandbox Code Playgroud)

或者更短:

user@stretch-amd64:~$ unshare -r -m sh -c 'mount --bind /tmp/src /tmp/dst; exec ./revertuid bash'
user@stretch-amd64:~$ ls /tmp/dst
file
Run Code Online (Sandbox Code Playgroud)

在内核 3.19 之后,行为可能会发生变化,如所示user_namespaces(7)

/proc/[pid]/setgroups文件是在 Linux 3.19 中添加的,但被向后移植到许多早期的稳定内核系列中,因为它解决了安全问题。该问题涉及具有“rwx---rwx”等权限的文件。