V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
牛客网
salamanderMH
V2EX  ›  问与答

创建一个 UST Namespace not permitted?

  •  
  •   salamanderMH · 345 天前 · 841 次点击
    这是一个创建于 345 天前的主题,其中的信息可能已经有所发展或是发生改变。

    问题

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

    10 条回复    2020-02-16 15:39:45 +08:00
    billlee
        1
    billlee   345 天前
    man 2 clone 上写的是要 CAP_SYS_ADMIN 权限的
    salamanderMH
        2
    salamanderMH   344 天前
    @billlee 感谢。
    salamanderMH
        3
    salamanderMH   344 天前
    看了下 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
        4
    codehz   344 天前
    (其实免特权跑容器一般都是先开一个(实际上可以同时) User namespace,然后设置 uid 映射
    salamanderMH
        5
    salamanderMH   339 天前
    我增加了一个 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
        6
    billlee   339 天前
    @salamanderMH #5 mount(8) 是個 setuid 程序,會自己檢查權限的。你可以直接調 mount(2) 系統調用試試
    salamanderMH
        7
    salamanderMH   338 天前
    @billlee
    -rwsr-xr-x 1 root root 43088 8 月 23 07:47 /bin/mount
    有点不太懂,看网上资料 setuid 是会让进程运行时自己提升为 root 用户
    看了这篇文章,有点不太懂,https://here2say.com/39/ 晚上我再去研究研究哈哈
    billlee
        8
    billlee   338 天前
    @salamanderMH #7 mount(8) 有 setuid 权限是为了非 root 用户也可以挂载 /etc/fstab 里面设置了 user 选项的文件系统。由于 setuid 了,就无法依赖内核来做权限检查,必须自己再实现一遍权限检查。可能这里的检查就没有考虑非 root 用户有 CAP_SYS_ADMIN 的情况。
    rome7054
        9
    rome7054   249 天前
    @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
        10
    salamanderMH   249 天前
    @rome7054 谢谢,我现在是这么做了。
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1336 人在线   最高记录 5168   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 19ms · UTC 18:14 · PVG 02:14 · LAX 11:14 · JFK 14:14
    ♥ Do have faith in what you're doing.