diff --git a/daemon/container_operations_unix.go b/daemon/container_operations_unix.go index dd637f5a04..a313ef5ccf 100644 --- a/daemon/container_operations_unix.go +++ b/daemon/container_operations_unix.go @@ -295,7 +295,18 @@ func specDevice(d *configs.Device) specs.Device { } } -func getDevicesFromPath(deviceMapping containertypes.DeviceMapping) (devs []specs.Device, err error) { +func specDeviceCgroup(d *configs.Device) specs.DeviceCgroup { + t := string(d.Type) + return specs.DeviceCgroup{ + Allow: true, + Type: &t, + Major: &d.Major, + Minor: &d.Minor, + Access: &d.Permissions, + } +} + +func getDevicesFromPath(deviceMapping containertypes.DeviceMapping) (devs []specs.Device, devPermissions []specs.DeviceCgroup, err error) { resolvedPathOnHost := deviceMapping.PathOnHost // check if it is a symbolic link @@ -309,7 +320,7 @@ func getDevicesFromPath(deviceMapping containertypes.DeviceMapping) (devs []spec // if there was no error, return the device if err == nil { device.Path = deviceMapping.PathInContainer - return append(devs, specDevice(device)), nil + return append(devs, specDevice(device)), append(devPermissions, specDeviceCgroup(device)), nil } // if the device is not a device node @@ -330,6 +341,7 @@ func getDevicesFromPath(deviceMapping containertypes.DeviceMapping) (devs []spec // add the device to userSpecified devices childDevice.Path = strings.Replace(dpath, resolvedPathOnHost, deviceMapping.PathInContainer, 1) devs = append(devs, specDevice(childDevice)) + devPermissions = append(devPermissions, specDeviceCgroup(childDevice)) return nil }) @@ -337,10 +349,10 @@ func getDevicesFromPath(deviceMapping containertypes.DeviceMapping) (devs []spec } if len(devs) > 0 { - return devs, nil + return devs, devPermissions, nil } - return devs, fmt.Errorf("error gathering device information while adding custom device %q: %s", deviceMapping.PathOnHost, err) + return devs, devPermissions, fmt.Errorf("error gathering device information while adding custom device %q: %s", deviceMapping.PathOnHost, err) } func mergeDevices(defaultDevices, userDevices []*configs.Device) []*configs.Device { diff --git a/daemon/oci_linux.go b/daemon/oci_linux.go index f00e0416a6..9f14ed078c 100644 --- a/daemon/oci_linux.go +++ b/daemon/oci_linux.go @@ -78,6 +78,7 @@ func setResources(s *specs.Spec, r containertypes.Resources) error { func setDevices(s *specs.Spec, c *container.Container) error { // Build lists of devices allowed and created within the container. var devs []specs.Device + devPermissions := s.Linux.Resources.Devices if c.HostConfig.Privileged { hostDevices, err := devices.HostDevices() if err != nil { @@ -86,18 +87,26 @@ func setDevices(s *specs.Spec, c *container.Container) error { for _, d := range hostDevices { devs = append(devs, specDevice(d)) } + rwm := "rwm" + devPermissions = []specs.DeviceCgroup{ + { + Allow: true, + Access: &rwm, + }, + } } else { for _, deviceMapping := range c.HostConfig.Devices { - d, err := getDevicesFromPath(deviceMapping) + d, dPermissions, err := getDevicesFromPath(deviceMapping) if err != nil { return err } - devs = append(devs, d...) + devPermissions = append(devPermissions, dPermissions...) } } s.Linux.Devices = append(s.Linux.Devices, devs...) + s.Linux.Resources.Devices = devPermissions return nil } diff --git a/integration-cli/docker_cli_run_unix_test.go b/integration-cli/docker_cli_run_unix_test.go index 624fbf8ba2..150a10aec4 100644 --- a/integration-cli/docker_cli_run_unix_test.go +++ b/integration-cli/docker_cli_run_unix_test.go @@ -13,6 +13,7 @@ import ( "strconv" "strings" "sync" + "syscall" "time" "github.com/docker/docker/pkg/homedir" @@ -980,3 +981,29 @@ func (s *DockerSuite) TestRunPidsLimit(c *check.C) { out = inspectField(c, "skittles", "HostConfig.PidsLimit") c.Assert(out, checker.Equals, "2", check.Commentf("setting the pids limit failed")) } + +func (s *DockerSuite) TestRunPrivilegedAllowedDevices(c *check.C) { + testRequires(c, DaemonIsLinux) + + file := "/sys/fs/cgroup/devices/devices.list" + out, _ := dockerCmd(c, "run", "--privileged", "busybox", "cat", file) + c.Logf("out: %q", out) + c.Assert(strings.TrimSpace(out), checker.Equals, "a *:* rwm") +} + +func (s *DockerSuite) TestRunUserDeviceAllowed(c *check.C) { + testRequires(c, DaemonIsLinux) + + fi, err := os.Stat("/dev/snd/timer") + if err != nil { + c.Skip("Host does not have /dev/snd/timer") + } + stat, ok := fi.Sys().(*syscall.Stat_t) + if !ok { + c.Skip("Could not stat /dev/snd/timer") + } + + file := "/sys/fs/cgroup/devices/devices.list" + out, _ := dockerCmd(c, "run", "--device", "/dev/snd/timer:w", "busybox", "cat", file) + c.Assert(out, checker.Contains, fmt.Sprintf("c %d:%d w", stat.Rdev/256, stat.Rdev%256)) +}