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 | 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` | 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 | field you specify either the numeric id, or if you use a name it will refer to the id allocated | ||||||
| refer to the id allocated to the container with that name. | to the container with that name. | ||||||
|  |  | ||||||
| ``` | ``` | ||||||
| services: | services: | ||||||
|   | |||||||
| @@ -50,8 +50,8 @@ type File struct { | |||||||
| 	Source    string | 	Source    string | ||||||
| 	Optional  bool | 	Optional  bool | ||||||
| 	Mode      string | 	Mode      string | ||||||
| 	UID       string `yaml:"uid" json:"uid"` | 	UID       interface{} `yaml:"uid" json:"uid"` | ||||||
| 	GID       string `yaml:"gid" json:"gid"` | 	GID       interface{} `yaml:"gid" json:"gid"` | ||||||
| } | } | ||||||
|  |  | ||||||
| // Image is the type of an image config | // Image is the type of an image config | ||||||
| @@ -75,9 +75,9 @@ type Image struct { | |||||||
| 	Readonly          *bool                   `yaml:"readonly" json:"readonly,omitempty"` | 	Readonly          *bool                   `yaml:"readonly" json:"readonly,omitempty"` | ||||||
| 	MaskedPaths       *[]string               `yaml:"maskedPaths" json:"maskedPaths,omitempty"` | 	MaskedPaths       *[]string               `yaml:"maskedPaths" json:"maskedPaths,omitempty"` | ||||||
| 	ReadonlyPaths     *[]string               `yaml:"readonlyPaths" json:"readonlyPaths,omitempty"` | 	ReadonlyPaths     *[]string               `yaml:"readonlyPaths" json:"readonlyPaths,omitempty"` | ||||||
| 	UID               *string                 `yaml:"uid" json:"uid,omitempty"` | 	UID               *interface{}            `yaml:"uid" json:"uid,omitempty"` | ||||||
| 	GID               *string                 `yaml:"gid" json:"gid,omitempty"` | 	GID               *interface{}            `yaml:"gid" json:"gid,omitempty"` | ||||||
| 	AdditionalGids    *[]string               `yaml:"additionalGids" json:"additionalGids,omitempty"` | 	AdditionalGids    *[]interface{}          `yaml:"additionalGids" json:"additionalGids,omitempty"` | ||||||
| 	NoNewPrivileges   *bool                   `yaml:"noNewPrivileges" json:"noNewPrivileges,omitempty"` | 	NoNewPrivileges   *bool                   `yaml:"noNewPrivileges" json:"noNewPrivileges,omitempty"` | ||||||
| 	OOMScoreAdj       *int                    `yaml:"oomScoreAdj" json:"oomScoreAdj,omitempty"` | 	OOMScoreAdj       *int                    `yaml:"oomScoreAdj" json:"oomScoreAdj,omitempty"` | ||||||
| 	DisableOOMKiller  *bool                   `yaml:"disableOOMKiller" json:"disableOOMKiller,omitempty"` | 	DisableOOMKiller  *bool                   `yaml:"disableOOMKiller" json:"disableOOMKiller,omitempty"` | ||||||
| @@ -369,6 +369,29 @@ func assignUint32Array(v1, v2 *[]uint32) []uint32 { | |||||||
| 	return []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 | // assignStrings does ordered overrides from JSON string array pointers | ||||||
| func assignStrings(v1, v2 *[]string) []string { | func assignStrings(v1, v2 *[]string) []string { | ||||||
| 	if v2 != nil { | 	if v2 != nil { | ||||||
| @@ -424,7 +447,7 @@ func assignString(v1, v2 *string) string { | |||||||
| 	return "" | 	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 { | func assignMappings(v1, v2 *[]specs.LinuxIDMapping) []specs.LinuxIDMapping { | ||||||
| 	if v2 != nil { | 	if v2 != nil { | ||||||
| 		return *v2 | 		return *v2 | ||||||
| @@ -512,20 +535,25 @@ var allCaps = []string{ | |||||||
| 	"CAP_WAKE_ALARM", | 	"CAP_WAKE_ALARM", | ||||||
| } | } | ||||||
|  |  | ||||||
| func idNumeric(id string, idMap map[string]uint32) (uint32, error) { | func idNumeric(v interface{}, idMap map[string]uint32) (uint32, error) { | ||||||
| 	if id == "" || id == "root" { | 	switch id := v.(type) { | ||||||
| 		return 0, nil | 	case nil: | ||||||
| 	} | 		return uint32(0), nil | ||||||
| 	for k, v := range idMap { | 	case int: | ||||||
| 		if id == k { | 		return uint32(id), nil | ||||||
| 			return v, nil | 	case string: | ||||||
|  | 		if id == "" || id == "root" { | ||||||
|  | 			return uint32(0), nil | ||||||
| 		} | 		} | ||||||
|  | 		for k, v := range idMap { | ||||||
|  | 			if id == k { | ||||||
|  | 				return v, nil | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		return 0, fmt.Errorf("Cannot find id: %s", id) | ||||||
|  | 	default: | ||||||
|  | 		return 0, fmt.Errorf("Bad type for uid or gid") | ||||||
| 	} | 	} | ||||||
| 	v, err := strconv.ParseUint(id, 10, 32) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return 0, fmt.Errorf("Cannot find or parse id (%s): %v", id, err) |  | ||||||
| 	} |  | ||||||
| 	return uint32(v), nil |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // ConfigInspectToOCI converts a config and the output of image inspect to an OCI config | // 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 | 	// handle mapping of named uid, gid to numbers | ||||||
| 	uidString := assignString(label.UID, yaml.UID) | 	uidIf := assignInterface(label.UID, yaml.UID) | ||||||
| 	gidString := assignString(label.GID, yaml.GID) | 	gidIf := assignInterface(label.GID, yaml.GID) | ||||||
| 	agStrings := assignStrings(label.AdditionalGids, yaml.AdditionalGids) | 	agIf := assignInterfaceArray(label.AdditionalGids, yaml.AdditionalGids) | ||||||
| 	uid, err := idNumeric(uidString, idMap) | 	uid, err := idNumeric(uidIf, idMap) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return oci, err | 		return oci, err | ||||||
| 	} | 	} | ||||||
| 	gid, err := idNumeric(gidString, idMap) | 	gid, err := idNumeric(gidIf, idMap) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return oci, err | 		return oci, err | ||||||
| 	} | 	} | ||||||
| 	additionalGroups := []uint32{} | 	additionalGroups := []uint32{} | ||||||
| 	for _, id := range agStrings { | 	for _, id := range agIf { | ||||||
| 		ag, err := idNumeric(id, idMap) | 		ag, err := idNumeric(id, idMap) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return oci, err | 			return oci, err | ||||||
|   | |||||||
| @@ -81,8 +81,8 @@ func TestInvalidCap(t *testing.T) { | |||||||
| func TestIdMap(t *testing.T) { | func TestIdMap(t *testing.T) { | ||||||
| 	idMap := map[string]uint32{"test": 199} | 	idMap := map[string]uint32{"test": 199} | ||||||
|  |  | ||||||
| 	uid := "test" | 	var uid interface{} = "test" | ||||||
| 	gid := "76" | 	var gid interface{} = 76 | ||||||
|  |  | ||||||
| 	yaml := Image{ | 	yaml := Image{ | ||||||
| 		Name:  "test", | 		Name:  "test", | ||||||
|   | |||||||
| @@ -27,8 +27,8 @@ var schema = string(` | |||||||
|           "source": {"type": "string"}, |           "source": {"type": "string"}, | ||||||
|           "optional": {"type": "boolean"}, |           "optional": {"type": "boolean"}, | ||||||
|           "mode": {"type": "string"}, |           "mode": {"type": "string"}, | ||||||
|           "uid": {"type": "string"}, |           "uid": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, | ||||||
|           "gid": {"type": "string"} |           "gid": {"anyOf": [{"type": "string"}, {"type": "integer"}]} | ||||||
|         } |         } | ||||||
|     }, |     }, | ||||||
|     "files": { |     "files": { | ||||||
| @@ -97,11 +97,11 @@ var schema = string(` | |||||||
|         "readonly": { "type": "boolean"}, |         "readonly": { "type": "boolean"}, | ||||||
|         "maskedPaths": { "$ref": "#/definitions/strings" }, |         "maskedPaths": { "$ref": "#/definitions/strings" }, | ||||||
|         "readonlyPaths": { "$ref": "#/definitions/strings" }, |         "readonlyPaths": { "$ref": "#/definitions/strings" }, | ||||||
|         "uid": {"type": "string"}, |         "uid": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, | ||||||
|         "gid": {"type": "string"}, |         "gid": {"anyOf": [{"type": "string"}, {"type": "integer"}]}, | ||||||
|         "additionalGids": { |         "additionalGids": { | ||||||
|             "type": "array", |             "type": "array", | ||||||
|             "items": { "type": "string" } |             "items": {"anyOf": [{"type": "string"}, {"type": "integer"}]} | ||||||
|         }, |         }, | ||||||
|         "noNewPrivileges": {"type": "boolean"}, |         "noNewPrivileges": {"type": "boolean"}, | ||||||
|         "hostname": {"type": "string"}, |         "hostname": {"type": "string"}, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user