devices.go 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. // +build linux
  2. package fs2
  3. import (
  4. "github.com/opencontainers/runc/libcontainer/cgroups/ebpf"
  5. "github.com/opencontainers/runc/libcontainer/cgroups/ebpf/devicefilter"
  6. "github.com/opencontainers/runc/libcontainer/configs"
  7. "github.com/pkg/errors"
  8. "golang.org/x/sys/unix"
  9. )
  10. func isRWM(cgroupPermissions string) bool {
  11. r := false
  12. w := false
  13. m := false
  14. for _, rn := range cgroupPermissions {
  15. switch rn {
  16. case 'r':
  17. r = true
  18. case 'w':
  19. w = true
  20. case 'm':
  21. m = true
  22. }
  23. }
  24. return r && w && m
  25. }
  26. // the logic is from crun
  27. // https://github.com/containers/crun/blob/0.10.2/src/libcrun/cgroup.c#L1644-L1652
  28. func canSkipEBPFError(cgroup *configs.Cgroup) bool {
  29. for _, dev := range cgroup.Resources.Devices {
  30. if dev.Allow || !isRWM(dev.Permissions) {
  31. return false
  32. }
  33. }
  34. return true
  35. }
  36. func setDevices(dirPath string, cgroup *configs.Cgroup) error {
  37. devices := cgroup.Devices
  38. if allowAllDevices := cgroup.Resources.AllowAllDevices; allowAllDevices != nil {
  39. // never set by OCI specconv, but *allowAllDevices=false is still used by the integration test
  40. if *allowAllDevices == true {
  41. return errors.New("libcontainer AllowAllDevices is not supported, use Devices")
  42. }
  43. for _, ad := range cgroup.Resources.AllowedDevices {
  44. d := *ad
  45. d.Allow = true
  46. devices = append(devices, &d)
  47. }
  48. }
  49. if len(cgroup.Resources.DeniedDevices) != 0 {
  50. // never set by OCI specconv
  51. return errors.New("libcontainer DeniedDevices is not supported, use Devices")
  52. }
  53. insts, license, err := devicefilter.DeviceFilter(devices)
  54. if err != nil {
  55. return err
  56. }
  57. dirFD, err := unix.Open(dirPath, unix.O_DIRECTORY|unix.O_RDONLY, 0600)
  58. if err != nil {
  59. return errors.Errorf("cannot get dir FD for %s", dirPath)
  60. }
  61. defer unix.Close(dirFD)
  62. if _, err := ebpf.LoadAttachCgroupDeviceFilter(insts, license, dirFD); err != nil {
  63. if !canSkipEBPFError(cgroup) {
  64. return err
  65. }
  66. }
  67. return nil
  68. }