创建一个 UST Namespace not permitted?

2019-11-12 22:02:55 +08:00
 salamanderMH

问题

照书写了段使用 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,这个问题应该高版本内核导致的,是有什么改动吗?

2102 次点击
所在节点    问与答
10 条回复
billlee
2019-11-12 23:51:09 +08:00
man 2 clone 上写的是要 CAP_SYS_ADMIN 权限的
salamanderMH
2019-11-13 08:14:52 +08:00
@billlee 感谢。
salamanderMH
2019-11-13 10:22:23 +08:00
看了下 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.
codehz
2019-11-13 11:29:37 +08:00
(其实免特权跑容器一般都是先开一个(实际上可以同时) User namespace,然后设置 uid 映射
salamanderMH
2019-11-18 19:03:03 +08:00
我增加了一个 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
billlee
2019-11-18 21:21:40 +08:00
@salamanderMH #5 mount(8) 是個 setuid 程序,會自己檢查權限的。你可以直接調 mount(2) 系統調用試試
salamanderMH
2019-11-19 11:13:51 +08:00
@billlee
-rwsr-xr-x 1 root root 43088 8 月 23 07:47 /bin/mount
有点不太懂,看网上资料 setuid 是会让进程运行时自己提升为 root 用户
看了这篇文章,有点不太懂,https://here2say.com/39/ 晚上我再去研究研究哈哈
billlee
2019-11-19 21:51:34 +08:00
@salamanderMH #7 mount(8) 有 setuid 权限是为了非 root 用户也可以挂载 /etc/fstab 里面设置了 user 选项的文件系统。由于 setuid 了,就无法依赖内核来做权限检查,必须自己再实现一遍权限检查。可能这里的检查就没有考虑非 root 用户有 CAP_SYS_ADMIN 的情况。
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)
}
}
```
salamanderMH
2020-02-16 15:39:45 +08:00
@rome7054 谢谢,我现在是这么做了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/618961

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX