Skip to content

Commit c0ad40c

Browse files
committed
Do not create devices when in user namespace
When we launch a container in a new user namespace, we cannot create devices, so we bind mount the host's devices into place instead. If we are running in a user namespace (i.e. nested in a container), then we need to do the same thing. Add a function to detect that and check for it before doing mknod. Signed-off-by: Serge Hallyn <[email protected]> --- Changelog - add a comment clarifying what's going on with the uidmap file.
1 parent 749928a commit c0ad40c

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

libcontainer/rootfs_linux.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/opencontainers/runc/libcontainer/cgroups"
1919
"github.com/opencontainers/runc/libcontainer/configs"
2020
"github.com/opencontainers/runc/libcontainer/label"
21+
"github.com/opencontainers/runc/libcontainer/system"
2122
)
2223

2324
const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV
@@ -383,11 +384,12 @@ func reOpenDevNull() error {
383384

384385
// Create the device nodes in the container.
385386
func createDevices(config *configs.Config) error {
387+
useBindMount := system.RunningInUserNS() || config.Namespaces.Contains(configs.NEWUSER)
386388
oldMask := syscall.Umask(0000)
387389
for _, node := range config.Devices {
388390
// containers running in a user namespace are not allowed to mknod
389391
// devices so we can just bind mount it from the host.
390-
if err := createDeviceNode(config.Rootfs, node, config.Namespaces.Contains(configs.NEWUSER)); err != nil {
392+
if err := createDeviceNode(config.Rootfs, node, useBindMount); err != nil {
391393
syscall.Umask(oldMask)
392394
return err
393395
}

libcontainer/system/linux.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
package system
44

55
import (
6+
"bufio"
7+
"fmt"
8+
"os"
69
"os/exec"
710
"syscall"
811
"unsafe"
@@ -75,3 +78,37 @@ func Setctty() error {
7578
}
7679
return nil
7780
}
81+
82+
/*
83+
* Detect whether we are currently running in a user namespace.
84+
* Copied from github.com/lxc/lxd/shared/util.go
85+
*/
86+
func RunningInUserNS() bool {
87+
file, err := os.Open("/proc/self/uid_map")
88+
if err != nil {
89+
/*
90+
* This kernel-provided file only exists if user namespaces are
91+
* supported
92+
*/
93+
return false
94+
}
95+
defer file.Close()
96+
97+
buf := bufio.NewReader(file)
98+
l, _, err := buf.ReadLine()
99+
if err != nil {
100+
return false
101+
}
102+
103+
line := string(l)
104+
var a, b, c int64
105+
fmt.Sscanf(line, "%d %d %d", &a, &b, &c)
106+
/*
107+
* We assume we are in the initial user namespace if we have a full
108+
* range - 4294967295 uids starting at uid 0.
109+
*/
110+
if a == 0 && b == 0 && c == 4294967295 {
111+
return false
112+
}
113+
return true
114+
}

0 commit comments

Comments
 (0)