diff --git a/libcontainer/cgroups/fs2/devices.go b/libcontainer/cgroups/fs2/devices.go index 4c793a1cc..99559fec5 100644 --- a/libcontainer/cgroups/fs2/devices.go +++ b/libcontainer/cgroups/fs2/devices.go @@ -7,6 +7,8 @@ import ( "github.com/opencontainers/runc/libcontainer/cgroups/ebpf/devicefilter" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/devices" + "github.com/opencontainers/runc/libcontainer/system" + "github.com/pkg/errors" "golang.org/x/sys/unix" ) @@ -26,11 +28,26 @@ func isRWM(perms devices.Permissions) bool { return r && w && m } -// the logic is from crun -// https://github.com/containers/crun/blob/0.10.2/src/libcrun/cgroup.c#L1644-L1652 +// This is similar to the logic applied in crun for handling errors from bpf(2) +// . func canSkipEBPFError(cgroup *configs.Cgroup) bool { + // If we're running in a user namespace we can ignore eBPF rules because we + // usually cannot use bpf(2), as well as rootless containers usually don't + // have the necessary privileges to mknod(2) device inodes or access + // host-level instances (though ideally we would be blocking device access + // for rootless containers anyway). + if system.RunningInUserNS() { + return true + } + + // We cannot ignore an eBPF load error if any rule if is a block rule or it + // doesn't permit all access modes. + // + // NOTE: This will sometimes trigger in cases where access modes are split + // between different rules but to handle this correctly would require + // using ".../libcontainer/cgroup/devices".Emulator. for _, dev := range cgroup.Resources.Devices { - if dev.Allow || !isRWM(dev.Permissions) { + if !dev.Allow || !isRWM(dev.Permissions) { return false } }