Skip to content

Commit

Permalink
libpod: allow userns=keep-id for root
Browse files Browse the repository at this point in the history
copy the current mapping into a new user namespace, and run into a
separate user namespace.

Closes: containers#17337

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
  • Loading branch information
giuseppe committed Feb 3, 2023
1 parent 78458e0 commit de63ad7
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 45 deletions.
8 changes: 4 additions & 4 deletions docs/source/markdown/options/userns.container.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand All @@ -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.

Expand Down
4 changes: 0 additions & 4 deletions pkg/specgen/generate/namespaces.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package generate

import (
"errors"
"fmt"
"strings"

Expand Down Expand Up @@ -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
Expand Down
27 changes: 24 additions & 3 deletions pkg/util/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 0 additions & 16 deletions test/e2e/run_userns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,30 +128,19 @@ 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())
Expect(session.OutputToString()).To(ContainSubstring(uid))

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))
Expand All @@ -161,23 +150,20 @@ 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))
Expect(session.OutputToString()).To(Equal("0"))
})

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))
Expect(session.OutputToString()).To(Equal("0"))
})

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")
Expand Down Expand Up @@ -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() {
Expand Down
26 changes: 8 additions & 18 deletions test/system/170-run-userns.bats
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}

0 comments on commit de63ad7

Please sign in to comment.