From 677baf22d24815cdab01817af8bf64d2073b0db1 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 10 Nov 2020 10:30:51 +0100 Subject: [PATCH] libcontainer: isolate libcontainer/devices Move the Device-related types to libcontainer/devices, so that the package can be used in isolation. Aliases have been created in libcontainer/configs for backward compatibility. Signed-off-by: Sebastiaan van Stijn --- .../cgroups/devices/devices_emulator.go | 46 +- .../cgroups/devices/devices_emulator_test.go | 530 +++++++++--------- .../cgroups/ebpf/devicefilter/devicefilter.go | 6 +- .../ebpf/devicefilter/devicefilter_test.go | 12 +- libcontainer/cgroups/fs/devices.go | 11 +- libcontainer/cgroups/fs/devices_test.go | 12 +- libcontainer/cgroups/fs2/devices.go | 3 +- libcontainer/cgroups/systemd/common.go | 35 +- libcontainer/configs/cgroup_linux.go | 3 +- libcontainer/configs/config.go | 3 +- libcontainer/configs/devices.go | 17 + libcontainer/{configs => devices}/device.go | 2 +- .../{configs => devices}/device_unix.go | 2 +- .../{configs => devices}/device_windows.go | 2 +- libcontainer/devices/devices.go | 25 +- libcontainer/devices/devices_test.go | 7 +- libcontainer/integration/template_test.go | 4 +- libcontainer/rootfs_linux.go | 14 +- libcontainer/specconv/spec_linux.go | 87 +-- libcontainer/specconv/spec_linux_test.go | 10 +- 20 files changed, 426 insertions(+), 405 deletions(-) create mode 100644 libcontainer/configs/devices.go rename libcontainer/{configs => devices}/device.go (99%) rename libcontainer/{configs => devices}/device_unix.go (94%) rename libcontainer/{configs => devices}/device_windows.go (80%) diff --git a/libcontainer/cgroups/devices/devices_emulator.go b/libcontainer/cgroups/devices/devices_emulator.go index 6afedbc6e73..670c14736ed 100644 --- a/libcontainer/cgroups/devices/devices_emulator.go +++ b/libcontainer/cgroups/devices/devices_emulator.go @@ -27,7 +27,7 @@ import ( "sort" "strconv" - "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/devices" "github.com/pkg/errors" ) @@ -36,7 +36,7 @@ import ( // wildcard-type support. It's effectively the "match" portion of a metadata // rule, for the purposes of our emulation. type deviceMeta struct { - node configs.DeviceType + node devices.DeviceType major int64 minor int64 } @@ -44,12 +44,12 @@ type deviceMeta struct { // deviceRule is effectively the tuple (deviceMeta, DevicePermissions). type deviceRule struct { meta deviceMeta - perms configs.DevicePermissions + perms devices.DevicePermissions } // deviceRules is a mapping of device metadata rules to the associated // permissions in the ruleset. -type deviceRules map[deviceMeta]configs.DevicePermissions +type deviceRules map[deviceMeta]devices.DevicePermissions func (r deviceRules) orderedEntries() []deviceRule { var rules []deviceRule @@ -103,9 +103,9 @@ func parseLine(line string) (*deviceRule, error) { // TODO: Double-check that the entire file is "a *:* rwm". return nil, nil case "b": - rule.meta.node = configs.BlockDevice + rule.meta.node = devices.BlockDevice case "c": - rule.meta.node = configs.CharDevice + rule.meta.node = devices.CharDevice default: // Should never happen! return nil, errors.Errorf("unknown device type %q", node) @@ -113,7 +113,7 @@ func parseLine(line string) (*deviceRule, error) { // Parse the major number. if major == "*" { - rule.meta.major = configs.Wildcard + rule.meta.major = devices.Wildcard } else { val, err := strconv.ParseUint(major, 10, 32) if err != nil { @@ -124,7 +124,7 @@ func parseLine(line string) (*deviceRule, error) { // Parse the minor number. if minor == "*" { - rule.meta.minor = configs.Wildcard + rule.meta.minor = devices.Wildcard } else { val, err := strconv.ParseUint(minor, 10, 32) if err != nil { @@ -134,7 +134,7 @@ func parseLine(line string) (*deviceRule, error) { } // Parse the access permissions. - rule.perms = configs.DevicePermissions(perms) + rule.perms = devices.DevicePermissions(perms) if !rule.perms.IsValid() || rule.perms.IsEmpty() { // Should never happen! return nil, errors.Errorf("parse access mode: contained unknown modes or is empty: %q", perms) @@ -144,7 +144,7 @@ func parseLine(line string) (*deviceRule, error) { func (e *Emulator) addRule(rule deviceRule) error { if e.rules == nil { - e.rules = make(map[deviceMeta]configs.DevicePermissions) + e.rules = make(map[deviceMeta]devices.DevicePermissions) } // Merge with any pre-existing permissions. @@ -169,9 +169,9 @@ func (e *Emulator) rmRule(rule deviceRule) error { // to mention it'd be really slow (the kernel side is implemented as a // linked-list of exceptions). for _, partialMeta := range []deviceMeta{ - {node: rule.meta.node, major: configs.Wildcard, minor: rule.meta.minor}, - {node: rule.meta.node, major: rule.meta.major, minor: configs.Wildcard}, - {node: rule.meta.node, major: configs.Wildcard, minor: configs.Wildcard}, + {node: rule.meta.node, major: devices.Wildcard, minor: rule.meta.minor}, + {node: rule.meta.node, major: rule.meta.major, minor: devices.Wildcard}, + {node: rule.meta.node, major: devices.Wildcard, minor: devices.Wildcard}, } { // This wildcard rule is equivalent to the requested rule, so skip it. if rule.meta == partialMeta { @@ -202,7 +202,7 @@ func (e *Emulator) rmRule(rule deviceRule) error { func (e *Emulator) allow(rule *deviceRule) error { // This cgroup is configured as a black-list. Reset the entire emulator, // and put is into black-list mode. - if rule == nil || rule.meta.node == configs.WildcardDevice { + if rule == nil || rule.meta.node == devices.WildcardDevice { *e = Emulator{ defaultAllow: true, rules: nil, @@ -222,7 +222,7 @@ func (e *Emulator) allow(rule *deviceRule) error { func (e *Emulator) deny(rule *deviceRule) error { // This cgroup is configured as a white-list. Reset the entire emulator, // and put is into white-list mode. - if rule == nil || rule.meta.node == configs.WildcardDevice { + if rule == nil || rule.meta.node == devices.WildcardDevice { *e = Emulator{ defaultAllow: false, rules: nil, @@ -239,7 +239,7 @@ func (e *Emulator) deny(rule *deviceRule) error { return err } -func (e *Emulator) Apply(rule configs.DeviceRule) error { +func (e *Emulator) Apply(rule devices.DeviceRule) error { if !rule.Type.CanCgroup() { return errors.Errorf("cannot add rule [%#v] with non-cgroup type %q", rule, rule.Type) } @@ -252,7 +252,7 @@ func (e *Emulator) Apply(rule configs.DeviceRule) error { }, perms: rule.Permissions, } - if innerRule.meta.node == configs.WildcardDevice { + if innerRule.meta.node == devices.WildcardDevice { innerRule = nil } @@ -307,8 +307,8 @@ func EmulatorFromList(list io.Reader) (*Emulator, error) { // This function is the sole reason for all of Emulator -- to allow us // to figure out how to update a containers' cgroups without causing spurrious // device errors (if possible). -func (source *Emulator) Transition(target *Emulator) ([]*configs.DeviceRule, error) { - var transitionRules []*configs.DeviceRule +func (source *Emulator) Transition(target *Emulator) ([]*devices.DeviceRule, error) { + var transitionRules []*devices.DeviceRule oldRules := source.rules // If the default policy doesn't match, we need to include a "disruptive" @@ -319,11 +319,11 @@ func (source *Emulator) Transition(target *Emulator) ([]*configs.DeviceRule, err // deny rules are in place in a black-list cgroup. Thus if the source is a // black-list we also have to include a disruptive rule. if source.IsBlacklist() || source.defaultAllow != target.defaultAllow { - transitionRules = append(transitionRules, &configs.DeviceRule{ + transitionRules = append(transitionRules, &devices.DeviceRule{ Type: 'a', Major: -1, Minor: -1, - Permissions: configs.DevicePermissions("rwm"), + Permissions: devices.DevicePermissions("rwm"), Allow: target.defaultAllow, }) // The old rules are only relevant if we aren't starting out with a @@ -342,7 +342,7 @@ func (source *Emulator) Transition(target *Emulator) ([]*configs.DeviceRule, err newPerms := target.rules[meta] droppedPerms := oldPerms.Difference(newPerms) if !droppedPerms.IsEmpty() { - transitionRules = append(transitionRules, &configs.DeviceRule{ + transitionRules = append(transitionRules, &devices.DeviceRule{ Type: meta.node, Major: meta.major, Minor: meta.minor, @@ -360,7 +360,7 @@ func (source *Emulator) Transition(target *Emulator) ([]*configs.DeviceRule, err oldPerms := oldRules[meta] gainedPerms := newPerms.Difference(oldPerms) if !gainedPerms.IsEmpty() { - transitionRules = append(transitionRules, &configs.DeviceRule{ + transitionRules = append(transitionRules, &devices.DeviceRule{ Type: meta.node, Major: meta.major, Minor: meta.minor, diff --git a/libcontainer/cgroups/devices/devices_emulator_test.go b/libcontainer/cgroups/devices/devices_emulator_test.go index 75e751c307c..9ea02e7f652 100644 --- a/libcontainer/cgroups/devices/devices_emulator_test.go +++ b/libcontainer/cgroups/devices/devices_emulator_test.go @@ -23,7 +23,7 @@ import ( "reflect" "testing" - "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/devices" ) func TestDeviceEmulatorLoad(t *testing.T) { @@ -45,10 +45,10 @@ func TestDeviceEmulatorLoad(t *testing.T) { defaultAllow: false, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 4, minor: 2, - }: configs.DevicePermissions("rw"), + }: devices.DevicePermissions("rw"), }, }, }, @@ -59,10 +59,10 @@ func TestDeviceEmulatorLoad(t *testing.T) { defaultAllow: false, rules: deviceRules{ { - node: configs.BlockDevice, + node: devices.BlockDevice, major: 0, - minor: configs.Wildcard, - }: configs.DevicePermissions("m"), + minor: devices.Wildcard, + }: devices.DevicePermissions("m"), }, }, }, @@ -74,16 +74,16 @@ c 1:1 r`, defaultAllow: false, rules: deviceRules{ { - node: configs.CharDevice, - major: configs.Wildcard, - minor: configs.Wildcard, - }: configs.DevicePermissions("rwm"), + node: devices.CharDevice, + major: devices.Wildcard, + minor: devices.Wildcard, + }: devices.DevicePermissions("rwm"), // To match the kernel, we allow redundant rules. { - node: configs.CharDevice, + node: devices.CharDevice, major: 1, minor: 1, - }: configs.DevicePermissions("r"), + }: devices.DevicePermissions("r"), }, }, }, @@ -104,60 +104,60 @@ c 10:200 rwm`, defaultAllow: false, rules: deviceRules{ { - node: configs.CharDevice, - major: configs.Wildcard, - minor: configs.Wildcard, - }: configs.DevicePermissions("m"), + node: devices.CharDevice, + major: devices.Wildcard, + minor: devices.Wildcard, + }: devices.DevicePermissions("m"), { - node: configs.BlockDevice, - major: configs.Wildcard, - minor: configs.Wildcard, - }: configs.DevicePermissions("m"), + node: devices.BlockDevice, + major: devices.Wildcard, + minor: devices.Wildcard, + }: devices.DevicePermissions("m"), { - node: configs.CharDevice, + node: devices.CharDevice, major: 1, minor: 3, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), { - node: configs.CharDevice, + node: devices.CharDevice, major: 1, minor: 5, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), { - node: configs.CharDevice, + node: devices.CharDevice, major: 1, minor: 7, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), { - node: configs.CharDevice, + node: devices.CharDevice, major: 1, minor: 8, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), { - node: configs.CharDevice, + node: devices.CharDevice, major: 1, minor: 9, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), { - node: configs.CharDevice, + node: devices.CharDevice, major: 5, minor: 0, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), { - node: configs.CharDevice, + node: devices.CharDevice, major: 5, minor: 2, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), { - node: configs.CharDevice, + node: devices.CharDevice, major: 136, - minor: configs.Wildcard, - }: configs.DevicePermissions("rwm"), + minor: devices.Wildcard, + }: devices.DevicePermissions("rwm"), { - node: configs.CharDevice, + node: devices.CharDevice, major: 10, minor: 200, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), }, }, }, @@ -220,32 +220,32 @@ c 10:200 rwm`, func testDeviceEmulatorApply(t *testing.T, baseDefaultAllow bool) { tests := []struct { name string - rule configs.DeviceRule + rule devices.DeviceRule base, expected *Emulator }{ // Switch between default modes. { name: "SwitchToOtherMode", - rule: configs.DeviceRule{ - Type: configs.WildcardDevice, - Major: configs.Wildcard, - Minor: configs.Wildcard, - Permissions: configs.DevicePermissions("rwm"), + rule: devices.DeviceRule{ + Type: devices.WildcardDevice, + Major: devices.Wildcard, + Minor: devices.Wildcard, + Permissions: devices.DevicePermissions("rwm"), Allow: !baseDefaultAllow, }, base: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, - major: configs.Wildcard, - minor: configs.Wildcard, - }: configs.DevicePermissions("rwm"), + node: devices.CharDevice, + major: devices.Wildcard, + minor: devices.Wildcard, + }: devices.DevicePermissions("rwm"), { - node: configs.CharDevice, + node: devices.CharDevice, major: 1, minor: 1, - }: configs.DevicePermissions("r"), + }: devices.DevicePermissions("r"), }, }, expected: &Emulator{ @@ -255,11 +255,11 @@ func testDeviceEmulatorApply(t *testing.T, baseDefaultAllow bool) { }, { name: "SwitchToSameModeNoop", - rule: configs.DeviceRule{ - Type: configs.WildcardDevice, - Major: configs.Wildcard, - Minor: configs.Wildcard, - Permissions: configs.DevicePermissions("rwm"), + rule: devices.DeviceRule{ + Type: devices.WildcardDevice, + Major: devices.Wildcard, + Minor: devices.Wildcard, + Permissions: devices.DevicePermissions("rwm"), Allow: baseDefaultAllow, }, base: &Emulator{ @@ -273,26 +273,26 @@ func testDeviceEmulatorApply(t *testing.T, baseDefaultAllow bool) { }, { name: "SwitchToSameMode", - rule: configs.DeviceRule{ - Type: configs.WildcardDevice, - Major: configs.Wildcard, - Minor: configs.Wildcard, - Permissions: configs.DevicePermissions("rwm"), + rule: devices.DeviceRule{ + Type: devices.WildcardDevice, + Major: devices.Wildcard, + Minor: devices.Wildcard, + Permissions: devices.DevicePermissions("rwm"), Allow: baseDefaultAllow, }, base: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, - major: configs.Wildcard, - minor: configs.Wildcard, - }: configs.DevicePermissions("rwm"), + node: devices.CharDevice, + major: devices.Wildcard, + minor: devices.Wildcard, + }: devices.DevicePermissions("rwm"), { - node: configs.CharDevice, + node: devices.CharDevice, major: 1, minor: 1, - }: configs.DevicePermissions("r"), + }: devices.DevicePermissions("r"), }, }, expected: &Emulator{ @@ -303,373 +303,373 @@ func testDeviceEmulatorApply(t *testing.T, baseDefaultAllow bool) { // Rule addition logic. { name: "RuleAdditionBasic", - rule: configs.DeviceRule{ - Type: configs.CharDevice, + rule: devices.DeviceRule{ + Type: devices.CharDevice, Major: 42, Minor: 1337, - Permissions: configs.DevicePermissions("rm"), + Permissions: devices.DevicePermissions("rm"), Allow: !baseDefaultAllow, }, base: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 2, minor: 1, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), { - node: configs.BlockDevice, + node: devices.BlockDevice, major: 1, minor: 5, - }: configs.DevicePermissions("r"), + }: devices.DevicePermissions("r"), }, }, expected: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 2, minor: 1, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), { - node: configs.BlockDevice, + node: devices.BlockDevice, major: 1, minor: 5, - }: configs.DevicePermissions("r"), + }: devices.DevicePermissions("r"), { - node: configs.CharDevice, + node: devices.CharDevice, major: 42, minor: 1337, - }: configs.DevicePermissions("rm"), + }: devices.DevicePermissions("rm"), }, }, }, { name: "RuleAdditionBasicDuplicate", - rule: configs.DeviceRule{ - Type: configs.CharDevice, + rule: devices.DeviceRule{ + Type: devices.CharDevice, Major: 42, Minor: 1337, - Permissions: configs.DevicePermissions("rm"), + Permissions: devices.DevicePermissions("rm"), Allow: !baseDefaultAllow, }, base: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 42, - minor: configs.Wildcard, - }: configs.DevicePermissions("rwm"), + minor: devices.Wildcard, + }: devices.DevicePermissions("rwm"), }, }, expected: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 42, - minor: configs.Wildcard, - }: configs.DevicePermissions("rwm"), + minor: devices.Wildcard, + }: devices.DevicePermissions("rwm"), // To match the kernel, we allow redundant rules. { - node: configs.CharDevice, + node: devices.CharDevice, major: 42, minor: 1337, - }: configs.DevicePermissions("rm"), + }: devices.DevicePermissions("rm"), }, }, }, { name: "RuleAdditionBasicDuplicateNoop", - rule: configs.DeviceRule{ - Type: configs.CharDevice, + rule: devices.DeviceRule{ + Type: devices.CharDevice, Major: 42, Minor: 1337, - Permissions: configs.DevicePermissions("rm"), + Permissions: devices.DevicePermissions("rm"), Allow: !baseDefaultAllow, }, base: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 42, minor: 1337, - }: configs.DevicePermissions("rm"), + }: devices.DevicePermissions("rm"), }, }, expected: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 42, minor: 1337, - }: configs.DevicePermissions("rm"), + }: devices.DevicePermissions("rm"), }, }, }, { name: "RuleAdditionMerge", - rule: configs.DeviceRule{ - Type: configs.BlockDevice, + rule: devices.DeviceRule{ + Type: devices.BlockDevice, Major: 5, Minor: 12, - Permissions: configs.DevicePermissions("rm"), + Permissions: devices.DevicePermissions("rm"), Allow: !baseDefaultAllow, }, base: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 2, minor: 1, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), { - node: configs.BlockDevice, + node: devices.BlockDevice, major: 5, minor: 12, - }: configs.DevicePermissions("rw"), + }: devices.DevicePermissions("rw"), }, }, expected: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 2, minor: 1, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), { - node: configs.BlockDevice, + node: devices.BlockDevice, major: 5, minor: 12, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), }, }, }, { name: "RuleAdditionMergeWildcard", - rule: configs.DeviceRule{ - Type: configs.BlockDevice, + rule: devices.DeviceRule{ + Type: devices.BlockDevice, Major: 5, - Minor: configs.Wildcard, - Permissions: configs.DevicePermissions("rm"), + Minor: devices.Wildcard, + Permissions: devices.DevicePermissions("rm"), Allow: !baseDefaultAllow, }, base: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 2, minor: 1, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), { - node: configs.BlockDevice, + node: devices.BlockDevice, major: 5, - minor: configs.Wildcard, - }: configs.DevicePermissions("rw"), + minor: devices.Wildcard, + }: devices.DevicePermissions("rw"), }, }, expected: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 2, minor: 1, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), { - node: configs.BlockDevice, + node: devices.BlockDevice, major: 5, - minor: configs.Wildcard, - }: configs.DevicePermissions("rwm"), + minor: devices.Wildcard, + }: devices.DevicePermissions("rwm"), }, }, }, { name: "RuleAdditionMergeNoop", - rule: configs.DeviceRule{ - Type: configs.BlockDevice, + rule: devices.DeviceRule{ + Type: devices.BlockDevice, Major: 5, Minor: 12, - Permissions: configs.DevicePermissions("r"), + Permissions: devices.DevicePermissions("r"), Allow: !baseDefaultAllow, }, base: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 2, minor: 1, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), { - node: configs.BlockDevice, + node: devices.BlockDevice, major: 5, minor: 12, - }: configs.DevicePermissions("rw"), + }: devices.DevicePermissions("rw"), }, }, expected: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 2, minor: 1, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), { - node: configs.BlockDevice, + node: devices.BlockDevice, major: 5, minor: 12, - }: configs.DevicePermissions("rw"), + }: devices.DevicePermissions("rw"), }, }, }, // Rule removal logic. { name: "RuleRemovalBasic", - rule: configs.DeviceRule{ - Type: configs.CharDevice, + rule: devices.DeviceRule{ + Type: devices.CharDevice, Major: 42, Minor: 1337, - Permissions: configs.DevicePermissions("rm"), + Permissions: devices.DevicePermissions("rm"), Allow: baseDefaultAllow, }, base: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 42, minor: 1337, - }: configs.DevicePermissions("rm"), + }: devices.DevicePermissions("rm"), { - node: configs.BlockDevice, + node: devices.BlockDevice, major: 1, minor: 5, - }: configs.DevicePermissions("r"), + }: devices.DevicePermissions("r"), }, }, expected: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.BlockDevice, + node: devices.BlockDevice, major: 1, minor: 5, - }: configs.DevicePermissions("r"), + }: devices.DevicePermissions("r"), }, }, }, { name: "RuleRemovalNonexistent", - rule: configs.DeviceRule{ - Type: configs.CharDevice, + rule: devices.DeviceRule{ + Type: devices.CharDevice, Major: 4, Minor: 1, - Permissions: configs.DevicePermissions("rw"), + Permissions: devices.DevicePermissions("rw"), Allow: baseDefaultAllow, }, base: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.BlockDevice, + node: devices.BlockDevice, major: 1, minor: 5, - }: configs.DevicePermissions("r"), + }: devices.DevicePermissions("r"), }, }, expected: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.BlockDevice, + node: devices.BlockDevice, major: 1, minor: 5, - }: configs.DevicePermissions("r"), + }: devices.DevicePermissions("r"), }, }, }, { name: "RuleRemovalFull", - rule: configs.DeviceRule{ - Type: configs.CharDevice, + rule: devices.DeviceRule{ + Type: devices.CharDevice, Major: 42, Minor: 1337, - Permissions: configs.DevicePermissions("rw"), + Permissions: devices.DevicePermissions("rw"), Allow: baseDefaultAllow, }, base: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 42, minor: 1337, - }: configs.DevicePermissions("w"), + }: devices.DevicePermissions("w"), { - node: configs.BlockDevice, + node: devices.BlockDevice, major: 1, minor: 5, - }: configs.DevicePermissions("r"), + }: devices.DevicePermissions("r"), }, }, expected: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.BlockDevice, + node: devices.BlockDevice, major: 1, minor: 5, - }: configs.DevicePermissions("r"), + }: devices.DevicePermissions("r"), }, }, }, { name: "RuleRemovalPartial", - rule: configs.DeviceRule{ - Type: configs.CharDevice, + rule: devices.DeviceRule{ + Type: devices.CharDevice, Major: 42, Minor: 1337, - Permissions: configs.DevicePermissions("r"), + Permissions: devices.DevicePermissions("r"), Allow: baseDefaultAllow, }, base: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 42, minor: 1337, - }: configs.DevicePermissions("rm"), + }: devices.DevicePermissions("rm"), { - node: configs.BlockDevice, + node: devices.BlockDevice, major: 1, minor: 5, - }: configs.DevicePermissions("r"), + }: devices.DevicePermissions("r"), }, }, expected: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 42, minor: 1337, - }: configs.DevicePermissions("m"), + }: devices.DevicePermissions("m"), { - node: configs.BlockDevice, + node: devices.BlockDevice, major: 1, minor: 5, - }: configs.DevicePermissions("r"), + }: devices.DevicePermissions("r"), }, }, }, @@ -677,62 +677,62 @@ func testDeviceEmulatorApply(t *testing.T, baseDefaultAllow bool) { // out" holes in a wildcard rule. { name: "RuleRemovalWildcardPunchoutImpossible", - rule: configs.DeviceRule{ - Type: configs.CharDevice, + rule: devices.DeviceRule{ + Type: devices.CharDevice, Major: 42, Minor: 1337, - Permissions: configs.DevicePermissions("r"), + Permissions: devices.DevicePermissions("r"), Allow: baseDefaultAllow, }, base: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 42, - minor: configs.Wildcard, - }: configs.DevicePermissions("rm"), + minor: devices.Wildcard, + }: devices.DevicePermissions("rm"), { - node: configs.CharDevice, + node: devices.CharDevice, major: 42, minor: 1337, - }: configs.DevicePermissions("r"), + }: devices.DevicePermissions("r"), }, }, expected: nil, }, { name: "RuleRemovalWildcardPunchoutPossible", - rule: configs.DeviceRule{ - Type: configs.CharDevice, + rule: devices.DeviceRule{ + Type: devices.CharDevice, Major: 42, Minor: 1337, - Permissions: configs.DevicePermissions("r"), + Permissions: devices.DevicePermissions("r"), Allow: baseDefaultAllow, }, base: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 42, - minor: configs.Wildcard, - }: configs.DevicePermissions("wm"), + minor: devices.Wildcard, + }: devices.DevicePermissions("wm"), { - node: configs.CharDevice, + node: devices.CharDevice, major: 42, minor: 1337, - }: configs.DevicePermissions("r"), + }: devices.DevicePermissions("r"), }, }, expected: &Emulator{ defaultAllow: baseDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 42, - minor: configs.Wildcard, - }: configs.DevicePermissions("wm"), + minor: devices.Wildcard, + }: devices.DevicePermissions("wm"), }, }, }, @@ -767,7 +767,7 @@ func testDeviceEmulatorTransition(t *testing.T, sourceDefaultAllow bool) { tests := []struct { name string source, target *Emulator - expected []*configs.DeviceRule + expected []*devices.DeviceRule }{ // No-op changes. { @@ -776,20 +776,20 @@ func testDeviceEmulatorTransition(t *testing.T, sourceDefaultAllow bool) { defaultAllow: sourceDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 42, - minor: configs.Wildcard, - }: configs.DevicePermissions("wm"), + minor: devices.Wildcard, + }: devices.DevicePermissions("wm"), }, }, target: &Emulator{ defaultAllow: sourceDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 42, - minor: configs.Wildcard, - }: configs.DevicePermissions("wm"), + minor: devices.Wildcard, + }: devices.DevicePermissions("wm"), }, }, // Identical white-lists produce no extra rules. @@ -802,37 +802,37 @@ func testDeviceEmulatorTransition(t *testing.T, sourceDefaultAllow bool) { defaultAllow: sourceDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 1, minor: 2, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), }, }, target: &Emulator{ defaultAllow: !sourceDefaultAllow, rules: deviceRules{ { - node: configs.BlockDevice, + node: devices.BlockDevice, major: 42, - minor: configs.Wildcard, - }: configs.DevicePermissions("wm"), + minor: devices.Wildcard, + }: devices.DevicePermissions("wm"), }, }, - expected: []*configs.DeviceRule{ + expected: []*devices.DeviceRule{ // Clear-all rule. { - Type: configs.WildcardDevice, - Major: configs.Wildcard, - Minor: configs.Wildcard, - Permissions: configs.DevicePermissions("rwm"), + Type: devices.WildcardDevice, + Major: devices.Wildcard, + Minor: devices.Wildcard, + Permissions: devices.DevicePermissions("rwm"), Allow: !sourceDefaultAllow, }, // The actual rule-set. { - Type: configs.BlockDevice, + Type: devices.BlockDevice, Major: 42, - Minor: configs.Wildcard, - Permissions: configs.DevicePermissions("wm"), + Minor: devices.Wildcard, + Permissions: devices.DevicePermissions("wm"), Allow: sourceDefaultAllow, }, }, @@ -844,33 +844,33 @@ func testDeviceEmulatorTransition(t *testing.T, sourceDefaultAllow bool) { defaultAllow: sourceDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 1, minor: 2, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), }, }, target: &Emulator{ defaultAllow: sourceDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 1, minor: 2, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), { - node: configs.BlockDevice, + node: devices.BlockDevice, major: 42, minor: 1337, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), }, }, - expected: []*configs.DeviceRule{ + expected: []*devices.DeviceRule{ { - Type: configs.BlockDevice, + Type: devices.BlockDevice, Major: 42, Minor: 1337, - Permissions: configs.DevicePermissions("rwm"), + Permissions: devices.DevicePermissions("rwm"), Allow: !sourceDefaultAllow, }, }, @@ -881,33 +881,33 @@ func testDeviceEmulatorTransition(t *testing.T, sourceDefaultAllow bool) { defaultAllow: sourceDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 1, minor: 2, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), { - node: configs.BlockDevice, + node: devices.BlockDevice, major: 42, minor: 1337, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), }, }, target: &Emulator{ defaultAllow: sourceDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 1, minor: 2, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), }, }, - expected: []*configs.DeviceRule{ + expected: []*devices.DeviceRule{ { - Type: configs.BlockDevice, + Type: devices.BlockDevice, Major: 42, Minor: 1337, - Permissions: configs.DevicePermissions("rwm"), + Permissions: devices.DevicePermissions("rwm"), Allow: sourceDefaultAllow, }, }, @@ -918,33 +918,33 @@ func testDeviceEmulatorTransition(t *testing.T, sourceDefaultAllow bool) { defaultAllow: sourceDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 1, minor: 2, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), { - node: configs.BlockDevice, + node: devices.BlockDevice, major: 3, minor: 9, - }: configs.DevicePermissions("rw"), + }: devices.DevicePermissions("rw"), }, }, target: &Emulator{ defaultAllow: sourceDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 1, minor: 2, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), }, }, - expected: []*configs.DeviceRule{ + expected: []*devices.DeviceRule{ { - Type: configs.BlockDevice, + Type: devices.BlockDevice, Major: 3, Minor: 9, - Permissions: configs.DevicePermissions("rw"), + Permissions: devices.DevicePermissions("rw"), Allow: sourceDefaultAllow, }, }, @@ -956,28 +956,28 @@ func testDeviceEmulatorTransition(t *testing.T, sourceDefaultAllow bool) { defaultAllow: sourceDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 1, minor: 2, - }: configs.DevicePermissions("r"), + }: devices.DevicePermissions("r"), }, }, target: &Emulator{ defaultAllow: sourceDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 1, minor: 2, - }: configs.DevicePermissions("rwm"), + }: devices.DevicePermissions("rwm"), }, }, - expected: []*configs.DeviceRule{ + expected: []*devices.DeviceRule{ { - Type: configs.CharDevice, + Type: devices.CharDevice, Major: 1, Minor: 2, - Permissions: configs.DevicePermissions("wm"), + Permissions: devices.DevicePermissions("wm"), Allow: !sourceDefaultAllow, }, }, @@ -988,28 +988,28 @@ func testDeviceEmulatorTransition(t *testing.T, sourceDefaultAllow bool) { defaultAllow: sourceDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 1, minor: 2, - }: configs.DevicePermissions("rw"), + }: devices.DevicePermissions("rw"), }, }, target: &Emulator{ defaultAllow: sourceDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 1, minor: 2, - }: configs.DevicePermissions("w"), + }: devices.DevicePermissions("w"), }, }, - expected: []*configs.DeviceRule{ + expected: []*devices.DeviceRule{ { - Type: configs.CharDevice, + Type: devices.CharDevice, Major: 1, Minor: 2, - Permissions: configs.DevicePermissions("r"), + Permissions: devices.DevicePermissions("r"), Allow: sourceDefaultAllow, }, }, @@ -1020,35 +1020,35 @@ func testDeviceEmulatorTransition(t *testing.T, sourceDefaultAllow bool) { defaultAllow: sourceDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 1, minor: 2, - }: configs.DevicePermissions("rw"), + }: devices.DevicePermissions("rw"), }, }, target: &Emulator{ defaultAllow: sourceDefaultAllow, rules: deviceRules{ { - node: configs.CharDevice, + node: devices.CharDevice, major: 1, minor: 2, - }: configs.DevicePermissions("rm"), + }: devices.DevicePermissions("rm"), }, }, - expected: []*configs.DeviceRule{ + expected: []*devices.DeviceRule{ { - Type: configs.CharDevice, + Type: devices.CharDevice, Major: 1, Minor: 2, - Permissions: configs.DevicePermissions("w"), + Permissions: devices.DevicePermissions("w"), Allow: sourceDefaultAllow, }, { - Type: configs.CharDevice, + Type: devices.CharDevice, Major: 1, Minor: 2, - Permissions: configs.DevicePermissions("m"), + Permissions: devices.DevicePermissions("m"), Allow: !sourceDefaultAllow, }, }, @@ -1063,15 +1063,15 @@ func testDeviceEmulatorTransition(t *testing.T, sourceDefaultAllow bool) { // white-list mode in mind), and then make a full copy of the // target rules. if sourceDefaultAllow && test.source.defaultAllow == test.target.defaultAllow { - test.expected = []*configs.DeviceRule{{ - Type: configs.WildcardDevice, - Major: configs.Wildcard, - Minor: configs.Wildcard, - Permissions: configs.DevicePermissions("rwm"), + test.expected = []*devices.DeviceRule{{ + Type: devices.WildcardDevice, + Major: devices.Wildcard, + Minor: devices.Wildcard, + Permissions: devices.DevicePermissions("rwm"), Allow: test.target.defaultAllow, }} for _, rule := range test.target.rules.orderedEntries() { - test.expected = append(test.expected, &configs.DeviceRule{ + test.expected = append(test.expected, &devices.DeviceRule{ Type: rule.meta.node, Major: rule.meta.major, Minor: rule.meta.minor, diff --git a/libcontainer/cgroups/ebpf/devicefilter/devicefilter.go b/libcontainer/cgroups/ebpf/devicefilter/devicefilter.go index c1681a50c72..44831dabd13 100644 --- a/libcontainer/cgroups/ebpf/devicefilter/devicefilter.go +++ b/libcontainer/cgroups/ebpf/devicefilter/devicefilter.go @@ -11,7 +11,7 @@ import ( "strconv" "github.com/cilium/ebpf/asm" - "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/devices" "github.com/pkg/errors" "golang.org/x/sys/unix" ) @@ -22,7 +22,7 @@ const ( ) // DeviceFilter returns eBPF device filter program and its license string -func DeviceFilter(devices []*configs.DeviceRule) (asm.Instructions, string, error) { +func DeviceFilter(devices []*devices.DeviceRule) (asm.Instructions, string, error) { p := &program{} p.init() for i := len(devices) - 1; i >= 0; i-- { @@ -68,7 +68,7 @@ func (p *program) init() { } // appendDevice needs to be called from the last element of OCI linux.resources.devices to the head element. -func (p *program) appendDevice(dev *configs.DeviceRule) error { +func (p *program) appendDevice(dev *devices.DeviceRule) error { if p.blockID < 0 { return errors.New("the program is finalized") } diff --git a/libcontainer/cgroups/ebpf/devicefilter/devicefilter_test.go b/libcontainer/cgroups/ebpf/devicefilter/devicefilter_test.go index d81e90f80c0..2f21cf1597d 100644 --- a/libcontainer/cgroups/ebpf/devicefilter/devicefilter_test.go +++ b/libcontainer/cgroups/ebpf/devicefilter/devicefilter_test.go @@ -4,7 +4,7 @@ import ( "strings" "testing" - "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/devices" "github.com/opencontainers/runc/libcontainer/specconv" ) @@ -20,7 +20,7 @@ func hash(s, comm string) string { return strings.Join(res, "\n") } -func testDeviceFilter(t testing.TB, devices []*configs.DeviceRule, expectedStr string) { +func testDeviceFilter(t testing.TB, devices []*devices.DeviceRule, expectedStr string) { insts, _, err := DeviceFilter(devices) if err != nil { t.Fatalf("%s: %v (devices: %+v)", t.Name(), err, devices) @@ -137,7 +137,7 @@ block-11: 62: Mov32Imm dst: r0 imm: 0 63: Exit ` - var devices []*configs.DeviceRule + var devices []*devices.DeviceRule for _, device := range specconv.AllowedDevices { devices = append(devices, &device.DeviceRule) } @@ -145,7 +145,7 @@ block-11: } func TestDeviceFilter_Privileged(t *testing.T) { - devices := []*configs.DeviceRule{ + devices := []*devices.DeviceRule{ { Type: 'a', Major: -1, @@ -172,7 +172,7 @@ block-0: } func TestDeviceFilter_PrivilegedExceptSingleDevice(t *testing.T) { - devices := []*configs.DeviceRule{ + devices := []*devices.DeviceRule{ { Type: 'a', Major: -1, @@ -212,7 +212,7 @@ block-1: } func TestDeviceFilter_Weird(t *testing.T) { - devices := []*configs.DeviceRule{ + devices := []*devices.DeviceRule{ { Type: 'b', Major: 8, diff --git a/libcontainer/cgroups/fs/devices.go b/libcontainer/cgroups/fs/devices.go index fd8f00d5bfd..91a70cf5d0b 100644 --- a/libcontainer/cgroups/fs/devices.go +++ b/libcontainer/cgroups/fs/devices.go @@ -8,9 +8,10 @@ import ( "reflect" "github.com/opencontainers/runc/libcontainer/cgroups" - "github.com/opencontainers/runc/libcontainer/cgroups/devices" + cgroupdevices "github.com/opencontainers/runc/libcontainer/cgroups/devices" "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/devices" "github.com/opencontainers/runc/libcontainer/system" ) @@ -34,17 +35,17 @@ func (s *DevicesGroup) Apply(path string, d *cgroupData) error { return join(path, d.pid) } -func loadEmulator(path string) (*devices.Emulator, error) { +func loadEmulator(path string) (*cgroupdevices.Emulator, error) { list, err := fscommon.ReadFile(path, "devices.list") if err != nil { return nil, err } - return devices.EmulatorFromList(bytes.NewBufferString(list)) + return cgroupdevices.EmulatorFromList(bytes.NewBufferString(list)) } -func buildEmulator(rules []*configs.DeviceRule) (*devices.Emulator, error) { +func buildEmulator(rules []*devices.DeviceRule) (*cgroupdevices.Emulator, error) { // This defaults to a white-list -- which is what we want! - emu := &devices.Emulator{} + emu := &cgroupdevices.Emulator{} for _, rule := range rules { if err := emu.Apply(*rule); err != nil { return nil, err diff --git a/libcontainer/cgroups/fs/devices_test.go b/libcontainer/cgroups/fs/devices_test.go index da7ccb01ecc..43405c96d12 100644 --- a/libcontainer/cgroups/fs/devices_test.go +++ b/libcontainer/cgroups/fs/devices_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" - "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/devices" ) func TestDevicesSetAllow(t *testing.T) { @@ -19,18 +19,18 @@ func TestDevicesSetAllow(t *testing.T) { "devices.list": "a *:* rwm", }) - helper.CgroupData.config.Resources.Devices = []*configs.DeviceRule{ + helper.CgroupData.config.Resources.Devices = []*devices.DeviceRule{ { - Type: configs.CharDevice, + Type: devices.CharDevice, Major: 1, Minor: 5, - Permissions: configs.DevicePermissions("rwm"), + Permissions: devices.DevicePermissions("rwm"), Allow: true, }, } - devices := &DevicesGroup{testingSkipFinalCheck: true} - if err := devices.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { + d := &DevicesGroup{testingSkipFinalCheck: true} + if err := d.Set(helper.CgroupPath, helper.CgroupData.config); err != nil { t.Fatal(err) } diff --git a/libcontainer/cgroups/fs2/devices.go b/libcontainer/cgroups/fs2/devices.go index e06617f1809..2bcb5e276db 100644 --- a/libcontainer/cgroups/fs2/devices.go +++ b/libcontainer/cgroups/fs2/devices.go @@ -6,11 +6,12 @@ import ( "github.com/opencontainers/runc/libcontainer/cgroups/ebpf" "github.com/opencontainers/runc/libcontainer/cgroups/ebpf/devicefilter" "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/devices" "github.com/pkg/errors" "golang.org/x/sys/unix" ) -func isRWM(perms configs.DevicePermissions) bool { +func isRWM(perms devices.DevicePermissions) bool { var r, w, m bool for _, perm := range perms { switch perm { diff --git a/libcontainer/cgroups/systemd/common.go b/libcontainer/cgroups/systemd/common.go index 2207285626a..882064718cf 100644 --- a/libcontainer/cgroups/systemd/common.go +++ b/libcontainer/cgroups/systemd/common.go @@ -13,8 +13,9 @@ import ( systemdDbus "github.com/coreos/go-systemd/v22/dbus" dbus "github.com/godbus/dbus/v5" - "github.com/opencontainers/runc/libcontainer/cgroups/devices" + cgroupdevices "github.com/opencontainers/runc/libcontainer/cgroups/devices" "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/devices" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -88,11 +89,11 @@ func ExpandSlice(slice string) (string, error) { return path, nil } -func groupPrefix(ruleType configs.DeviceType) (string, error) { +func groupPrefix(ruleType devices.DeviceType) (string, error) { switch ruleType { - case configs.BlockDevice: + case devices.BlockDevice: return "block-", nil - case configs.CharDevice: + case devices.CharDevice: return "char-", nil default: return "", errors.Errorf("device type %v has no group prefix", ruleType) @@ -103,7 +104,7 @@ func groupPrefix(ruleType configs.DeviceType) (string, error) { // /proc/devices) with the type prefixed as required for DeviceAllow, for a // given (type, major) combination. If more than one device group exists, an // arbitrary one is chosen. -func findDeviceGroup(ruleType configs.DeviceType, ruleMajor int64) (string, error) { +func findDeviceGroup(ruleType devices.DeviceType, ruleMajor int64) (string, error) { fh, err := os.Open("/proc/devices") if err != nil { return "", err @@ -116,7 +117,7 @@ func findDeviceGroup(ruleType configs.DeviceType, ruleMajor int64) (string, erro } scanner := bufio.NewScanner(fh) - var currentType configs.DeviceType + var currentType devices.DeviceType for scanner.Scan() { // We need to strip spaces because the first number is column-aligned. line := strings.TrimSpace(scanner.Text()) @@ -124,10 +125,10 @@ func findDeviceGroup(ruleType configs.DeviceType, ruleMajor int64) (string, erro // Handle the "header" lines. switch line { case "Block devices:": - currentType = configs.BlockDevice + currentType = devices.BlockDevice continue case "Character devices:": - currentType = configs.CharDevice + currentType = devices.CharDevice continue case "": continue @@ -163,7 +164,7 @@ func findDeviceGroup(ruleType configs.DeviceType, ruleMajor int64) (string, erro // generateDeviceProperties takes the configured device rules and generates a // corresponding set of systemd properties to configure the devices correctly. -func generateDeviceProperties(rules []*configs.DeviceRule) ([]systemdDbus.Property, error) { +func generateDeviceProperties(rules []*devices.DeviceRule) ([]systemdDbus.Property, error) { // DeviceAllow is the type "a(ss)" which means we need a temporary struct // to represent it in Go. type deviceAllowEntry struct { @@ -179,7 +180,7 @@ func generateDeviceProperties(rules []*configs.DeviceRule) ([]systemdDbus.Proper } // Figure out the set of rules. - configEmu := &devices.Emulator{} + configEmu := &cgroupdevices.Emulator{} for _, rule := range rules { if err := configEmu.Apply(*rule); err != nil { return nil, errors.Wrap(err, "apply rule for systemd") @@ -206,7 +207,7 @@ func generateDeviceProperties(rules []*configs.DeviceRule) ([]systemdDbus.Proper // Now generate the set of rules we actually need to apply. Unlike the // normal devices cgroup, in "strict" mode systemd defaults to a deny-all // whitelist which is the default for devices.Emulator. - baseEmu := &devices.Emulator{} + baseEmu := &cgroupdevices.Emulator{} finalRules, err := baseEmu.Transition(configEmu) if err != nil { return nil, errors.Wrap(err, "get simplified rules for systemd") @@ -218,7 +219,7 @@ func generateDeviceProperties(rules []*configs.DeviceRule) ([]systemdDbus.Proper return nil, errors.Errorf("[internal error] cannot add deny rule to systemd DeviceAllow list: %v", *rule) } switch rule.Type { - case configs.BlockDevice, configs.CharDevice: + case devices.BlockDevice, devices.CharDevice: default: // Should never happen. return nil, errors.Errorf("invalid device type for DeviceAllow: %v", rule.Type) @@ -250,9 +251,9 @@ func generateDeviceProperties(rules []*configs.DeviceRule) ([]systemdDbus.Proper // so we'll give a warning in that case (note that the fallback code // will insert any rules systemd couldn't handle). What amazing fun. - if rule.Major == configs.Wildcard { + if rule.Major == devices.Wildcard { // "_ *:n _" rules aren't supported by systemd. - if rule.Minor != configs.Wildcard { + if rule.Minor != devices.Wildcard { logrus.Warnf("systemd doesn't support '*:n' device rules -- temporarily ignoring rule: %v", *rule) continue } @@ -263,7 +264,7 @@ func generateDeviceProperties(rules []*configs.DeviceRule) ([]systemdDbus.Proper return nil, err } entry.Path = prefix + "*" - } else if rule.Minor == configs.Wildcard { + } else if rule.Minor == devices.Wildcard { // "_ n:* _" rules require a device group from /proc/devices. group, err := findDeviceGroup(rule.Type, rule.Major) if err != nil { @@ -278,9 +279,9 @@ func generateDeviceProperties(rules []*configs.DeviceRule) ([]systemdDbus.Proper } else { // "_ n:m _" rules are just a path in /dev/{block,char}/. switch rule.Type { - case configs.BlockDevice: + case devices.BlockDevice: entry.Path = fmt.Sprintf("/dev/block/%d:%d", rule.Major, rule.Minor) - case configs.CharDevice: + case devices.CharDevice: entry.Path = fmt.Sprintf("/dev/char/%d:%d", rule.Major, rule.Minor) } } diff --git a/libcontainer/configs/cgroup_linux.go b/libcontainer/configs/cgroup_linux.go index dcc29c61944..592595dd9fa 100644 --- a/libcontainer/configs/cgroup_linux.go +++ b/libcontainer/configs/cgroup_linux.go @@ -2,6 +2,7 @@ package configs import ( systemdDbus "github.com/coreos/go-systemd/v22/dbus" + "github.com/opencontainers/runc/libcontainer/devices" ) type FreezerState string @@ -42,7 +43,7 @@ type Cgroup struct { type Resources struct { // Devices is the set of access rules for devices in the container. - Devices []*DeviceRule `json:"devices"` + Devices []*devices.DeviceRule `json:"devices"` // Memory limit (in bytes) Memory int64 `json:"memory"` diff --git a/libcontainer/configs/config.go b/libcontainer/configs/config.go index 55ca65f22c5..e1cd1626565 100644 --- a/libcontainer/configs/config.go +++ b/libcontainer/configs/config.go @@ -7,6 +7,7 @@ import ( "os/exec" "time" + "github.com/opencontainers/runc/libcontainer/devices" "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -107,7 +108,7 @@ type Config struct { Mounts []*Mount `json:"mounts"` // The device nodes that should be automatically created within the container upon container start. Note, make sure that the node is marked as allowed in the cgroup as well! - Devices []*Device `json:"devices"` + Devices []*devices.Device `json:"devices"` MountLabel string `json:"mount_label"` diff --git a/libcontainer/configs/devices.go b/libcontainer/configs/devices.go new file mode 100644 index 00000000000..ac44ab5df08 --- /dev/null +++ b/libcontainer/configs/devices.go @@ -0,0 +1,17 @@ +package configs + +import "github.com/opencontainers/runc/libcontainer/devices" + +type ( + // Deprecated: use libcontainer/devices.Device + Device = devices.Device + + // Deprecated: use libcontainer/devices.DeviceRule + DeviceRule = devices.DeviceRule + + // Deprecated: use libcontainer/devices.DeviceType + DeviceType = devices.DeviceType + + // Deprecated: use libcontainer/devices.DevicePermissions + DevicePermissions = devices.DevicePermissions +) diff --git a/libcontainer/configs/device.go b/libcontainer/devices/device.go similarity index 99% rename from libcontainer/configs/device.go rename to libcontainer/devices/device.go index 632bf6ac49c..2fb33b00d47 100644 --- a/libcontainer/configs/device.go +++ b/libcontainer/devices/device.go @@ -1,4 +1,4 @@ -package configs +package devices import ( "fmt" diff --git a/libcontainer/configs/device_unix.go b/libcontainer/devices/device_unix.go similarity index 94% rename from libcontainer/configs/device_unix.go rename to libcontainer/devices/device_unix.go index 650c46848a1..3bc4e179c9c 100644 --- a/libcontainer/configs/device_unix.go +++ b/libcontainer/devices/device_unix.go @@ -1,6 +1,6 @@ // +build !windows -package configs +package devices import ( "errors" diff --git a/libcontainer/configs/device_windows.go b/libcontainer/devices/device_windows.go similarity index 80% rename from libcontainer/configs/device_windows.go rename to libcontainer/devices/device_windows.go index 729289393fe..421f66c0e4b 100644 --- a/libcontainer/configs/device_windows.go +++ b/libcontainer/devices/device_windows.go @@ -1,4 +1,4 @@ -package configs +package devices func (d *DeviceRule) Mkdev() (uint64, error) { return 0, nil diff --git a/libcontainer/devices/devices.go b/libcontainer/devices/devices.go index 79f89c2d775..59a3a4f8be0 100644 --- a/libcontainer/devices/devices.go +++ b/libcontainer/devices/devices.go @@ -6,7 +6,6 @@ import ( "os" "path/filepath" - "github.com/opencontainers/runc/libcontainer/configs" "golang.org/x/sys/unix" ) @@ -23,7 +22,7 @@ var ( // Given the path to a device and its cgroup_permissions(which cannot be easily queried) look up the // information about a linux device and return that information as a Device struct. -func DeviceFromPath(path, permissions string) (*configs.Device, error) { +func DeviceFromPath(path, permissions string) (*Device, error) { var stat unix.Stat_t err := unixLstat(path, &stat) if err != nil { @@ -31,7 +30,7 @@ func DeviceFromPath(path, permissions string) (*configs.Device, error) { } var ( - devType configs.DeviceType + devType DeviceType mode = stat.Mode devNumber = uint64(stat.Rdev) major = unix.Major(devNumber) @@ -39,20 +38,20 @@ func DeviceFromPath(path, permissions string) (*configs.Device, error) { ) switch mode & unix.S_IFMT { case unix.S_IFBLK: - devType = configs.BlockDevice + devType = BlockDevice case unix.S_IFCHR: - devType = configs.CharDevice + devType = CharDevice case unix.S_IFIFO: - devType = configs.FifoDevice + devType = FifoDevice default: return nil, ErrNotADevice } - return &configs.Device{ - DeviceRule: configs.DeviceRule{ + return &Device{ + DeviceRule: DeviceRule{ Type: devType, Major: int64(major), Minor: int64(minor), - Permissions: configs.DevicePermissions(permissions), + Permissions: DevicePermissions(permissions), }, Path: path, FileMode: os.FileMode(mode), @@ -62,18 +61,18 @@ func DeviceFromPath(path, permissions string) (*configs.Device, error) { } // HostDevices returns all devices that can be found under /dev directory. -func HostDevices() ([]*configs.Device, error) { +func HostDevices() ([]*Device, error) { return GetDevices("/dev") } // GetDevices recursively traverses a directory specified by path // and returns all devices found there. -func GetDevices(path string) ([]*configs.Device, error) { +func GetDevices(path string) ([]*Device, error) { files, err := ioutilReadDir(path) if err != nil { return nil, err } - var out []*configs.Device + var out []*Device for _, f := range files { switch { case f.IsDir(): @@ -104,7 +103,7 @@ func GetDevices(path string) ([]*configs.Device, error) { } return nil, err } - if device.Type == configs.FifoDevice { + if device.Type == FifoDevice { continue } out = append(out, device) diff --git a/libcontainer/devices/devices_test.go b/libcontainer/devices/devices_test.go index 887b6ff01f7..02ebb4b6ece 100644 --- a/libcontainer/devices/devices_test.go +++ b/libcontainer/devices/devices_test.go @@ -6,7 +6,6 @@ import ( "os" "testing" - "github.com/opencontainers/runc/libcontainer/configs" "golang.org/x/sys/unix" ) @@ -86,11 +85,11 @@ func TestHostDevicesAllValid(t *testing.T) { // Devices should only have file modes that correspond to their type. var expectedType os.FileMode switch device.Type { - case configs.BlockDevice: + case BlockDevice: expectedType = unix.S_IFBLK - case configs.CharDevice: + case CharDevice: expectedType = unix.S_IFCHR - case configs.FifoDevice: + case FifoDevice: t.Logf("fifo devices shouldn't show up from HostDevices") fallthrough default: diff --git a/libcontainer/integration/template_test.go b/libcontainer/integration/template_test.go index 51a6b53619c..718e45c6374 100644 --- a/libcontainer/integration/template_test.go +++ b/libcontainer/integration/template_test.go @@ -5,8 +5,8 @@ import ( "strconv" "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/devices" "github.com/opencontainers/runc/libcontainer/specconv" - "golang.org/x/sys/unix" ) @@ -30,7 +30,7 @@ type tParam struct { // it uses a network strategy of just setting a loopback interface // and the default setup for devices func newTemplateConfig(p *tParam) *configs.Config { - var allowedDevices []*configs.DeviceRule + var allowedDevices []*devices.DeviceRule for _, device := range specconv.AllowedDevices { allowedDevices = append(allowedDevices, &device.DeviceRule) } diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go index 7e03afc9dc5..ad856bff999 100644 --- a/libcontainer/rootfs_linux.go +++ b/libcontainer/rootfs_linux.go @@ -18,12 +18,12 @@ import ( "github.com/mrunalp/fileutils" "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/devices" "github.com/opencontainers/runc/libcontainer/system" "github.com/opencontainers/runc/libcontainer/utils" libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils" "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/selinux/go-selinux/label" - "golang.org/x/sys/unix" ) @@ -614,7 +614,7 @@ func createDevices(config *configs.Config) error { return nil } -func bindMountDeviceNode(dest string, node *configs.Device) error { +func bindMountDeviceNode(dest string, node *devices.Device) error { f, err := os.Create(dest) if err != nil && !os.IsExist(err) { return err @@ -626,7 +626,7 @@ func bindMountDeviceNode(dest string, node *configs.Device) error { } // Creates the device node in the rootfs of the container. -func createDeviceNode(rootfs string, node *configs.Device, bind bool) error { +func createDeviceNode(rootfs string, node *devices.Device, bind bool) error { if node.Path == "" { // The node only exists for cgroup reasons, ignore it here. return nil @@ -649,14 +649,14 @@ func createDeviceNode(rootfs string, node *configs.Device, bind bool) error { return nil } -func mknodDevice(dest string, node *configs.Device) error { +func mknodDevice(dest string, node *devices.Device) error { fileMode := node.FileMode switch node.Type { - case configs.BlockDevice: + case devices.BlockDevice: fileMode |= unix.S_IFBLK - case configs.CharDevice: + case devices.CharDevice: fileMode |= unix.S_IFCHR - case configs.FifoDevice: + case devices.FifoDevice: fileMode |= unix.S_IFIFO default: return fmt.Errorf("%c is not a valid device type for device %s", node.Type, node.Path) diff --git a/libcontainer/specconv/spec_linux.go b/libcontainer/specconv/spec_linux.go index 97c8fb8bcd1..81d19aacba2 100644 --- a/libcontainer/specconv/spec_linux.go +++ b/libcontainer/specconv/spec_linux.go @@ -17,6 +17,7 @@ import ( dbus "github.com/godbus/dbus/v5" "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/configs" + "github.com/opencontainers/runc/libcontainer/devices" "github.com/opencontainers/runc/libcontainer/seccomp" libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils" "github.com/opencontainers/runtime-spec/specs-go" @@ -61,22 +62,22 @@ var mountPropagationMapping = map[string]int{ // // ... unfortunately I'm too scared to change this now because who knows how // many people depend on this (incorrect and arguably insecure) behaviour. -var AllowedDevices = []*configs.Device{ +var AllowedDevices = []*devices.Device{ // allow mknod for any device { - DeviceRule: configs.DeviceRule{ - Type: configs.CharDevice, - Major: configs.Wildcard, - Minor: configs.Wildcard, + DeviceRule: devices.DeviceRule{ + Type: devices.CharDevice, + Major: devices.Wildcard, + Minor: devices.Wildcard, Permissions: "m", Allow: true, }, }, { - DeviceRule: configs.DeviceRule{ - Type: configs.BlockDevice, - Major: configs.Wildcard, - Minor: configs.Wildcard, + DeviceRule: devices.DeviceRule{ + Type: devices.BlockDevice, + Major: devices.Wildcard, + Minor: devices.Wildcard, Permissions: "m", Allow: true, }, @@ -86,8 +87,8 @@ var AllowedDevices = []*configs.Device{ FileMode: 0666, Uid: 0, Gid: 0, - DeviceRule: configs.DeviceRule{ - Type: configs.CharDevice, + DeviceRule: devices.DeviceRule{ + Type: devices.CharDevice, Major: 1, Minor: 3, Permissions: "rwm", @@ -99,8 +100,8 @@ var AllowedDevices = []*configs.Device{ FileMode: 0666, Uid: 0, Gid: 0, - DeviceRule: configs.DeviceRule{ - Type: configs.CharDevice, + DeviceRule: devices.DeviceRule{ + Type: devices.CharDevice, Major: 1, Minor: 8, Permissions: "rwm", @@ -112,8 +113,8 @@ var AllowedDevices = []*configs.Device{ FileMode: 0666, Uid: 0, Gid: 0, - DeviceRule: configs.DeviceRule{ - Type: configs.CharDevice, + DeviceRule: devices.DeviceRule{ + Type: devices.CharDevice, Major: 1, Minor: 7, Permissions: "rwm", @@ -125,8 +126,8 @@ var AllowedDevices = []*configs.Device{ FileMode: 0666, Uid: 0, Gid: 0, - DeviceRule: configs.DeviceRule{ - Type: configs.CharDevice, + DeviceRule: devices.DeviceRule{ + Type: devices.CharDevice, Major: 5, Minor: 0, Permissions: "rwm", @@ -138,8 +139,8 @@ var AllowedDevices = []*configs.Device{ FileMode: 0666, Uid: 0, Gid: 0, - DeviceRule: configs.DeviceRule{ - Type: configs.CharDevice, + DeviceRule: devices.DeviceRule{ + Type: devices.CharDevice, Major: 1, Minor: 5, Permissions: "rwm", @@ -151,8 +152,8 @@ var AllowedDevices = []*configs.Device{ FileMode: 0666, Uid: 0, Gid: 0, - DeviceRule: configs.DeviceRule{ - Type: configs.CharDevice, + DeviceRule: devices.DeviceRule{ + Type: devices.CharDevice, Major: 1, Minor: 9, Permissions: "rwm", @@ -161,17 +162,17 @@ var AllowedDevices = []*configs.Device{ }, // /dev/pts/ - pts namespaces are "coming soon" { - DeviceRule: configs.DeviceRule{ - Type: configs.CharDevice, + DeviceRule: devices.DeviceRule{ + Type: devices.CharDevice, Major: 136, - Minor: configs.Wildcard, + Minor: devices.Wildcard, Permissions: "rwm", Allow: true, }, }, { - DeviceRule: configs.DeviceRule{ - Type: configs.CharDevice, + DeviceRule: devices.DeviceRule{ + Type: devices.CharDevice, Major: 5, Minor: 2, Permissions: "rwm", @@ -180,8 +181,8 @@ var AllowedDevices = []*configs.Device{ }, // tuntap { - DeviceRule: configs.DeviceRule{ - Type: configs.CharDevice, + DeviceRule: devices.DeviceRule{ + Type: devices.CharDevice, Major: 10, Minor: 200, Permissions: "rwm", @@ -413,7 +414,7 @@ func initSystemdProps(spec *specs.Spec) ([]systemdDbus.Property, error) { return sp, nil } -func CreateCgroupConfig(opts *CreateOpts, defaultDevs []*configs.Device) (*configs.Cgroup, error) { +func CreateCgroupConfig(opts *CreateOpts, defaultDevs []*devices.Device) (*configs.Cgroup, error) { var ( myCgroupPath string @@ -491,11 +492,11 @@ func CreateCgroupConfig(opts *CreateOpts, defaultDevs []*configs.Device) (*confi if err != nil { return nil, err } - c.Resources.Devices = append(c.Resources.Devices, &configs.DeviceRule{ + c.Resources.Devices = append(c.Resources.Devices, &devices.DeviceRule{ Type: dt, Major: major, Minor: minor, - Permissions: configs.DevicePermissions(d.Access), + Permissions: devices.DevicePermissions(d.Access), Allow: d.Allow, }) } @@ -634,36 +635,36 @@ func CreateCgroupConfig(opts *CreateOpts, defaultDevs []*configs.Device) (*confi return c, nil } -func stringToCgroupDeviceRune(s string) (configs.DeviceType, error) { +func stringToCgroupDeviceRune(s string) (devices.DeviceType, error) { switch s { case "a": - return configs.WildcardDevice, nil + return devices.WildcardDevice, nil case "b": - return configs.BlockDevice, nil + return devices.BlockDevice, nil case "c": - return configs.CharDevice, nil + return devices.CharDevice, nil default: return 0, fmt.Errorf("invalid cgroup device type %q", s) } } -func stringToDeviceRune(s string) (configs.DeviceType, error) { +func stringToDeviceRune(s string) (devices.DeviceType, error) { switch s { case "p": - return configs.FifoDevice, nil + return devices.FifoDevice, nil case "u", "c": - return configs.CharDevice, nil + return devices.CharDevice, nil case "b": - return configs.BlockDevice, nil + return devices.BlockDevice, nil default: return 0, fmt.Errorf("invalid device type %q", s) } } -func createDevices(spec *specs.Spec, config *configs.Config) ([]*configs.Device, error) { +func createDevices(spec *specs.Spec, config *configs.Config) ([]*devices.Device, error) { // If a spec device is redundant with a default device, remove that default // device (the spec one takes priority). - dedupedAllowDevs := []*configs.Device{} + dedupedAllowDevs := []*devices.Device{} next: for _, ad := range AllowedDevices { @@ -699,8 +700,8 @@ next: if d.FileMode != nil { filemode = *d.FileMode } - device := &configs.Device{ - DeviceRule: configs.DeviceRule{ + device := &devices.Device{ + DeviceRule: devices.DeviceRule{ Type: dt, Major: d.Major, Minor: d.Minor, diff --git a/libcontainer/specconv/spec_linux_test.go b/libcontainer/specconv/spec_linux_test.go index 52954399e7a..a49db6cc59c 100644 --- a/libcontainer/specconv/spec_linux_test.go +++ b/libcontainer/specconv/spec_linux_test.go @@ -7,12 +7,12 @@ import ( "strings" "testing" - "golang.org/x/sys/unix" - dbus "github.com/godbus/dbus/v5" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/configs/validate" + "github.com/opencontainers/runc/libcontainer/devices" "github.com/opencontainers/runtime-spec/specs-go" + "golang.org/x/sys/unix" ) func TestCreateCommandHookTimeout(t *testing.T) { @@ -722,13 +722,13 @@ func TestCreateDevices(t *testing.T) { // Verify that createDevices() deduplicated the /dev/tty entry in the config for _, configDev := range conf.Devices { if configDev.Path == "/dev/tty" { - wantDev := &configs.Device{ + wantDev := &devices.Device{ Path: "/dev/tty", FileMode: 0666, Uid: 1000, Gid: 1000, - DeviceRule: configs.DeviceRule{ - Type: configs.CharDevice, + DeviceRule: devices.DeviceRule{ + Type: devices.CharDevice, Major: 5, Minor: 0, },