照书写了段使用 UTS Namespace 的代码:
import (
"os/exec"
"syscall"
"os"
"log"
)
func main() {
cmd := exec.Command("sh")
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUTS,
}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
log.Fatal(err)
}
}
执行go run uts.go
发现提示fork/exec /bin/sh: operation not permitted
,我改用 root 用户跑是可以解决问题的,看书上的环境是 Ubuntu 14.04 ,内核版本是 3.13.0-83-generic,书上跑这段代码是没这个权限问题的(因为它没说),我的环境是 Ubuntu 18.04.3,内核 5.0.0-32-generic,这个问题应该高版本内核导致的,是有什么改动吗?
1
billlee 2019-11-12 23:51:09 +08:00
man 2 clone 上写的是要 CAP_SYS_ADMIN 权限的
|
2
salamanderMH OP @billlee 感谢。
|
3
salamanderMH OP 看了下 doc
If CLONE_NEWUTS is set, then create the process in a new UTS namespace, whose identifiers are initialized by duplicating the identifiers from the UTS namespace of the calling process. If this flag is not set, then (as with fork(2)) the process is created in the same UTS namespace as the calling process. This flag is intended for the implementation of containers. A UTS namespace is the set of identifiers returned by uname(2); among these, the domain name and the hostname can be modified by setdomainname(2) and sethostname(2), respectively. Changes made to the identifiers in a UTS namespace are visible to all other processes in the same namespace, but are not visible to processes in other UTS namespaces. Only a privileged process (CAP_SYS_ADMIN) can employ CLONE_NEWUTS. |
4
codehz 2019-11-13 11:29:37 +08:00
(其实免特权跑容器一般都是先开一个(实际上可以同时) User namespace,然后设置 uid 映射
|
5
salamanderMH OP 我增加了一个 Mount Namespace,添加了 CAP_SYS_ADMIN,但是进入容器还是需要 root 权限?
```` package main import ( "log" "os" "os/exec" "syscall" ) // Mount Namespace func main() { cmd := exec.Command("sh") cmd.SysProcAttr = &syscall.SysProcAttr{ Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS, } cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { log.Fatal(err) } } ``` sudo setcap CAP_SYS_ADMIN+ep app // 赋予 CAP_SYS_ADMIN 然后`mount -t proc proc /proc`提示 mount: 只有 root 用户能使用“--types”选项 @billlee |
6
billlee 2019-11-18 21:21:40 +08:00
@salamanderMH #5 mount(8) 是個 setuid 程序,會自己檢查權限的。你可以直接調 mount(2) 系統調用試試
|
7
salamanderMH OP @billlee
-rwsr-xr-x 1 root root 43088 8 月 23 07:47 /bin/mount 有点不太懂,看网上资料 setuid 是会让进程运行时自己提升为 root 用户 看了这篇文章,有点不太懂,https://here2say.com/39/ 晚上我再去研究研究哈哈 |
8
billlee 2019-11-19 21:51:34 +08:00
@salamanderMH #7 mount(8) 有 setuid 权限是为了非 root 用户也可以挂载 /etc/fstab 里面设置了 user 选项的文件系统。由于 setuid 了,就无法依赖内核来做权限检查,必须自己再实现一遍权限检查。可能这里的检查就没有考虑非 root 用户有 CAP_SYS_ADMIN 的情况。
|
9
rome7054 2020-02-16 15:19:08 +08:00
@salamanderMH 无意翻到旧帖,其实 codehz 也说了,要用 User namespace,然后设置 uid 映射。你引用的这个系列文章是没问题,在前面章节我有解释这个用户执行权限问题,你应该看这个 https://here2say.com/37/
所以这么写的话就不需要 root 来执行,没有 operation not permitted 这个问题 ```go // +build linux package main import ( "fmt" "os" "os/exec" "syscall" ) func main() { cmd := exec.Command("sh") //set identify for this demo cmd.Env = []string{"PS1=-[namespace-process]-# "} cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.SysProcAttr = &syscall.SysProcAttr{ Cloneflags: syscall.CLONE_NEWNS | syscall.CLONE_NEWUTS | syscall.CLONE_NEWUSER, UidMappings: []syscall.SysProcIDMap{ { ContainerID: 0, HostID: os.Getuid(), Size: 1, }, }, GidMappings: []syscall.SysProcIDMap{ { ContainerID: 0, HostID: os.Getgid(), Size: 1, }, }, } if err := cmd.Run(); err != nil { fmt.Printf("Error running the /bin/sh command - %s\n", err) os.Exit(1) } } ``` |
10
salamanderMH OP @rome7054 谢谢,我现在是这么做了。
|