我正在尝试非特权 Linux 容器,并且正在编写一个创建极简容器的 Go 程序。程序分叉自身并在进程中创建名称空间。但是,由于某种原因,如果我将用户命名空间大小设置为大于 1,则以普通用户身份运行时会失败。
cmd := exec.Command("/proc/self/exe", "run-container")
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUSER | syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS,
Unshareflags: syscall.CLONE_NEWNS,
UidMappings: []syscall.SysProcIDMap{
{
ContainerID: 0,
HostID: os.Getuid(),
Size: 1, // set this to 2 or more and it fails
},
},
GidMappings: []syscall.SysProcIDMap{
{
ContainerID: 0,
HostID: os.Getgid(),
Size: 1,
},
},
}
// other flags: CLONE_NEWNET, CLONE_NEWIPC, CLONE_NEWCGROUP, CLONE_NEWUSER,
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
fmt.Println("ERROR: parent cmd.Run", err)
os.Exit(1)
}
上面的代码(以及所有其他东西,如pivot_root等)工作正常。但当我将 Size 设置为 2 时,它就崩溃了:
ERROR: parent cmd.Run fork/exec /proc/self/exe: operation not permitted
这似乎是一个功能问题,因为当我以 root 身份运行时它可以工作。
这是我的/etc/subuid
:
lxd:1000:1
root:1000:1
lxd:100000:65536
root:100000:65536
developer:165536:65536
mounter:231072:65536
更新:
我发现您需要 CAP_SETUID 将当前的内容映射euid
到另一个(请参阅用户命名空间手册页)。
但即使sudo setcap cap_setuid=eip /my/binary
失败了。错误消息已更改为:
ERROR: parent cmd.Run fork/exec /proc/self/exe: permission denied
如果我运行它,当尝试写入时strace
会失败。EPERM
/proc/xx/uid_map
openat(AT_FDCWD, "/proc/25233/uid_map", O_RDWR) = 5
write(5, "0 1000 100\n\0", 12) = -1 EPERM (Operation not permitted)