containers / podman

Podman: A tool for managing OCI containers and pods.
https://podman.io
Apache License 2.0
22.36k stars 2.31k forks source link

Error: writing file `/proc/450976/gid_map`: Operation not permitted: OCI permission denied #23109

Closed leiless closed 4 days ago

leiless commented 4 days ago

Issue Description

When running a simple podman run command, I get an error: Error: writing file/proc/450976/gid_map: Operation not permitted: OCI permission denied.

Steps to reproduce the issue

Steps to reproduce the issue

1. The Dockerfile

FROM alpine:3.20

RUN set -eufxo pipefail && \
    apk add --no-cache shadow && \
    useradd --create-home --shell /bin/sh --uid 1000 nonroot && \
    apk del --no-cache shadow

USER nonroot
WORKDIR /home/nonroot

2. Build the image

$ docker build --rm -t local/podman-alpine-regular-user-image .
STEP 1/4: FROM alpine:3.20
STEP 2/4: RUN set -eufxo pipefail &&     apk add --no-cache shadow &&     useradd --create-home --shell /bin/sh --uid 1000 nonroot &&     apk del --no-cache shadow
--> Using cache 85e30b988ebe5be98798bc2dc018bda37c74a6ce8d9d13e8bbd82465bebd241f
--> 85e30b988eb
STEP 3/4: USER nonroot
--> Using cache 2948b248eeacb1ed47636fe251d7ee2731726b5913ef6644efc18be2adb68141
--> 2948b248eea
STEP 4/4: WORKDIR /home/nonroot
--> Using cache 01f9615514e0cc48ed321993cd635e910aa2ec7a380e4502b13c9d36d0ddde73
COMMIT local/podman-alpine-regular-user-image
--> 01f9615514e
Successfully tagged localhost/local/podman-alpine-regular-user-image:latest
01f9615514e0cc48ed321993cd635e910aa2ec7a380e4502b13c9d36d0ddde73

3. Script to run the container

#!/bin/bash

set -eufo pipefail

CONTAINER_UID=1000
CONTAINER_GID=1000

UID_MAP=$(id -u "$USER")
GID_MAP=$(id -g "$USER")
SUBUID_MAP_FROM=$(grep -w "^$USER" /etc/subuid | cut -d: -f2)
SUBUID_MAP_N=$(grep -w "^$USER" /etc/subuid | cut -d: -f3)
SUBGID_MAP_FROM=$(grep -w "^$USER" /etc/subgid | cut -d: -f2)
SUBGID_MAP_N=$(grep -w "^$USER" /etc/subgid | cut -d: -f3)

echo $CONTAINER_UID $CONTAINER_GID $UID_MAP $GID_MAP $SUBUID_MAP_FROM $SUBUID_MAP_N $SUBGID_MAP_FROM $SUBGID_MAP_N

# gid=42 is the "shadow" group
docker run -it --rm \
    -v "$HOME/.local/share":/test \
    -w /test \
    --uidmap="$CONTAINER_UID:$UID_MAP:1" \
    --uidmap="$((CONTAINER_UID + 1)):$SUBUID_MAP_FROM:$SUBUID_MAP_N" \
    --gidmap="$CONTAINER_GID:$GID_MAP:1" \
    --gidmap="$((CONTAINER_GID + 1)):$SUBGID_MAP_FROM:$SUBGID_MAP_N" \
    --uidmap="0:0:1" \
    --gidmap="0:0:1" \
    --gidmap="42:42:1" \
    local/podman-alpine-regular-user-image

Describe the results you received

$ ./run-container.sh
1000 1000 1000 1000 100000 65536 100000 65536
Error: writing file `/proc/450976/gid_map`: Operation not permitted: OCI permission denied

Describe the results you expected

I expect the podman container run successfully.

podman info output

$ uname -a
Linux DESKTOP-xxxxxxx 5.15.133.1-microsoft-standard-WSL2 #1 SMP Thu Oct 5 21:02:42 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

$ cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.4 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.4 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy

$ podman version
Version:      3.4.4
API Version:  3.4.4
Go Version:   go1.18.1
Built:        Thu Jan  1 08:00:00 1970
OS/Arch:      linux/amd64

$ podman info
host:
  arch: amd64
  buildahVersion: 1.23.1
  cgroupControllers: []
  cgroupManager: cgroupfs
  cgroupVersion: v1
  conmon:
    package: 'conmon: /usr/bin/conmon'
    path: /usr/bin/conmon
    version: 'conmon version 2.0.25, commit: unknown'
  cpus: 12
  distribution:
    codename: jammy
    distribution: ubuntu
    version: "22.04"
  eventLogger: journald
  hostname: DESKTOP-xxxxxxx
  idMappings:
    gidmap:
    - container_id: 0
      host_id: 1000
      size: 1
    - container_id: 1
      host_id: 100000
      size: 65536
    uidmap:
    - container_id: 0
      host_id: 1000
      size: 1
    - container_id: 1
      host_id: 100000
      size: 65536
  kernel: 5.15.133.1-microsoft-standard-WSL2
  linkmode: dynamic
  logDriver: journald
  memFree: 216285184
  memTotal: 8159125504
  ociRuntime:
    name: crun
    package: 'crun: /usr/bin/crun'
    path: /usr/bin/crun
    version: |-
      crun version 0.17
      commit: 0e9229ae34caaebcb86f1fde18de3acaf18c6d9a
      spec: 1.0.0
      +SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +YAJL
  os: linux
  remoteSocket:
    exists: true
    path: /run/user/1000/podman/podman.sock
  security:
    apparmorEnabled: false
    capabilities: CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FOWNER,CAP_FSETID,CAP_KILL,CAP_NET_BIND_SERVICE,CAP_SETFCAP,CAP_SETGID,CAP_SETPCAP,CAP_SETUID,CAP_SYS_CHROOT
    rootless: true
    seccompEnabled: true
    seccompProfilePath: /usr/share/containers/seccomp.json
    selinuxEnabled: false
  serviceIsRemote: false
  slirp4netns:
    executable: /usr/bin/slirp4netns
    package: 'slirp4netns: /usr/bin/slirp4netns'
    version: |-
      slirp4netns version 1.0.1
      commit: 6a7b16babc95b6a3056b33fb45b74a6f62262dd4
      libslirp: 4.6.1
  swapFree: 2106605568
  swapTotal: 2147483648
  uptime: 59h 6m 53.31s (Approximately 2.46 days)
plugins:
  log:
  - k8s-file
  - none
  - journald
  network:
  - bridge
  - macvlan
  volume:
  - local
registries: {}
store:
  configFile: /home/lei/.config/containers/storage.conf
  containerStore:
    number: 0
    paused: 0
    running: 0
    stopped: 0
  graphDriverName: overlay
  graphOptions: {}
  graphRoot: /home/lei/.local/share/containers/storage
  graphStatus:
    Backing Filesystem: extfs
    Native Overlay Diff: "true"
    Supports d_type: "true"
    Using metacopy: "false"
  imageStore:
    number: 176
  runRoot: /run/user/1000/containers
  volumePath: /home/lei/.local/share/containers/storage/volumes
version:
  APIVersion: 3.4.4
  Built: 0
  BuiltTime: Thu Jan  1 08:00:00 1970
  GitCommit: ""
  GoVersion: go1.18.1
  OsArch: linux/amd64
  Version: 3.4.4

Podman in a container

No

Privileged Or Rootless

Rootless

Upstream Latest Release

No

Additional environment details

Additional environment details

Additional information

I'm not using SELinux and AppArmor.

Luap99 commented 4 days ago

First podman 3.4 is super outdated and we only support the latest version upstream.

However I do not see how you mapping can ever be valid. Rootless podman already runs inside the user namesapce setup according to the subuid/subgid files so the mapping for the container is relative to this (see podman unshare cat /proc/self/uid_map /proc/self/gid_map). This means $SUBGID_MAP_FROM would actully need to be 1 here

Sounds like you are trying to do a mapping similat to userns keep-id

$ podman run --userns keep-id quay.io/libpod/testimage:20240123 cat /proc/self/uid_map 
         0          1       1000
      1000          0          1
      1001       1001      64536
leiless commented 4 days ago

@Luap99 What if the container UID:GID is not the same as the the current rootless user’s UID:GID?

The --userns keep-id would not work in this way.

Luap99 commented 4 days ago

You can pass uid,git to keep-id on newer versions https://github.com/containers/podman/blob/main/troubleshooting.md#39-podman-run-fails-with-error-unrecognized-namespace-mode-keep-iduid1000gid1000-passed

leiless commented 4 days ago

Solution for Podman < v4.3.0

https://github.com/containers/podman/blob/main/troubleshooting.md#solution-36

FROM alpine:3.20

ARG NEW_UID=65532
ARG NEW_GID=65532

RUN set -eufxo pipefail && \
    apk add --no-cache shadow && \
    groupadd --gid $NEW_GID nonroot && \
    useradd --create-home --shell /bin/sh --uid $NEW_UID --gid $NEW_GID nonroot && \
    apk del --no-cache shadow

USER nonroot
WORKDIR /home/nonroot
docker build --rm -t local/podman-alpine-regular-user-image .
CONTAINER_UID=65532
CONTAINER_GID=65532
SUBUID_SIZE=$(grep -w "^$USER" /etc/subuid | cut -d: -f3)
SUBGID_SIZE=$(grep -w "^$USER" /etc/subgid | cut -d: -f3)

set -x

podman run -it --rm \
    -v "$HOME/.local/share":/test \
    -w /test \
    --user $CONTAINER_UID:$CONTAINER_GID \
    --uidmap 0:1:$CONTAINER_UID \
    --uidmap $CONTAINER_UID:0:1 \
    --uidmap $((CONTAINER_UID+1)):$((CONTAINER_UID+1)):$((SUBUID_SIZE-CONTAINER_UID)) \
    --gidmap 0:1:$CONTAINER_GID \
    --gidmap $CONTAINER_GID:0:1 \
    --gidmap $((CONTAINER_GID+1)):$((CONTAINER_GID+1)):$((SUBGID_SIZE-CONTAINER_GID)) \
    local/podman-alpine-regular-user-image

+ podman run -it --rm -v /home/lei/.local/share:/test -w /test --user 65532:65532 --uidmap 0:1:65532 --uidmap 65532:0:1 --uidmap 65533:65533:4 --gidmap 0:1:65532 --gidmap 65532:0:1 --gidmap 65533:65533:4 local/podman-alpine-regular-user-image

/test $ ls -ld man
drwxr-xr-x    3 nonroot  nonroot       4096 May 13 01:17 man
/test $ whoami
nonroot
/test $ id -u nonroot
65532
/test $ id -g nonroot
65532
/test $ cat /proc/self/uid_map
         0          1      65532
     65532          0          1
     65533      65533          4
/test $ cat /proc/self/gid_map
         0          1      65532
     65532          0          1
     65533      65533          4

FYI, -user $CONTAINER_UID:$CONTAINER_GID is optional, since we already changed user to nonroot in Dockerfile, so the default container uid:gid is nonroot:nonroot.

leiless commented 4 days ago

https://docs.podman.io/en/v3.4.4/markdown/podman-run.1.html?highlight=uidmap#uidmap-container-uid-from-uid-amount

@Luap99 Hi again, after checking the uidmap docs, I still don't understand how those uid/gid mappings works in podman. Especially:

--uidmap 0:1:$CONTAINER_UID \
--uidmap $CONTAINER_UID:0:1 \
--uidmap $((CONTAINER_UID+1)):$((CONTAINER_UID+1)):$((SUBUID_SIZE-CONTAINER_UID)) \
--gidmap 0:1:$CONTAINER_GID \
--gidmap $CONTAINER_GID:0:1 \
--gidmap $((CONTAINER_GID+1)):$((CONTAINER_GID+1)):$((SUBGID_SIZE-CONTAINER_GID)) \

Could you explain this to me? 🥹