Follow symlink for --device argument.

Fixes: #13840

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
This commit is contained in:
Yong Tang 2016-02-25 01:50:39 +00:00
parent e330d0749c
commit 7ed569efdc
2 changed files with 50 additions and 4 deletions

View File

@ -1106,7 +1106,16 @@ func killProcessDirectly(container *container.Container) error {
}
func getDevicesFromPath(deviceMapping containertypes.DeviceMapping) (devs []*configs.Device, err error) {
device, err := devices.DeviceFromPath(deviceMapping.PathOnHost, deviceMapping.CgroupPermissions)
resolvedPathOnHost := deviceMapping.PathOnHost
// check if it is a symbolic link
if src, e := os.Lstat(deviceMapping.PathOnHost); e == nil && src.Mode()&os.ModeSymlink == os.ModeSymlink {
if linkedPathOnHost, e := os.Readlink(deviceMapping.PathOnHost); e == nil {
resolvedPathOnHost = linkedPathOnHost
}
}
device, err := devices.DeviceFromPath(resolvedPathOnHost, deviceMapping.CgroupPermissions)
// if there was no error, return the device
if err == nil {
device.Path = deviceMapping.PathInContainer
@ -1118,10 +1127,10 @@ func getDevicesFromPath(deviceMapping containertypes.DeviceMapping) (devs []*con
if err == devices.ErrNotADevice {
// check if it is a directory
if src, e := os.Stat(deviceMapping.PathOnHost); e == nil && src.IsDir() {
if src, e := os.Stat(resolvedPathOnHost); e == nil && src.IsDir() {
// mount the internal devices recursively
filepath.Walk(deviceMapping.PathOnHost, func(dpath string, f os.FileInfo, e error) error {
filepath.Walk(resolvedPathOnHost, func(dpath string, f os.FileInfo, e error) error {
childDevice, e := devices.DeviceFromPath(dpath, deviceMapping.CgroupPermissions)
if e != nil {
// ignore the device
@ -1129,7 +1138,7 @@ func getDevicesFromPath(deviceMapping containertypes.DeviceMapping) (devs []*con
}
// add the device to userSpecified devices
childDevice.Path = strings.Replace(dpath, deviceMapping.PathOnHost, deviceMapping.PathInContainer, 1)
childDevice.Path = strings.Replace(dpath, resolvedPathOnHost, deviceMapping.PathInContainer, 1)
devs = append(devs, childDevice)
return nil

View File

@ -919,3 +919,40 @@ func (s *DockerSuite) TestRunSeccompWithDefaultProfile(c *check.C) {
c.Assert(err, checker.NotNil, check.Commentf(out))
c.Assert(strings.TrimSpace(out), checker.Equals, "unshare: unshare failed: Operation not permitted")
}
// TestRunDeviceSymlink checks run with device that follows symlink (#13840)
func (s *DockerSuite) TestRunDeviceSymlink(c *check.C) {
testRequires(c, DaemonIsLinux, NotUserNamespace, NotArm, SameHostDaemon)
if _, err := os.Stat("/dev/zero"); err != nil {
c.Skip("Host does not have /dev/zero")
}
// Create a temporary directory to create symlink
tmpDir, err := ioutil.TempDir("", "docker_device_follow_symlink_tests")
c.Assert(err, checker.IsNil)
defer os.RemoveAll(tmpDir)
// Create a symbolic link to /dev/zero
symZero := filepath.Join(tmpDir, "zero")
err = os.Symlink("/dev/zero", symZero)
c.Assert(err, checker.IsNil)
// Create a temporary file "temp" inside tmpDir, write some data to "tmpDir/temp",
// then create a symlink "tmpDir/file" to the temporary file "tmpDir/temp".
tmpFile := filepath.Join(tmpDir, "temp")
err = ioutil.WriteFile(tmpFile, []byte("temp"), 0666)
c.Assert(err, checker.IsNil)
symFile := filepath.Join(tmpDir, "file")
err = os.Symlink(tmpFile, symFile)
c.Assert(err, checker.IsNil)
// md5sum of 'dd if=/dev/zero bs=4K count=8' is bb7df04e1b0a2570657527a7e108ae23
out, _ := dockerCmd(c, "run", "--device", symZero+":/dev/symzero", "busybox", "sh", "-c", "dd if=/dev/symzero bs=4K count=8 | md5sum")
c.Assert(strings.Trim(out, "\r\n"), checker.Contains, "bb7df04e1b0a2570657527a7e108ae23", check.Commentf("expected output bb7df04e1b0a2570657527a7e108ae23"))
// symlink "tmpDir/file" to a file "tmpDir/temp" will result in an error as it is not a device.
out, _, err = dockerCmdWithError("run", "--device", symFile+":/dev/symzero", "busybox", "sh", "-c", "dd if=/dev/symzero bs=4K count=8 | md5sum")
c.Assert(err, check.NotNil)
c.Assert(strings.Trim(out, "\r\n"), checker.Contains, "not a device node", check.Commentf("expected output 'not a device node'"))
}