mirror of
				https://github.com/linuxkit/linuxkit.git
				synced 2025-10-31 01:37:42 +00:00 
			
		
		
		
	Allow uid, gid fields to be numeric or names
Previously I was forcing them to be strings, which is horrible. Now you can either specify a numeric uid or the name of a service to use the allocated id for that service. Signed-off-by: Justin Cormack <justin.cormack@docker.com>
This commit is contained in:
		| @@ -15,8 +15,8 @@ Each section adds file to the root file system. Sections may be omitted. | ||||
|  | ||||
| Each container that is specified is allocated a unique `uid` and `gid` that it may use if it | ||||
| wishes to run as an isolated user (or user namespace). Anywhere you specify a `uid` or `gid` | ||||
| field you specify a string that can either be the numeric id, or if you use a name it will | ||||
| refer to the id allocated to the container with that name. | ||||
| field you specify either the numeric id, or if you use a name it will refer to the id allocated | ||||
| to the container with that name. | ||||
|  | ||||
| ``` | ||||
| services: | ||||
|   | ||||
| @@ -50,8 +50,8 @@ type File struct { | ||||
| 	Source    string | ||||
| 	Optional  bool | ||||
| 	Mode      string | ||||
| 	UID       string `yaml:"uid" json:"uid"` | ||||
| 	GID       string `yaml:"gid" json:"gid"` | ||||
| 	UID       interface{} `yaml:"uid" json:"uid"` | ||||
| 	GID       interface{} `yaml:"gid" json:"gid"` | ||||
| } | ||||
|  | ||||
| // Image is the type of an image config | ||||
| @@ -75,9 +75,9 @@ type Image struct { | ||||
| 	Readonly          *bool                   `yaml:"readonly" json:"readonly,omitempty"` | ||||
| 	MaskedPaths       *[]string               `yaml:"maskedPaths" json:"maskedPaths,omitempty"` | ||||
| 	ReadonlyPaths     *[]string               `yaml:"readonlyPaths" json:"readonlyPaths,omitempty"` | ||||
| 	UID               *string                 `yaml:"uid" json:"uid,omitempty"` | ||||
| 	GID               *string                 `yaml:"gid" json:"gid,omitempty"` | ||||
| 	AdditionalGids    *[]string               `yaml:"additionalGids" json:"additionalGids,omitempty"` | ||||
| 	UID               *interface{}            `yaml:"uid" json:"uid,omitempty"` | ||||
| 	GID               *interface{}            `yaml:"gid" json:"gid,omitempty"` | ||||
| 	AdditionalGids    *[]interface{}          `yaml:"additionalGids" json:"additionalGids,omitempty"` | ||||
| 	NoNewPrivileges   *bool                   `yaml:"noNewPrivileges" json:"noNewPrivileges,omitempty"` | ||||
| 	OOMScoreAdj       *int                    `yaml:"oomScoreAdj" json:"oomScoreAdj,omitempty"` | ||||
| 	DisableOOMKiller  *bool                   `yaml:"disableOOMKiller" json:"disableOOMKiller,omitempty"` | ||||
| @@ -369,6 +369,29 @@ func assignUint32Array(v1, v2 *[]uint32) []uint32 { | ||||
| 	return []uint32{} | ||||
| } | ||||
|  | ||||
| // assignInterface does ordered overrides from Go interfaces | ||||
| // we return 0 as we are using this for uid and this is the default | ||||
| func assignInterface(v1, v2 *interface{}) interface{} { | ||||
| 	if v2 != nil { | ||||
| 		return *v2 | ||||
| 	} | ||||
| 	if v1 != nil { | ||||
| 		return *v1 | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| // assignInterfaceArray does ordered overrides from arrays of Go interfaces | ||||
| func assignInterfaceArray(v1, v2 *[]interface{}) []interface{} { | ||||
| 	if v2 != nil { | ||||
| 		return *v2 | ||||
| 	} | ||||
| 	if v1 != nil { | ||||
| 		return *v1 | ||||
| 	} | ||||
| 	return []interface{}{} | ||||
| } | ||||
|  | ||||
| // assignStrings does ordered overrides from JSON string array pointers | ||||
| func assignStrings(v1, v2 *[]string) []string { | ||||
| 	if v2 != nil { | ||||
| @@ -424,7 +447,7 @@ func assignString(v1, v2 *string) string { | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| // assignMappings does prdered overrides from UID, GID maps | ||||
| // assignMappings does ordered overrides from UID, GID maps | ||||
| func assignMappings(v1, v2 *[]specs.LinuxIDMapping) []specs.LinuxIDMapping { | ||||
| 	if v2 != nil { | ||||
| 		return *v2 | ||||
| @@ -512,20 +535,25 @@ var allCaps = []string{ | ||||
| 	"CAP_WAKE_ALARM", | ||||
| } | ||||
|  | ||||
| func idNumeric(id string, idMap map[string]uint32) (uint32, error) { | ||||
| func idNumeric(v interface{}, idMap map[string]uint32) (uint32, error) { | ||||
| 	switch id := v.(type) { | ||||
| 	case nil: | ||||
| 		return uint32(0), nil | ||||
| 	case int: | ||||
| 		return uint32(id), nil | ||||
| 	case string: | ||||
| 		if id == "" || id == "root" { | ||||
| 		return 0, nil | ||||
| 			return uint32(0), nil | ||||
| 		} | ||||
| 		for k, v := range idMap { | ||||
| 			if id == k { | ||||
| 				return v, nil | ||||
| 			} | ||||
| 		} | ||||
| 	v, err := strconv.ParseUint(id, 10, 32) | ||||
| 	if err != nil { | ||||
| 		return 0, fmt.Errorf("Cannot find or parse id (%s): %v", id, err) | ||||
| 		return 0, fmt.Errorf("Cannot find id: %s", id) | ||||
| 	default: | ||||
| 		return 0, fmt.Errorf("Bad type for uid or gid") | ||||
| 	} | ||||
| 	return uint32(v), nil | ||||
| } | ||||
|  | ||||
| // ConfigInspectToOCI converts a config and the output of image inspect to an OCI config | ||||
| @@ -797,19 +825,19 @@ func ConfigInspectToOCI(yaml Image, inspect types.ImageInspect, idMap map[string | ||||
| 	} | ||||
|  | ||||
| 	// handle mapping of named uid, gid to numbers | ||||
| 	uidString := assignString(label.UID, yaml.UID) | ||||
| 	gidString := assignString(label.GID, yaml.GID) | ||||
| 	agStrings := assignStrings(label.AdditionalGids, yaml.AdditionalGids) | ||||
| 	uid, err := idNumeric(uidString, idMap) | ||||
| 	uidIf := assignInterface(label.UID, yaml.UID) | ||||
| 	gidIf := assignInterface(label.GID, yaml.GID) | ||||
| 	agIf := assignInterfaceArray(label.AdditionalGids, yaml.AdditionalGids) | ||||
| 	uid, err := idNumeric(uidIf, idMap) | ||||
| 	if err != nil { | ||||
| 		return oci, err | ||||
| 	} | ||||
| 	gid, err := idNumeric(gidString, idMap) | ||||
| 	gid, err := idNumeric(gidIf, idMap) | ||||
| 	if err != nil { | ||||
| 		return oci, err | ||||
| 	} | ||||
| 	additionalGroups := []uint32{} | ||||
| 	for _, id := range agStrings { | ||||
| 	for _, id := range agIf { | ||||
| 		ag, err := idNumeric(id, idMap) | ||||
| 		if err != nil { | ||||
| 			return oci, err | ||||
|   | ||||
| @@ -81,8 +81,8 @@ func TestInvalidCap(t *testing.T) { | ||||
| func TestIdMap(t *testing.T) { | ||||
| 	idMap := map[string]uint32{"test": 199} | ||||
|  | ||||
| 	uid := "test" | ||||
| 	gid := "76" | ||||
| 	var uid interface{} = "test" | ||||
| 	var gid interface{} = 76 | ||||
|  | ||||
| 	yaml := Image{ | ||||
| 		Name:  "test", | ||||
|   | ||||
| @@ -27,8 +27,8 @@ var schema = string(` | ||||
|           "source": {"type": "string"}, | ||||
|           "optional": {"type": "boolean"}, | ||||
|           "mode": {"type": "string"}, | ||||
|           "uid": {"type": "string"}, | ||||
|           "gid": {"type": "string"} | ||||
|           "uid": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, | ||||
|           "gid": {"anyOf": [{"type": "string"}, {"type": "integer"}]} | ||||
|         } | ||||
|     }, | ||||
|     "files": { | ||||
| @@ -97,11 +97,11 @@ var schema = string(` | ||||
|         "readonly": { "type": "boolean"}, | ||||
|         "maskedPaths": { "$ref": "#/definitions/strings" }, | ||||
|         "readonlyPaths": { "$ref": "#/definitions/strings" }, | ||||
|         "uid": {"type": "string"}, | ||||
|         "gid": {"type": "string"}, | ||||
|         "uid": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, | ||||
|         "gid": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, | ||||
|         "additionalGids": { | ||||
|             "type": "array", | ||||
|             "items": { "type": "string" } | ||||
|             "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]} | ||||
|         }, | ||||
|         "noNewPrivileges": {"type": "boolean"}, | ||||
|         "hostname": {"type": "string"}, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user