Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

error about User Namespace #3

Closed
lvxingzhe opened this issue Jul 29, 2017 · 16 comments

Comments

@lvxingzhe
Copy link

commented Jul 29, 2017

使用root权限运行go run main.go,"main.go"如下所示:

//main.go
package main

import (
	"log"
	"os"
	"os/exec"
	"syscall"
)

func main() {
	cmd := exec.Command("sh")
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWPID |
			syscall.CLONE_NEWNS | syscall.CLONE_NEWUSER,
	}
	cmd.SysProcAttr.Credential = &syscall.Credential{
		Uid: uint32(1), Gid: uint32(1)}
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		log.Fatal(err)
	}
	os.Exit(-1)
}

会出现下列报错

2017/07/30 01:27:36 fork/exec /bin/sh: operation not permitted
exit status 1

谁能解答一下?

@BSWANG

This comment has been minimized.

Copy link
Collaborator

commented Jul 31, 2017

请提供下你运行的操作系统的版本和内核的版本,我们复现下

@BSWANG

This comment has been minimized.

Copy link
Collaborator

commented Jul 31, 2017

Linux kernel在3.19以上的版本中对user namespace做了些修改,我怀疑跟这个有关,链接是:https://go-review.googlesource.com/c/10670/
我们当时开发验证的操作系统版本和内核版本是ubuntu 14.04kernel-3.13,可以切换成同样的环境验证,或者你如果有在高版本内核上兼容的实现方案,欢迎提交PR。

@BSWANG

This comment has been minimized.

Copy link
Collaborator

commented Jul 31, 2017

刚才在4.4的内核上测试了下那个代码,这样修改就可以在4.4内核正确运行了,修改后的代码是:

//main.go
package main

import (
	"log"
	"os"
	"os/exec"
	"syscall"
)

func main() {
	cmd := exec.Command("sh")
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWPID |
			syscall.CLONE_NEWNS | syscall.CLONE_NEWUSER,
		UidMappings: []syscall.SysProcIDMap{
			{
				ContainerID: 1234,
				HostID:      0,
				Size:        1,
			},
		},
		GidMappings: []syscall.SysProcIDMap{
			{
				ContainerID: 1234,
				HostID:      0,
				Size:        1,
			},
		},
	}
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		log.Fatal(err)
	}
	os.Exit(-1)
}

请确认是否解决,我先关闭这个issue了,有问题可以随时在Open这个issue

@luhuisicnu

This comment has been minimized.

Copy link

commented Aug 30, 2017

我的环境:

# uname -a
Linux drjr-ThinkPad-T520 4.4.0-92-generic #115-Ubuntu SMP Thu Aug 10 09:04:33 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

我通过删除该代码成功运行了书中的示例。
被删除的代码
cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uiint32(1), Gid: uint32(1)}
运行展示

# go run main.go 
$ id
uid=65534(nobody) gid=65534(nogroup) 组=65534(nogroup)

代码如下:

package main

import (
	"log"
	"os"
	"os/exec"
	"syscall"
)

func main() {
	cmd := exec.Command("sh")
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWIPC | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS |
			syscall.CLONE_NEWUSER,
	}
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	if err := cmd.Run(); err != nil {
		log.Fatal(err)
	}
	os.Exit(-1)
}

@BSWANG

This comment has been minimized.

Copy link
Collaborator

commented Aug 31, 2017

@luhuisicnu 是的,4.4的内核不在支持cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uiint32(1), Gid: uint32(1)}的方式

@riclava

This comment has been minimized.

Copy link

commented Feb 8, 2018

@BSWANG 补充下,在ubuntu 16.04 - 4.13内核上,你上面给出的代码也不能通过了

@BSWANG

This comment has been minimized.

Copy link
Collaborator

commented Feb 8, 2018

@riclava 尴尬,kernel在更新时有些兼容性可能不能保证,你如果发现了在4.13上或者兼容所有的解决办法欢迎贡献代码给我们

@riclava

This comment has been minimized.

Copy link

commented Feb 8, 2018

@BSWANG 尴尬尴尬😅 我的问题,不知什么时候退了sudo -s了;不过 golang 的 issue#10626 上面的代码可以借鉴(非root也能跑,当然部分Namespace没有权限):

UidMappings: []syscall.SysProcIDMap{
	{
		ContainerID: 1234,
		HostID:      syscall.Getuid(),
		Size:        1,
	},
},
GidMappings: []syscall.SysProcIDMap{
	{
		ContainerID: 1234,
		HostID:      syscall.Getgid(),
		Size:        1,
	},
},

效果:

ricl@ricl:~/code/playground$ make
go run main.go
$ id
uid=1234 gid=1234 groups=1234,65534(nogroup)
$

尴尬 ;-(

@xieydd

This comment has been minimized.

Copy link

commented Jun 12, 2018

上面两种方法都试了,不行呢?

[root@15-pxe Docker]# uname -a
Linux 15-pxe 3.10.0-514.el7.x86_64 #1 SMP Tue Nov 22 16:42:41 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
@Lemon-le

This comment has been minimized.

Copy link

commented Jun 25, 2018

我的也是上面两种都试了 不行 Linux iZj6c5dly2y6k9y0thzjoqZ 3.10.0-693.2.2.el7.x86_64 #1 SMP Tue Sep 12 22:26:13 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

@v1xingyue

This comment has been minimized.

Copy link

commented Jan 14, 2019

centos7 3.10 的内核 , 报错:

2019/01/14 13:46:57 fork/exec /bin/sh: invalid argument 各种方法都试了,总是这个错误。求解

@Arbusz

This comment has been minimized.

Copy link

commented Jan 15, 2019

Linux VM_86_181_centos 3.10.0-693.21.1.el7.x86_64 #1 SMP Wed Mar 7 19:03:37 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
fork/exec /usr/bin/sh: invalid argument
目前还未解决

@dayuoba

This comment has been minimized.

Copy link

commented Feb 13, 2019

@v1xingyue @Arbusz
centos默认的没有开启user namespace,参考链接
https://zhuanlan.zhihu.com/p/31871814
golang/go#16283

@Zenoe

This comment has been minimized.

Copy link

commented Mar 13, 2019

grubby --args="user_namespace.enable=1" --update-kernel="$(grubby --default-kernel)"
执行后要reboot

@fucangyu

This comment has been minimized.

Copy link

commented Apr 5, 2019

centos7

[root@mydocker chapter2]# uname -a
Linux mydocker 3.10.0-957.10.1.el7.x86_64 #1 SMP Mon Mar 18 15:06:45 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux

如果已经内核开启user_namespace依旧invalid argument的话
使用下面的命令fixed

echo 640 > /proc/sys/user/max_user_namespaces

https://unix.stackexchange.com/questions/479635/unable-to-create-user-namespace-in-rhel?rq=1

@hikame

This comment has been minimized.

Copy link

commented Apr 8, 2019

内核:4.15.0-47-generic
系统:Ubuntu 18.04.2 LTS

func main() {
	cmd := exec.Command("sh")
	cmd.SysProcAttr = &syscall.SysProcAttr{
		// Cloneflags: syscall.CLONE_NEWUTS,
		// Cloneflags: syscall.CLONE_NEWIPC,
		// Cloneflags: syscall.CLONE_NEWPID,
		// Cloneflags: syscall.CLONE_NEWNS,
		Cloneflags: syscall.CLONE_NEWUSER,
	}
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err := cmd.Run(); err != nil {
		log.Fatal(err)
	}
	os.Exit(0)
}

除了CLONE_NEWUSER外,其他均无法用普通用户权限执行,但CLONE_NEWUSER | CLONE_XXXXX可以。

此外,关于UID和GID的设置,在我的测试系统中有如下发现:

	cmd.SysProcAttr = &syscall.SysProcAttr{
		Cloneflags: syscall.CLONE_NEWUSER,
		/*
			以下两种情况,会导致UidMappings/GidMappings中设置了非当前进程所属UID和GID的相关数值:
			1. HostID非本进程所有(与Getuid()和Getgid()不等)
			2. Size大于1 (则肯定包含非当前进程的UID和GID)
			则需要Host机使用Root权限才能正常执行此段代码。
		*/
		UidMappings: []syscall.SysProcIDMap{
			{
				ContainerID: 10086,
				HostID:      syscall.Getuid(),
				Size:        1,
			},
			{
				ContainerID: 10010,
				HostID:      syscall.Getgid() + 1,
				Size:        1,
			},
		},
		GidMappings: []syscall.SysProcIDMap{
			{
				ContainerID: 10086,
				HostID:      syscall.Getgid(),
				Size:        1,
			},
			{
				ContainerID: 10010,
				HostID:      syscall.Getgid() + 1,
				Size:        1,
			},
		},
	}

以上规则应该是处于安全的考虑

iBug added a commit to iBug/my-docker that referenced this issue Jul 18, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
You can’t perform that action at this time.