diff --git a/SPEC.md b/SPEC.md index 78fee33..788c6d6 100644 --- a/SPEC.md +++ b/SPEC.md @@ -139,6 +139,7 @@ The keywords "must", "must not", "required", "shall", "shall not", "should", "sh // * r - allows container to read from the specified device. // * w - allows container to write to the specified device. // * m - allows container to create device files that do not yet exist. + // Omitted or empty permissions default to 'rwm'. 'none' requests empty permissions. "permissions": "" (optional), "uid": (optional), "gid": (optional) diff --git a/pkg/cdi/container-edits.go b/pkg/cdi/container-edits.go index f498049..6c69685 100644 --- a/pkg/cdi/container-edits.go +++ b/pkg/cdi/container-edits.go @@ -42,6 +42,9 @@ const ( PoststartHook = "poststart" // PoststopHook is the name of the OCI "poststop" hook. PoststopHook = "poststop" + + // NoPermissions requests empty cgroup permissions for a device. + NoPermissions = "none" ) var ( @@ -106,8 +109,11 @@ func (e *ContainerEdits) Apply(spec *oci.Spec) error { if dev.Type == "b" || dev.Type == "c" { access := d.Permissions - if access == "" { + switch access { + case "": access = "rwm" + case NoPermissions: + access = "" } specgen.AddLinuxResourcesDevice(true, dev.Type, &dev.Major, &dev.Minor, access) } @@ -354,10 +360,12 @@ func (d *DeviceNode) Validate() error { if _, ok := validTypes[d.Type]; !ok { return fmt.Errorf("device %q: invalid type %q", d.Path, d.Type) } - for _, bit := range d.Permissions { - if bit != 'r' && bit != 'w' && bit != 'm' { - return fmt.Errorf("device %q: invalid permissions %q", - d.Path, d.Permissions) + if d.Permissions != NoPermissions { + for _, bit := range d.Permissions { + if bit != 'r' && bit != 'w' && bit != 'm' { + return fmt.Errorf("device %q: invalid permissions %q", + d.Path, d.Permissions) + } } } return nil diff --git a/pkg/cdi/container-edits_test.go b/pkg/cdi/container-edits_test.go index 2c553d9..a4711aa 100644 --- a/pkg/cdi/container-edits_test.go +++ b/pkg/cdi/container-edits_test.go @@ -133,6 +133,18 @@ func TestValidateContainerEdits(t *testing.T) { }, invalid: true, }, + { + name: "valid device, with NoPermissions", + edits: &cdi.ContainerEdits{ + DeviceNodes: []*cdi.DeviceNode{ + { + Path: "/dev/vendorctl", + Type: "b", + Permissions: NoPermissions, + }, + }, + }, + }, { name: "valid mount", edits: &cdi.ContainerEdits{ @@ -420,6 +432,44 @@ func TestApplyContainerEdits(t *testing.T) { }, }, }, + { + name: "empty spec, device with explicitly empty permissions", + spec: &oci.Spec{}, + edits: &cdi.ContainerEdits{ + DeviceNodes: []*cdi.DeviceNode{ + { + Path: "/dev/nil", + Type: "c", + Major: 1, + Minor: 3, + Permissions: NoPermissions, + }, + }, + }, + result: &oci.Spec{ + Linux: &oci.Linux{ + Devices: []oci.LinuxDevice{ + { + Path: "/dev/nil", + Type: "c", + Major: nullDeviceMajor, + Minor: nullDeviceMinor, + }, + }, + Resources: &oci.LinuxResources{ + Devices: []oci.LinuxDeviceCgroup{ + { + Allow: true, + Type: "c", + Major: &nullDeviceMajor, + Minor: &nullDeviceMinor, + Access: "", + }, + }, + }, + }, + }, + }, { name: "empty spec, device, env var", spec: &oci.Spec{},