github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/libcontainer/cgroups/devices/v2.go (about) 1 package devices 2 3 import ( 4 "fmt" 5 6 "golang.org/x/sys/unix" 7 8 "github.com/opencontainers/runc/libcontainer/configs" 9 "github.com/opencontainers/runc/libcontainer/devices" 10 "github.com/opencontainers/runc/libcontainer/userns" 11 ) 12 13 func isRWM(perms devices.Permissions) bool { 14 var r, w, m bool 15 for _, perm := range perms { 16 switch perm { 17 case 'r': 18 r = true 19 case 'w': 20 w = true 21 case 'm': 22 m = true 23 } 24 } 25 return r && w && m 26 } 27 28 // This is similar to the logic applied in crun for handling errors from bpf(2) 29 // <https://github.com/containers/crun/blob/0.17/src/libcrun/cgroup.c#L2438-L2470>. 30 func canSkipEBPFError(r *configs.Resources) bool { 31 // If we're running in a user namespace we can ignore eBPF rules because we 32 // usually cannot use bpf(2), as well as rootless containers usually don't 33 // have the necessary privileges to mknod(2) device inodes or access 34 // host-level instances (though ideally we would be blocking device access 35 // for rootless containers anyway). 36 if userns.RunningInUserNS() { 37 return true 38 } 39 40 // We cannot ignore an eBPF load error if any rule if is a block rule or it 41 // doesn't permit all access modes. 42 // 43 // NOTE: This will sometimes trigger in cases where access modes are split 44 // between different rules but to handle this correctly would require 45 // using ".../libcontainer/cgroup/devices".Emulator. 46 for _, dev := range r.Devices { 47 if !dev.Allow || !isRWM(dev.Permissions) { 48 return false 49 } 50 } 51 return true 52 } 53 54 func setV2(dirPath string, r *configs.Resources) error { 55 if r.SkipDevices { 56 return nil 57 } 58 insts, license, err := deviceFilter(r.Devices) 59 if err != nil { 60 return err 61 } 62 dirFD, err := unix.Open(dirPath, unix.O_DIRECTORY|unix.O_RDONLY, 0o600) 63 if err != nil { 64 return fmt.Errorf("cannot get dir FD for %s", dirPath) 65 } 66 defer unix.Close(dirFD) 67 if _, err := loadAttachCgroupDeviceFilter(insts, license, dirFD); err != nil { 68 if !canSkipEBPFError(r) { 69 return err 70 } 71 } 72 return nil 73 }