Browse Source

Fix setting cgroup permission to user/privileged devices

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Tonis Tiigi 9 years ago
parent
commit
ee61235880

+ 16 - 4
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 {

+ 11 - 2
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
 }
 

+ 27 - 0
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))
+}