github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/libcontainer/configs/validate/rootless.go (about) 1 package validate 2 3 import ( 4 "errors" 5 "fmt" 6 "strconv" 7 "strings" 8 9 "github.com/opencontainers/runc/libcontainer/configs" 10 ) 11 12 // rootlessEUIDCheck makes sure that the config can be applied when runc 13 // is being executed as a non-root user (euid != 0) in the current user namespace. 14 func rootlessEUIDCheck(config *configs.Config) error { 15 if !config.RootlessEUID { 16 return nil 17 } 18 if err := rootlessEUIDMappings(config); err != nil { 19 return err 20 } 21 if err := rootlessEUIDMount(config); err != nil { 22 return err 23 } 24 25 // XXX: We currently can't verify the user config at all, because 26 // configs.Config doesn't store the user-related configs. So this 27 // has to be verified by setupUser() in init_linux.go. 28 29 return nil 30 } 31 32 func rootlessEUIDMappings(config *configs.Config) error { 33 if !config.Namespaces.Contains(configs.NEWUSER) { 34 return errors.New("rootless container requires user namespaces") 35 } 36 // We only require mappings if we are not joining another userns. 37 if path := config.Namespaces.PathOf(configs.NEWUSER); path == "" { 38 if len(config.UIDMappings) == 0 { 39 return errors.New("rootless containers requires at least one UID mapping") 40 } 41 if len(config.GIDMappings) == 0 { 42 return errors.New("rootless containers requires at least one GID mapping") 43 } 44 } 45 return nil 46 } 47 48 // rootlessEUIDMount verifies that all mounts have valid uid=/gid= options, 49 // i.e. their arguments has proper ID mappings. 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 str := strings.TrimPrefix(opt, "uid="); len(str) < len(opt) { 60 uid, err := strconv.Atoi(str) 61 if err != nil { 62 // Ignore unknown mount options. 63 continue 64 } 65 if _, err := config.HostUID(uid); err != nil { 66 return fmt.Errorf("cannot specify uid=%d mount option for rootless container: %w", uid, err) 67 } 68 } 69 70 if str := strings.TrimPrefix(opt, "gid="); len(str) < len(opt) { 71 gid, err := strconv.Atoi(str) 72 if err != nil { 73 // Ignore unknown mount options. 74 continue 75 } 76 if _, err := config.HostGID(gid); err != nil { 77 return fmt.Errorf("cannot specify gid=%d mount option for rootless container: %w", gid, err) 78 } 79 } 80 } 81 } 82 83 return nil 84 }