This file is indexed.

/usr/share/gocode/src/github.com/opencontainers/runc/libcontainer/configs/validate/rootless.go is in golang-github-opencontainers-runc-dev 1.0.0~rc4+dfsg1-6.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package validate

import (
	"fmt"
	"os"
	"reflect"
	"strings"

	"github.com/opencontainers/runc/libcontainer/configs"
)

var (
	geteuid = os.Geteuid
	getegid = os.Getegid
)

func (v *ConfigValidator) rootless(config *configs.Config) error {
	if err := rootlessMappings(config); err != nil {
		return err
	}
	if err := rootlessMount(config); err != nil {
		return err
	}
	// Currently, cgroups cannot effectively be used in rootless containers.
	// The new cgroup namespace doesn't really help us either because it doesn't
	// have nice interactions with the user namespace (we're working with upstream
	// to fix this).
	if err := rootlessCgroup(config); err != nil {
		return err
	}

	// XXX: We currently can't verify the user config at all, because
	//      configs.Config doesn't store the user-related configs. So this
	//      has to be verified by setupUser() in init_linux.go.

	return nil
}

func rootlessMappings(config *configs.Config) error {
	rootuid, err := config.HostRootUID()
	if err != nil {
		return fmt.Errorf("failed to get root uid from uidMappings: %v", err)
	}
	if euid := geteuid(); euid != 0 {
		if !config.Namespaces.Contains(configs.NEWUSER) {
			return fmt.Errorf("rootless containers require user namespaces")
		}
		if rootuid != euid {
			return fmt.Errorf("rootless containers cannot map container root to a different host user")
		}
	}

	rootgid, err := config.HostRootGID()
	if err != nil {
		return fmt.Errorf("failed to get root gid from gidMappings: %v", err)
	}

	// Similar to the above test, we need to make sure that we aren't trying to
	// map to a group ID that we don't have the right to be.
	if rootgid != getegid() {
		return fmt.Errorf("rootless containers cannot map container root to a different host group")
	}

	// We can only map one user and group inside a container (our own).
	if len(config.UidMappings) != 1 || config.UidMappings[0].Size != 1 {
		return fmt.Errorf("rootless containers cannot map more than one user")
	}
	if len(config.GidMappings) != 1 || config.GidMappings[0].Size != 1 {
		return fmt.Errorf("rootless containers cannot map more than one group")
	}

	return nil
}

// cgroup verifies that the user isn't trying to set any cgroup limits or paths.
func rootlessCgroup(config *configs.Config) error {
	// Nothing set at all.
	if config.Cgroups == nil || config.Cgroups.Resources == nil {
		return nil
	}

	// Used for comparing to the zero value.
	left := reflect.ValueOf(*config.Cgroups.Resources)
	right := reflect.Zero(left.Type())

	// This is all we need to do, since specconv won't add cgroup options in
	// rootless mode.
	if !reflect.DeepEqual(left.Interface(), right.Interface()) {
		return fmt.Errorf("cannot specify resource limits in rootless container")
	}

	return nil
}

// mount verifies that the user isn't trying to set up any mounts they don't have
// the rights to do. In addition, it makes sure that no mount has a `uid=` or
// `gid=` option that doesn't resolve to root.
func rootlessMount(config *configs.Config) error {
	// XXX: We could whitelist allowed devices at this point, but I'm not
	//      convinced that's a good idea. The kernel is the best arbiter of
	//      access control.

	for _, mount := range config.Mounts {
		// Check that the options list doesn't contain any uid= or gid= entries
		// that don't resolve to root.
		for _, opt := range strings.Split(mount.Data, ",") {
			if strings.HasPrefix(opt, "uid=") && opt != "uid=0" {
				return fmt.Errorf("cannot specify uid= mount options in rootless containers where argument isn't 0")
			}
			if strings.HasPrefix(opt, "gid=") && opt != "gid=0" {
				return fmt.Errorf("cannot specify gid= mount options in rootless containers where argument isn't 0")
			}
		}
	}

	return nil
}