Skip to content
This repository was archived by the owner on May 12, 2021. It is now read-only.

Commit 27ebdc9

Browse files
committed
device: Check type as well as major:minor when looking up devices
To update device resource entries from host to guest, we search for the right entry by host major:minor numbers, then later update it. However block and character devices exist in separate major:minor namespaces so we could have one block and one character device with matching major:minor and thus incorrectly update both with the details for whichever device is processed second. Add a check on device type to prevent this. Fixes: #835 Signed-off-by: David Gibson <[email protected]>
1 parent d88d468 commit 27ebdc9

File tree

2 files changed

+71
-1
lines changed

2 files changed

+71
-1
lines changed

device.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ func makeDevIndex(spec *pb.Spec) devIndex {
446446

447447
if spec.Linux.Resources != nil && spec.Linux.Resources.Devices != nil {
448448
for j, r := range spec.Linux.Resources.Devices {
449-
if r.Major == d.Major && r.Minor == d.Minor {
449+
if r.Type == d.Type && r.Major == d.Major && r.Minor == d.Minor {
450450
rIdx = append(rIdx, j)
451451
}
452452
}

device_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,76 @@ func TestUpdateSpecDeviceListGuestHostConflict(t *testing.T) {
615615
assert.Equal(guestMinorB, spec.Linux.Resources.Devices[1].Minor)
616616
}
617617

618+
// Test handling in the case that the host has a block device and a
619+
// character device with the same major:minor, but the equivalent
620+
// guest devices do *not* have the same major:minor
621+
func TestUpdateSpecDeviceListCharBlockConflict(t *testing.T) {
622+
assert := assert.New(t)
623+
624+
var nullStat unix.Stat_t
625+
err := unix.Stat("/dev/null", &nullStat)
626+
assert.NoError(err)
627+
628+
guestMajor := int64(unix.Major(nullStat.Rdev))
629+
guestMinor := int64(unix.Minor(nullStat.Rdev))
630+
631+
hostMajor := int64(99)
632+
hostMinor := int64(99)
633+
634+
spec := &pb.Spec{
635+
Linux: &pb.Linux{
636+
Devices: []pb.LinuxDevice{
637+
{
638+
Path: "/dev/char",
639+
Type: "c",
640+
Major: hostMajor,
641+
Minor: hostMinor,
642+
},
643+
{
644+
Path: "/dev/block",
645+
Type: "b",
646+
Major: hostMajor,
647+
Minor: hostMinor,
648+
},
649+
},
650+
Resources: &pb.LinuxResources{
651+
Devices: []pb.LinuxDeviceCgroup{
652+
{
653+
Type: "c",
654+
Major: hostMajor,
655+
Minor: hostMinor,
656+
},
657+
{
658+
Type: "b",
659+
Major: hostMajor,
660+
Minor: hostMinor,
661+
},
662+
},
663+
},
664+
},
665+
}
666+
667+
dev := pb.Device{
668+
ContainerPath: "/dev/char",
669+
VmPath: "/dev/null",
670+
}
671+
672+
assert.Equal(hostMajor, spec.Linux.Resources.Devices[0].Major)
673+
assert.Equal(hostMinor, spec.Linux.Resources.Devices[0].Minor)
674+
assert.Equal(hostMajor, spec.Linux.Resources.Devices[1].Major)
675+
assert.Equal(hostMinor, spec.Linux.Resources.Devices[1].Minor)
676+
677+
devIdx := makeDevIndex(spec)
678+
err = updateSpecDeviceList(dev, spec, devIdx)
679+
assert.NoError(err)
680+
681+
// Only the char device, not the block device should be updated
682+
assert.Equal(guestMajor, spec.Linux.Resources.Devices[0].Major)
683+
assert.Equal(guestMinor, spec.Linux.Resources.Devices[0].Minor)
684+
assert.Equal(hostMajor, spec.Linux.Resources.Devices[1].Major)
685+
assert.Equal(hostMinor, spec.Linux.Resources.Devices[1].Minor)
686+
}
687+
618688
func TestRescanPciBus(t *testing.T) {
619689
skipUnlessRoot(t)
620690

0 commit comments

Comments
 (0)