github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/libcontainer/cgroups/devices/v1.go (about) 1 package devices 2 3 import ( 4 "bytes" 5 "errors" 6 "reflect" 7 8 "github.com/opencontainers/runc/libcontainer/cgroups" 9 "github.com/opencontainers/runc/libcontainer/configs" 10 "github.com/opencontainers/runc/libcontainer/devices" 11 "github.com/opencontainers/runc/libcontainer/userns" 12 ) 13 14 var testingSkipFinalCheck bool 15 16 func setV1(path string, r *configs.Resources) error { 17 if userns.RunningInUserNS() || r.SkipDevices { 18 return nil 19 } 20 // Generate two emulators, one for the current state of the cgroup and one 21 // for the requested state by the user. 22 current, err := loadEmulator(path) 23 if err != nil { 24 return err 25 } 26 target, err := buildEmulator(r.Devices) 27 if err != nil { 28 return err 29 } 30 31 // Compute the minimal set of transition rules needed to achieve the 32 // requested state. 33 transitionRules, err := current.Transition(target) 34 if err != nil { 35 return err 36 } 37 for _, rule := range transitionRules { 38 file := "devices.deny" 39 if rule.Allow { 40 file = "devices.allow" 41 } 42 if err := cgroups.WriteFile(path, file, rule.CgroupString()); err != nil { 43 return err 44 } 45 } 46 47 // Final safety check -- ensure that the resulting state is what was 48 // requested. This is only really correct for white-lists, but for 49 // black-lists we can at least check that the cgroup is in the right mode. 50 // 51 // This safety-check is skipped for the unit tests because we cannot 52 // currently mock devices.list correctly. 53 if !testingSkipFinalCheck { 54 currentAfter, err := loadEmulator(path) 55 if err != nil { 56 return err 57 } 58 if !target.IsBlacklist() && !reflect.DeepEqual(currentAfter, target) { 59 return errors.New("resulting devices cgroup doesn't precisely match target") 60 } else if target.IsBlacklist() != currentAfter.IsBlacklist() { 61 return errors.New("resulting devices cgroup doesn't match target mode") 62 } 63 } 64 return nil 65 } 66 67 func loadEmulator(path string) (*emulator, error) { 68 list, err := cgroups.ReadFile(path, "devices.list") 69 if err != nil { 70 return nil, err 71 } 72 return emulatorFromList(bytes.NewBufferString(list)) 73 } 74 75 func buildEmulator(rules []*devices.Rule) (*emulator, error) { 76 // This defaults to a white-list -- which is what we want! 77 emu := &emulator{} 78 for _, rule := range rules { 79 if err := emu.Apply(*rule); err != nil { 80 return nil, err 81 } 82 } 83 return emu, nil 84 }