diff --git a/docs/sources/reference/run.md b/docs/sources/reference/run.md index 7587c70ba6..aa3d941b13 100644 --- a/docs/sources/reference/run.md +++ b/docs/sources/reference/run.md @@ -439,6 +439,8 @@ but the operator can override it: -u="": Username or UID +> **Note:** if you pass numeric uid, it must be in range 0-2147483647. + ## WORKDIR The default working directory for running binaries within a container is the diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index a439c5f387..154b72e27a 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -544,6 +544,51 @@ func TestUserByID(t *testing.T) { logDone("run - user by id") } +func TestUserByIDBig(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "-u", "2147483648", "busybox", "id") + + out, _, err := runCommandWithOutput(cmd) + if err == nil { + t.Fatal("No error, but must be.", out) + } + if !strings.Contains(out, "Uids and gids must be in range") { + t.Fatalf("expected error about uids range, got %s", out) + } + deleteAllContainers() + + logDone("run - user by id, id too big") +} + +func TestUserByIDNegative(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "-u", "-1", "busybox", "id") + + out, _, err := runCommandWithOutput(cmd) + if err == nil { + t.Fatal("No error, but must be.", out) + } + if !strings.Contains(out, "Uids and gids must be in range") { + t.Fatalf("expected error about uids range, got %s", out) + } + deleteAllContainers() + + logDone("run - user by id, id negative") +} + +func TestUserByIDZero(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "-u", "0", "busybox", "id") + + out, _, err := runCommandWithOutput(cmd) + if err != nil { + t.Fatal(err, out) + } + if !strings.Contains(out, "uid=0(root) gid=0(root) groups=10(wheel)") { + t.Fatalf("expected daemon user got %s", out) + } + deleteAllContainers() + + logDone("run - user by id, zero uid") +} + func TestUserNotFound(t *testing.T) { cmd := exec.Command(dockerBinary, "run", "-u", "notme", "busybox", "id") diff --git a/pkg/user/user.go b/pkg/user/user.go index 1672f7e679..df47101221 100644 --- a/pkg/user/user.go +++ b/pkg/user/user.go @@ -9,6 +9,15 @@ import ( "strings" ) +const ( + minId = 0 + maxId = 1<<31 - 1 //for 32-bit systems compatibility +) + +var ( + ErrRange = fmt.Errorf("Uids and gids must be in range %d-%d", minId, maxId) +) + type User struct { Name string Pass string @@ -194,6 +203,9 @@ func GetUserGroupSupplementary(userSpec string, defaultUid int, defaultGid int) // not numeric - we have to bail return 0, 0, nil, fmt.Errorf("Unable to find user %v", userArg) } + if uid < minId || uid > maxId { + return 0, 0, nil, ErrRange + } // if userArg couldn't be found in /etc/passwd but is numeric, just roll with it - this is legit } @@ -226,6 +238,9 @@ func GetUserGroupSupplementary(userSpec string, defaultUid int, defaultGid int) // not numeric - we have to bail return 0, 0, nil, fmt.Errorf("Unable to find group %v", groupArg) } + if gid < minId || gid > maxId { + return 0, 0, nil, ErrRange + } // if groupArg couldn't be found in /etc/group but is numeric, just roll with it - this is legit }