Add mode check for device

This fixes two problems:
1. docker run --device /dev/sda:rw ubuntu bash doesn't work
2. --device /dev/zero:/dev/noro:ro doesn't show clear error message,
but fail when writing to cgroup file.

Signed-off-by: Qiang Huang <h.huangqiang@huawei.com>
This commit is contained in:
Qiang Huang 2015-08-24 17:57:12 +08:00 committed by Vincent Demeester
parent 6a31056ff6
commit 22e1ac4966
2 changed files with 53 additions and 29 deletions

View File

@ -170,11 +170,32 @@ func ValidateLink(val string) (string, error) {
return val, nil return val, nil
} }
// ValidDeviceMode checks if the mode for device is valid or not.
// Valid mode is a composition of r (read), w (write), and m (mknod).
func ValidDeviceMode(mode string) bool {
var legalDeviceMode = map[rune]bool{
'r': true,
'w': true,
'm': true,
}
if mode == "" {
return false
}
for _, c := range mode {
if !legalDeviceMode[c] {
return false
}
legalDeviceMode[c] = false
}
return true
}
// ValidateDevice Validate a path for devices // ValidateDevice Validate a path for devices
// It will make sure 'val' is in the form: // It will make sure 'val' is in the form:
// [host-dir:]container-path[:mode] // [host-dir:]container-path[:mode]
// It will also validate the device mode.
func ValidateDevice(val string) (string, error) { func ValidateDevice(val string) (string, error) {
return validatePath(val, false) return validatePath(val, ValidDeviceMode)
} }
// ValidatePath Validate a path for volumes // ValidatePath Validate a path for volumes
@ -182,27 +203,27 @@ func ValidateDevice(val string) (string, error) {
// [host-dir:]container-path[:rw|ro] // [host-dir:]container-path[:rw|ro]
// It will also validate the mount mode. // It will also validate the mount mode.
func ValidatePath(val string) (string, error) { func ValidatePath(val string) (string, error) {
return validatePath(val, true) return validatePath(val, volume.ValidMountMode)
} }
func validatePath(val string, validateMountMode bool) (string, error) { func validatePath(val string, validator func(string) bool) (string, error) {
var containerPath string var containerPath string
var mode string var mode string
if strings.Count(val, ":") > 2 { if strings.Count(val, ":") > 2 {
return val, fmt.Errorf("bad format for volumes: %s", val) return val, fmt.Errorf("bad format for path: %s", val)
} }
splited := strings.SplitN(val, ":", 3) splited := strings.SplitN(val, ":", 3)
if splited[0] == "" { if splited[0] == "" {
return val, fmt.Errorf("bad format for volumes: %s", val) return val, fmt.Errorf("bad format for path: %s", val)
} }
switch len(splited) { switch len(splited) {
case 1: case 1:
containerPath = splited[0] containerPath = splited[0]
val = path.Clean(containerPath) val = path.Clean(containerPath)
case 2: case 2:
if isValid := volume.ValidMountMode(splited[1]); validateMountMode && isValid { if isValid := validator(splited[1]); isValid {
containerPath = splited[0] containerPath = splited[0]
mode = splited[1] mode = splited[1]
val = fmt.Sprintf("%s:%s", path.Clean(containerPath), mode) val = fmt.Sprintf("%s:%s", path.Clean(containerPath), mode)
@ -213,8 +234,8 @@ func validatePath(val string, validateMountMode bool) (string, error) {
case 3: case 3:
containerPath = splited[1] containerPath = splited[1]
mode = splited[2] mode = splited[2]
if isValid := volume.ValidMountMode(splited[2]); validateMountMode && !isValid { if isValid := validator(splited[2]); !isValid {
return val, fmt.Errorf("bad mount mode specified : %s", mode) return val, fmt.Errorf("bad mode specified: %s", mode)
} }
val = fmt.Sprintf("%s:%s:%s", splited[0], containerPath, mode) val = fmt.Sprintf("%s:%s:%s", splited[0], containerPath, mode)
} }

View File

@ -289,24 +289,24 @@ func TestValidatePath(t *testing.T) {
"/rw:rw", "/rw:rw",
} }
invalid := map[string]string{ invalid := map[string]string{
"": "bad format for volumes: ", "": "bad format for path: ",
"./": "./ is not an absolute path", "./": "./ is not an absolute path",
"../": "../ is not an absolute path", "../": "../ is not an absolute path",
"/:../": "../ is not an absolute path", "/:../": "../ is not an absolute path",
"/:path": "path is not an absolute path", "/:path": "path is not an absolute path",
":": "bad format for volumes: :", ":": "bad format for path: :",
"/tmp:": " is not an absolute path", "/tmp:": " is not an absolute path",
":test": "bad format for volumes: :test", ":test": "bad format for path: :test",
":/test": "bad format for volumes: :/test", ":/test": "bad format for path: :/test",
"tmp:": " is not an absolute path", "tmp:": " is not an absolute path",
":test:": "bad format for volumes: :test:", ":test:": "bad format for path: :test:",
"::": "bad format for volumes: ::", "::": "bad format for path: ::",
":::": "bad format for volumes: :::", ":::": "bad format for path: :::",
"/tmp:::": "bad format for volumes: /tmp:::", "/tmp:::": "bad format for path: /tmp:::",
":/tmp::": "bad format for volumes: :/tmp::", ":/tmp::": "bad format for path: :/tmp::",
"path:ro": "path is not an absolute path", "path:ro": "path is not an absolute path",
"/path:/path:sw": "bad mount mode specified : sw", "/path:/path:sw": "bad mode specified: sw",
"/path:/path:rwz": "bad mount mode specified : rwz", "/path:/path:rwz": "bad mode specified: rwz",
} }
for _, path := range valid { for _, path := range valid {
@ -333,27 +333,30 @@ func TestValidateDevice(t *testing.T) {
"/with space", "/with space",
"/home:/with space", "/home:/with space",
"relative:/absolute-path", "relative:/absolute-path",
"hostPath:/containerPath:ro", "hostPath:/containerPath:r",
"/hostPath:/containerPath:rw", "/hostPath:/containerPath:rw",
"/hostPath:/containerPath:mrw", "/hostPath:/containerPath:mrw",
} }
invalid := map[string]string{ invalid := map[string]string{
"": "bad format for volumes: ", "": "bad format for path: ",
"./": "./ is not an absolute path", "./": "./ is not an absolute path",
"../": "../ is not an absolute path", "../": "../ is not an absolute path",
"/:../": "../ is not an absolute path", "/:../": "../ is not an absolute path",
"/:path": "path is not an absolute path", "/:path": "path is not an absolute path",
":": "bad format for volumes: :", ":": "bad format for path: :",
"/tmp:": " is not an absolute path", "/tmp:": " is not an absolute path",
":test": "bad format for volumes: :test", ":test": "bad format for path: :test",
":/test": "bad format for volumes: :/test", ":/test": "bad format for path: :/test",
"tmp:": " is not an absolute path", "tmp:": " is not an absolute path",
":test:": "bad format for volumes: :test:", ":test:": "bad format for path: :test:",
"::": "bad format for volumes: ::", "::": "bad format for path: ::",
":::": "bad format for volumes: :::", ":::": "bad format for path: :::",
"/tmp:::": "bad format for volumes: /tmp:::", "/tmp:::": "bad format for path: /tmp:::",
":/tmp::": "bad format for volumes: :/tmp::", ":/tmp::": "bad format for path: :/tmp::",
"path:ro": "ro is not an absolute path", "path:ro": "ro is not an absolute path",
"path:rr": "rr is not an absolute path",
"a:/b:ro": "bad mode specified: ro",
"a:/b:rr": "bad mode specified: rr",
} }
for _, path := range valid { for _, path := range valid {