...

Source file src/github.com/opencontainers/runc/libcontainer/cgroups/fs2/devices.go

Documentation: github.com/opencontainers/runc/libcontainer/cgroups/fs2

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

View as plain text