mirror of
https://github.com/containers/podman.git
synced 2025-12-12 09:50:25 +08:00
Add support for --userns=nomap
From a security point of view, it would be nice to be able to map a rootless usernamespace that does not use your own UID within the container. This would add protection against a hostile process escapping the container and reading content in your homedir. Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
@@ -78,12 +78,18 @@ 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 os.Geteuid() == 0 {
|
||||
Expect(session).Should(Exit(125))
|
||||
return
|
||||
}
|
||||
|
||||
Expect(session).Should(Exit(0))
|
||||
uid := fmt.Sprintf("%d", os.Geteuid())
|
||||
Expect(session.OutputToString()).To(ContainSubstring(uid))
|
||||
})
|
||||
|
||||
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))
|
||||
@@ -93,6 +99,7 @@ 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))
|
||||
@@ -100,6 +107,7 @@ 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))
|
||||
@@ -107,10 +115,7 @@ var _ = Describe("Podman UserNS support", func() {
|
||||
})
|
||||
|
||||
It("podman run --userns=keep-id can add users", func() {
|
||||
if os.Geteuid() == 0 {
|
||||
Skip("Test only runs without root")
|
||||
}
|
||||
|
||||
SkipIfNotRootless("keep-id only works in rootless mode")
|
||||
userName := os.Getenv("USER")
|
||||
if userName == "" {
|
||||
Skip("Can't complete test if no username available")
|
||||
|
||||
@@ -160,6 +160,7 @@ var _ = Describe("Toolbox-specific testing", func() {
|
||||
})
|
||||
|
||||
It("podman create --userns=keep-id --user root:root - entrypoint - entrypoint is executed as root", func() {
|
||||
SkipIfNotRootless("only meaningful when run rootless")
|
||||
session := podmanTest.Podman([]string{"run", "--userns=keep-id", "--user", "root:root", ALPINE,
|
||||
"id"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
@@ -168,6 +169,7 @@ var _ = Describe("Toolbox-specific testing", func() {
|
||||
})
|
||||
|
||||
It("podman create --userns=keep-id + podman exec - correct names of user and group", func() {
|
||||
SkipIfNotRootless("only meaningful when run rootless")
|
||||
var session *PodmanSessionIntegration
|
||||
var err error
|
||||
|
||||
@@ -199,6 +201,7 @@ var _ = Describe("Toolbox-specific testing", func() {
|
||||
})
|
||||
|
||||
It("podman create --userns=keep-id - entrypoint - adding user with useradd and then removing their password", func() {
|
||||
SkipIfNotRootless("only meaningful when run rootless")
|
||||
var session *PodmanSessionIntegration
|
||||
|
||||
var username string = "testuser"
|
||||
@@ -238,6 +241,7 @@ var _ = Describe("Toolbox-specific testing", func() {
|
||||
})
|
||||
|
||||
It("podman create --userns=keep-id + podman exec - adding group with groupadd", func() {
|
||||
SkipIfNotRootless("only meaningful when run rootless")
|
||||
var session *PodmanSessionIntegration
|
||||
|
||||
var groupName string = "testgroup"
|
||||
@@ -268,6 +272,7 @@ var _ = Describe("Toolbox-specific testing", func() {
|
||||
})
|
||||
|
||||
It("podman create --userns=keep-id - entrypoint - modifying existing user with usermod - add to new group, change home/shell/uid", func() {
|
||||
SkipIfNotRootless("only meaningful when run rootless")
|
||||
var session *PodmanSessionIntegration
|
||||
var badHomeDir string = "/home/badtestuser"
|
||||
var badShell string = "/bin/sh"
|
||||
@@ -315,6 +320,7 @@ var _ = Describe("Toolbox-specific testing", func() {
|
||||
})
|
||||
|
||||
It("podman run --privileged --userns=keep-id --user root:root - entrypoint - (bind)mounting", func() {
|
||||
SkipIfNotRootless("only meaningful when run rootless")
|
||||
var session *PodmanSessionIntegration
|
||||
|
||||
session = podmanTest.Podman([]string{"run", "--privileged", "--userns=keep-id", "--user", "root:root", ALPINE,
|
||||
@@ -329,6 +335,7 @@ var _ = Describe("Toolbox-specific testing", func() {
|
||||
})
|
||||
|
||||
It("podman create + start - with all needed switches for create - sleep as entry-point", func() {
|
||||
SkipIfNotRootless("only meaningful when run rootless")
|
||||
var session *PodmanSessionIntegration
|
||||
|
||||
// These should be most of the switches that Toolbox uses to create a "toolbox" container
|
||||
@@ -365,8 +372,8 @@ var _ = Describe("Toolbox-specific testing", func() {
|
||||
})
|
||||
|
||||
It("podman run --userns=keep-id check $HOME", func() {
|
||||
SkipIfNotRootless("only meaningful when run rootless")
|
||||
var session *PodmanSessionIntegration
|
||||
|
||||
currentUser, err := user.Current()
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
|
||||
@@ -273,9 +273,11 @@ echo $rand | 0 | $rand
|
||||
# symptom only manifests on a fedora container image -- we have no
|
||||
# reproducer on alpine. Checking directory ownership is good enough.
|
||||
@test "podman run : user namespace preserved root ownership" {
|
||||
keep="--userns=keep-id"
|
||||
is_rootless || keep=""
|
||||
for priv in "" "--privileged"; do
|
||||
for user in "--user=0" "--user=100"; do
|
||||
for keepid in "" "--userns=keep-id"; do
|
||||
for keepid in "" ${keep}; do
|
||||
opts="$priv $user $keepid"
|
||||
|
||||
for dir in /etc /usr;do
|
||||
@@ -290,6 +292,7 @@ echo $rand | 0 | $rand
|
||||
|
||||
# #6829 : add username to /etc/passwd inside container if --userns=keep-id
|
||||
@test "podman run : add username to /etc/passwd if --userns=keep-id" {
|
||||
skip_if_not_rootless "--userns=keep-id only works in rootless mode"
|
||||
# Default: always run as root
|
||||
run_podman run --rm $IMAGE id -un
|
||||
is "$output" "root" "id -un on regular container"
|
||||
@@ -340,6 +343,7 @@ echo $rand | 0 | $rand
|
||||
|
||||
# #6991 : /etc/passwd is modifiable
|
||||
@test "podman run : --userns=keep-id: passwd file is modifiable" {
|
||||
skip_if_not_rootless "--userns=keep-id only works in rootless mode"
|
||||
run_podman run -d --userns=keep-id --cap-add=dac_override $IMAGE sh -c 'while ! test -e /tmp/stop; do sleep 0.1; done'
|
||||
cid="$output"
|
||||
|
||||
@@ -824,6 +828,9 @@ EOF
|
||||
|
||||
# CVE-2022-1227 : podman top joins container mount NS and uses nsenter from image
|
||||
@test "podman top does not use nsenter from image" {
|
||||
keepid="--userns=keep-id"
|
||||
is_rootless || keepid=""
|
||||
|
||||
tmpdir=$PODMAN_TMPDIR/build-test
|
||||
mkdir -p $tmpdir
|
||||
tmpbuilddir=$tmpdir/build
|
||||
@@ -838,7 +845,7 @@ EOF
|
||||
|
||||
test_image="cve_2022_1227_test"
|
||||
run_podman build -t $test_image $tmpbuilddir
|
||||
run_podman run -d --userns=keep-id $test_image top
|
||||
run_podman run -d ${keepid} $test_image top
|
||||
ctr="$output"
|
||||
run_podman top $ctr huser,user
|
||||
run_podman rm -f -t0 $ctr
|
||||
|
||||
@@ -119,7 +119,9 @@ load helpers
|
||||
echo "content" > $srcdir/hostfile
|
||||
userid=$(id -u)
|
||||
|
||||
run_podman run --user=$userid --userns=keep-id -d --name cpcontainer $IMAGE sleep infinity
|
||||
keepid="--userns=keep-id"
|
||||
is_rootless || keepid=""
|
||||
run_podman run --user=$userid ${keepid} -d --name cpcontainer $IMAGE sleep infinity
|
||||
run_podman cp $srcdir/hostfile cpcontainer:/tmp/hostfile
|
||||
run_podman exec cpcontainer stat -c "%u" /tmp/hostfile
|
||||
is "$output" "$userid" "copied file is chowned to the container user"
|
||||
@@ -138,7 +140,9 @@ load helpers
|
||||
|
||||
userid=$(id -u)
|
||||
|
||||
run_podman run --user="$userid" --userns=keep-id -d --name cpcontainer $IMAGE sleep infinity
|
||||
keepid="--userns=keep-id"
|
||||
is_rootless || keepid=""
|
||||
run_podman run --user=$userid ${keepid} -d --name cpcontainer $IMAGE sleep infinity
|
||||
run_podman cp -a=false - cpcontainer:/tmp/ < "${tmpdir}/a.tar"
|
||||
run_podman exec cpcontainer stat -c "%u:%g" /tmp/a.txt
|
||||
is "$output" "1042:1043" "copied file retains uid/gid from the tar"
|
||||
|
||||
@@ -87,6 +87,7 @@ load helpers
|
||||
|
||||
# #6829 : add username to /etc/passwd inside container if --userns=keep-id
|
||||
@test "podman exec - with keep-id" {
|
||||
skip_if_not_rootless "--userns=keep-id only works in rootless mode"
|
||||
# Multiple --userns options confirm command-line override (last one wins)
|
||||
run_podman run -d --userns=private --userns=keep-id $IMAGE sh -c \
|
||||
"echo READY;while [ ! -f /tmp/stop ]; do sleep 1; done"
|
||||
|
||||
@@ -182,13 +182,14 @@ EOF
|
||||
|
||||
run_podman volume rm $myvol
|
||||
|
||||
# Autocreated volumes should also work with keep-id
|
||||
# All we do here is check status; podman 1.9.1 would fail with EPERM
|
||||
myvol=myvol$(random_string)
|
||||
run_podman run --rm -v $myvol:/myvol:z --userns=keep-id $IMAGE \
|
||||
if is_rootless; then
|
||||
# Autocreated volumes should also work with keep-id
|
||||
# All we do here is check status; podman 1.9.1 would fail with EPERM
|
||||
myvol=myvol$(random_string)
|
||||
run_podman run --rm -v $myvol:/myvol:z --userns=keep-id $IMAGE \
|
||||
touch /myvol/myfile
|
||||
|
||||
run_podman volume rm $myvol
|
||||
run_podman volume rm $myvol
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -94,3 +94,17 @@ EOF
|
||||
is ${output} ${secret_content} "Secrets should work with user namespace"
|
||||
run_podman secret rm ${test_name}
|
||||
}
|
||||
|
||||
@test "podman userns=nomap" {
|
||||
skip_if_not_rootless "--userns=nomap only works in rootless mode"
|
||||
ns_user=$(id -un)
|
||||
baseuid=$(egrep "${ns_user}:" /etc/subuid | cut -f2 -d:)
|
||||
test ! -z ${baseuid} || skip "no IDs allocated for user ${ns_user}"
|
||||
|
||||
test_name="test_$(random_string 12)"
|
||||
run_podman run -d --userns=nomap $IMAGE sleep 100
|
||||
cid=${output}
|
||||
run_podman top ${cid} huser
|
||||
is "${output}" "HUSER.*${baseuid}" "Container should start with baseuid from /etc/subuid not user UID"
|
||||
run_podman rm -t 0 --force ${cid}
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ load helpers
|
||||
|
||||
# Issue #5466 - port-forwarding doesn't work with this option and -d
|
||||
@test "podman networking: port with --userns=keep-id" {
|
||||
skip_if_not_rootless "--userns=keep-id only works in rootless mode"
|
||||
for cidr in "" "$(random_rfc1918_subnet).0/24"; do
|
||||
myport=$(random_free_port 52000-52999)
|
||||
if [[ -z $cidr ]]; then
|
||||
|
||||
Reference in New Issue
Block a user