...

Source file src/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go

Documentation: github.com/opencontainers/runc/libcontainer/configs/validate

     1  package validate
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/opencontainers/runc/libcontainer/configs"
     9  )
    10  
    11  // rootlessEUID makes sure that the config can be applied when runc
    12  // is being executed as a non-root user (euid != 0) in the current user namespace.
    13  func (v *ConfigValidator) rootlessEUID(config *configs.Config) error {
    14  	if !config.RootlessEUID {
    15  		return nil
    16  	}
    17  	if err := rootlessEUIDMappings(config); err != nil {
    18  		return err
    19  	}
    20  	if err := rootlessEUIDMount(config); err != nil {
    21  		return err
    22  	}
    23  
    24  	// XXX: We currently can't verify the user config at all, because
    25  	//      configs.Config doesn't store the user-related configs. So this
    26  	//      has to be verified by setupUser() in init_linux.go.
    27  
    28  	return nil
    29  }
    30  
    31  func rootlessEUIDMappings(config *configs.Config) error {
    32  	if !config.Namespaces.Contains(configs.NEWUSER) {
    33  		return errors.New("rootless container requires user namespaces")
    34  	}
    35  	// We only require mappings if we are not joining another userns.
    36  	if path := config.Namespaces.PathOf(configs.NEWUSER); path == "" {
    37  		if len(config.UidMappings) == 0 {
    38  			return errors.New("rootless containers requires at least one UID mapping")
    39  		}
    40  		if len(config.GidMappings) == 0 {
    41  			return errors.New("rootless containers requires at least one GID mapping")
    42  		}
    43  	}
    44  	return nil
    45  }
    46  
    47  // mount verifies that the user isn't trying to set up any mounts they don't have
    48  // the rights to do. In addition, it makes sure that no mount has a `uid=` or
    49  // `gid=` option that doesn't resolve to root.
    50  func rootlessEUIDMount(config *configs.Config) error {
    51  	// XXX: We could whitelist allowed devices at this point, but I'm not
    52  	//      convinced that's a good idea. The kernel is the best arbiter of
    53  	//      access control.
    54  
    55  	for _, mount := range config.Mounts {
    56  		// Check that the options list doesn't contain any uid= or gid= entries
    57  		// that don't resolve to root.
    58  		for _, opt := range strings.Split(mount.Data, ",") {
    59  			if strings.HasPrefix(opt, "uid=") {
    60  				var uid int
    61  				n, err := fmt.Sscanf(opt, "uid=%d", &uid)
    62  				if n != 1 || err != nil {
    63  					// Ignore unknown mount options.
    64  					continue
    65  				}
    66  				if _, err := config.HostUID(uid); err != nil {
    67  					return fmt.Errorf("cannot specify uid=%d mount option for rootless container: %w", uid, err)
    68  				}
    69  			}
    70  
    71  			if strings.HasPrefix(opt, "gid=") {
    72  				var gid int
    73  				n, err := fmt.Sscanf(opt, "gid=%d", &gid)
    74  				if n != 1 || err != nil {
    75  					// Ignore unknown mount options.
    76  					continue
    77  				}
    78  				if _, err := config.HostGID(gid); err != nil {
    79  					return fmt.Errorf("cannot specify gid=%d mount option for rootless container: %w", gid, err)
    80  				}
    81  			}
    82  		}
    83  	}
    84  
    85  	return nil
    86  }
    87  

View as plain text