From de63ad70442585790d34693169558fc6e897b3fd Mon Sep 17 00:00:00 2001 From: Giuseppe Scrivano Date: Fri, 3 Feb 2023 11:10:55 +0100 Subject: [PATCH] libpod: allow userns=keep-id for root copy the current mapping into a new user namespace, and run into a separate user namespace. Closes: https://github.com/containers/podman/issues/17337 Signed-off-by: Giuseppe Scrivano --- .../markdown/options/userns.container.md | 8 +++--- pkg/specgen/generate/namespaces.go | 4 --- pkg/util/utils.go | 27 ++++++++++++++++--- test/e2e/run_userns_test.go | 16 ----------- test/system/170-run-userns.bats | 26 ++++++------------ 5 files changed, 36 insertions(+), 45 deletions(-) diff --git a/docs/source/markdown/options/userns.container.md b/docs/source/markdown/options/userns.container.md index 1c6e2be64bc5..298d3d90ff49 100644 --- a/docs/source/markdown/options/userns.container.md +++ b/docs/source/markdown/options/userns.container.md @@ -28,7 +28,7 @@ Example: `containers:2147483647:2147483648`. Podman allocates unique ranges of UIDs and GIDs from the `containers` subordinate user ids. The size of the ranges is based on the number of UIDs required in the image. The number of UIDs and GIDs can be overridden with the `size` option. -The rootless option `--userns=keep-id` uses all the subuids and subgids of the user. Using `--userns=auto` when starting new containers will not work as long as any containers exist that were started with `--userns=keep-id`. +The option `--userns=keep-id` uses all the subuids and subgids of the user. Using `--userns=auto` when starting new containers will not work as long as any containers exist that were started with `--userns=keep-id`. Valid `auto` options: @@ -40,12 +40,12 @@ The rootless option `--userns=keep-id` uses all the subuids and subgids of the u **host**: run in the user namespace of the caller. The processes running in the container will have the same privileges on the host as any other process launched by the calling user (default). -**keep-id**: creates a user namespace where the current rootless user's UID:GID are mapped to the same values in the container. This option is not allowed for containers created by the root user. +**keep-id**: creates a user namespace where the current user's UID:GID are mapped to the same values in the container. For containers created by root, the current mapping is created into a new user namespace. Valid `keep-id` options: - - *uid*=UID: override the UID inside the container that will be used to map the current rootless user to. - - *gid*=GID: override the GID inside the container that will be used to map the current rootless user to. + - *uid*=UID: override the UID inside the container that will be used to map the current user to. + - *gid*=GID: override the GID inside the container that will be used to map the current user to. **nomap**: creates a user namespace where the current rootless user's UID:GID are not mapped into the container. This option is not allowed for containers created by the root user. diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go index fa4b6a2f5d70..ff5154cec53e 100644 --- a/pkg/specgen/generate/namespaces.go +++ b/pkg/specgen/generate/namespaces.go @@ -1,7 +1,6 @@ package generate import ( - "errors" "fmt" "strings" @@ -194,9 +193,6 @@ func namespaceOptions(s *specgen.SpecGenerator, rt *libpod.Runtime, pod *libpod. // User switch s.UserNS.NSMode { case specgen.KeepID: - if !rootless.IsRootless() { - return nil, errors.New("keep-id is only supported in rootless mode") - } opts, err := namespaces.UsernsMode(s.UserNS.String()).GetKeepIDOptions() if err != nil { return nil, err diff --git a/pkg/util/utils.go b/pkg/util/utils.go index 4e4080202918..905561830a64 100644 --- a/pkg/util/utils.go +++ b/pkg/util/utils.go @@ -113,13 +113,34 @@ func ParseSignal(rawSignal string) (syscall.Signal, error) { // GetKeepIDMapping returns the mappings and the user to use when keep-id is used func GetKeepIDMapping(opts *namespaces.KeepIDUserNsOptions) (*stypes.IDMappingOptions, int, int, error) { - if !rootless.IsRootless() { - return nil, -1, -1, errors.New("keep-id is only supported in rootless mode") - } options := stypes.IDMappingOptions{ HostUIDMapping: false, HostGIDMapping: false, } + + if !rootless.IsRootless() { + uids, err := rootless.ReadMappingsProc("/proc/self/uid_map") + if err != nil { + return nil, 0, 0, err + } + gids, err := rootless.ReadMappingsProc("/proc/self/uid_map") + if err != nil { + return nil, 0, 0, err + } + options.UIDMap = uids + options.GIDMap = gids + + uid, gid := 0, 0 + if opts.UID != nil { + uid = int(*opts.UID) + } + if opts.GID != nil { + gid = int(*opts.GID) + } + + return &options, uid, gid, nil + } + min := func(a, b int) int { if a < b { return a diff --git a/test/e2e/run_userns_test.go b/test/e2e/run_userns_test.go index 269b4895e4cc..1da50f4d7ed2 100644 --- a/test/e2e/run_userns_test.go +++ b/test/e2e/run_userns_test.go @@ -128,11 +128,6 @@ var _ = Describe("Podman UserNS support", func() { It("podman --userns=keep-id", func() { session := podmanTest.Podman([]string{"run", "--userns=keep-id", "alpine", "id", "-u"}) session.WaitWithDefaultTimeout() - if !isRootless() { - Expect(session).Should(Exit(125)) - Expect(session.ErrorToString()).To(ContainSubstring("keep-id is only supported in rootless mode")) - return - } Expect(session).Should(Exit(0)) uid := fmt.Sprintf("%d", os.Geteuid()) @@ -140,18 +135,12 @@ var _ = Describe("Podman UserNS support", func() { session = podmanTest.Podman([]string{"run", "--userns=keep-id:uid=10,gid=12", "alpine", "sh", "-c", "echo $(id -u):$(id -g)"}) session.WaitWithDefaultTimeout() - if !isRootless() { - Expect(session).Should(Exit(125)) - Expect(session.ErrorToString()).To(ContainSubstring("keep-id is only supported in rootless mode")) - return - } Expect(session).Should(Exit(0)) Expect(session.OutputToString()).To(ContainSubstring("10:12")) }) It("podman --userns=keep-id check passwd", func() { - SkipIfNotRootless("keep-id only works in rootless mode") session := podmanTest.Podman([]string{"run", "--userns=keep-id", "alpine", "id", "-un"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) @@ -161,7 +150,6 @@ var _ = Describe("Podman UserNS support", func() { }) It("podman --userns=keep-id root owns /usr", func() { - SkipIfNotRootless("keep-id only works in rootless mode") session := podmanTest.Podman([]string{"run", "--userns=keep-id", "alpine", "stat", "-c%u", "/usr"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) @@ -169,7 +157,6 @@ var _ = Describe("Podman UserNS support", func() { }) It("podman --userns=keep-id --user root:root", func() { - SkipIfNotRootless("keep-id only works in rootless mode") session := podmanTest.Podman([]string{"run", "--userns=keep-id", "--user", "root:root", "alpine", "id", "-u"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) @@ -177,7 +164,6 @@ var _ = Describe("Podman UserNS support", func() { }) It("podman run --userns=keep-id can add users", func() { - SkipIfNotRootless("keep-id only works in rootless mode") userName := os.Getenv("USER") if userName == "" { Skip("Can't complete test if no username available") @@ -403,8 +389,6 @@ var _ = Describe("Podman UserNS support", func() { }) It("podman PODMAN_USERNS", func() { - SkipIfNotRootless("keep-id only works in rootless mode") - podmanUserns, podmanUserusSet := os.LookupEnv("PODMAN_USERNS") os.Setenv("PODMAN_USERNS", "keep-id") defer func() { diff --git a/test/system/170-run-userns.bats b/test/system/170-run-userns.bats index f468476476d6..dd4897b82072 100644 --- a/test/system/170-run-userns.bats +++ b/test/system/170-run-userns.bats @@ -131,25 +131,15 @@ EOF } @test "podman userns=keep-id" { - if is_rootless; then - user=$(id -u) - run_podman run --rm --userns=keep-id $IMAGE id -u - is "${output}" "$user" "Container should run as the current user" - else - run_podman 125 run --rm --userns=keep-id $IMAGE id -u - is "${output}" "Error: keep-id is only supported in rootless mode" "Container should fail to start since keep-id is not supported in rootful mode" - fi + user=$(id -u) + run_podman run --rm --userns=keep-id $IMAGE id -u + is "${output}" "$user" "Container should run as the current user" } @test "podman userns=keep-id in a pod" { - if is_rootless; then - user=$(id -u) - run_podman pod create --userns keep-id - pid=$output - run_podman run --rm --pod $pid $IMAGE id -u - is "${output}" "$user" "Container should run as the current user" - else - run_podman 125 pod create --userns keep-id - is "${output}" 'Error:.*keep-id is only supported in rootless mode' "pod should fail to be created since keep-id is not supported in rootful mode" - fi + user=$(id -u) + run_podman pod create --userns keep-id + pid=$output + run_podman run --rm --pod $pid $IMAGE id -u + is "${output}" "$user" "Container should run as the current user" }