diff --git a/libcontainer/cgroups/fs/devices.go b/libcontainer/cgroups/fs/devices.go index d621d275c03..069b8a65ed6 100644 --- a/libcontainer/cgroups/fs/devices.go +++ b/libcontainer/cgroups/fs/devices.go @@ -26,6 +26,9 @@ func (s *DevicesGroup) Apply(d *data) error { } func (s *DevicesGroup) Set(path string, cgroup *configs.Cgroup) error { + if cgroup.IsHostUnprivileged { + return nil + } if !cgroup.AllowAllDevices { if err := writeFile(path, "devices.deny", "a"); err != nil { return err diff --git a/libcontainer/configs/cgroup.go b/libcontainer/configs/cgroup.go index bad86b036a6..ecc0a8cc829 100644 --- a/libcontainer/configs/cgroup.go +++ b/libcontainer/configs/cgroup.go @@ -24,6 +24,7 @@ type Cgroup struct { DeniedDevices []*Device `json:"denied_devices"` + IsHostUnprivileged bool `json:"isHostUnprivileged"` // Memory limit (in bytes) Memory int64 `json:"memory"` diff --git a/libcontainer/configs/config.go b/libcontainer/configs/config.go index 7fd311db429..8be9eeb3bef 100644 --- a/libcontainer/configs/config.go +++ b/libcontainer/configs/config.go @@ -72,6 +72,9 @@ type Syscall struct { // Config defines configuration options for executing a process inside a contained environment. type Config struct { + // Indicates if the host is unprivileged + // Used by libcontainer to check whether to mknod and write to devices cgroup + IsHostUnprivileged bool `json:"isHostUnprivileged"` // NoPivotRoot will use MS_MOVE and a chroot to jail the process into the container's rootfs // This is a common option when the container is running in ramdisk NoPivotRoot bool `json:"no_pivot_root"` diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go index 78beb038740..0a981ad0d2b 100644 --- a/libcontainer/rootfs_linux.go +++ b/libcontainer/rootfs_linux.go @@ -370,7 +370,13 @@ func createDevices(config *configs.Config) error { for _, node := range config.Devices { // containers running in a user namespace are not allowed to mknod // devices so we can just bind mount it from the host. - if err := createDeviceNode(config.Rootfs, node, config.Namespaces.Contains(configs.NEWUSER)); err != nil { + isHostUserns := config.IsHostUnprivileged + + isContainerUserns := config.Namespaces.Contains(configs.NEWUSER) + if err := createDeviceNode( + config.Rootfs, + node, + isContainerUserns || isHostUserns); err != nil { syscall.Umask(oldMask) return err } diff --git a/spec.go b/spec.go index 9958f486dd4..ffee2cbe7c6 100644 --- a/spec.go +++ b/spec.go @@ -340,12 +340,12 @@ func createLibcontainerConfig(cgroupName string, spec *specs.LinuxSpec, rspec *s rootfsPath = filepath.Join(cwd, rootfsPath) } config := &configs.Config{ - Rootfs: rootfsPath, - Capabilities: spec.Linux.Capabilities, - Readonlyfs: spec.Root.Readonly, - Hostname: spec.Hostname, + Rootfs: rootfsPath, + Capabilities: spec.Linux.Capabilities, + Readonlyfs: spec.Root.Readonly, + Hostname: spec.Hostname, + IsHostUnprivileged: rspec.Linux.IsHostUnprivileged, } - exists := false if config.RootPropagation, exists = mountPropagationMapping[rspec.Linux.RootfsPropagation]; !exists { return nil, fmt.Errorf("rootfsPropagation=%v is not supported", rspec.Linux.RootfsPropagation) @@ -444,6 +444,7 @@ func createCgroupConfig(name string, spec *specs.LinuxRuntimeSpec, devices []*co AllowedDevices: append(devices, allowedDevices...), } r := spec.Linux.Resources + c.IsHostUnprivileged = spec.Linux.IsHostUnprivileged c.Memory = r.Memory.Limit c.MemoryReservation = r.Memory.Reservation c.MemorySwap = r.Memory.Swap