| Tested on | Red Hat Enterprise Linux 10.2 (Coughlan) |
|---|---|
| Package | podman-5.8.2-5.el10_2.x86_64 |
| Applies to | Any Linux host with rootless Podman |
| Privilege | Rootless examples as podtest; rootful error demo with sudo podman |
| Scope | The podman unshare command — user namespace entry, uid_map inspection, host vs namespace file ownership, podman unshare chown, rootless podman mount, stopped-container filesystem edits, --rootless-netns, exit codes, and rootful failure. Does not cover subuid provisioning, full --userns modes, SELinux diagnosis, or the complete volume permission tree. |
| Related guides | Podman volumes |
Rootless Podman maps container UIDs through a user namespace. A file that looks like 984038 in your normal shell can look like 999 inside Podman's namespace — same inode, different numeric view. podman unshare drops you into that namespace so you can inspect mappings, fix ownership with container-visible IDs, and reach rootless mount points your host shell cannot see.
This guide focuses on the command itself. For the full permission diagnostic tree, start with Fix Podman volume permission denied. For --userns mode theory, see Podman user namespaces.
The lab user is podtest for every rootless example.
What does podman unshare do?
Run a command inside Podman's rootless user namespace:
podman unshare iduid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:container_runtime_t:s0-s0:c0.c1023That uid=0(root) is root inside the rootless user's user namespace — not host UID 0. Your normal shell still runs as podtest; podman unshare is a separate view:
normal host shell
UID 1014
│
▼
podman unshare
UID 0 inside rootless namespace
│
├── maps back to host UID 1014
└── subordinate IDs map additional container userspodman unshare executes one command (or starts a shell) with the same ID mapping rootless containers use. These examples use Podman's normal rootless mapping. Containers created with explicit --userns modes can have additional mapping behavior; see the user-namespace guide for those cases.
Inspect UID and GID maps
Each /proc/self/uid_map line has three columns: namespace start, host start, length.
Read the mapping inside unshare:
podman unshare cat /proc/self/uid_map0 1014 1
1 983040 65536GID mapping uses the same layout:
podman unshare cat /proc/self/gid_map0 1015 1
1 983040 65536On this host, namespace UID 0 maps to host 1014, and namespace UIDs 1–65536 draw from the subordinate pool starting at 983040. Those pools come from /etc/subuid and /etc/subgid:
grep '^podtest:' /etc/subuid /etc/subgid/etc/subuid:podtest:983040:65536
/etc/subgid:podtest:983040:65536Provisioning subordinate ranges belongs in Rootless Podman. Here you only need to read the maps unshare exposes.
See file ownership as Podman sees it
Create a file through a container running as UID 999, then compare host and namespace views.
Prepare a writable directory and create the file from a container:
mkdir -p ~/unshare-demo/data && chmod 777 ~/unshare-demo/dataCreate the file as container UID 999 through a bind mount:
podman run --rm --user 999 -v ~/unshare-demo/data:/data:Z docker.io/library/alpine:3.20 touch /data/exampleFrom your normal shell the owner is a subordinate host UID:
ls -ln ~/unshare-demo/data/total 0
-rw-r--r--. 1 984038 1015 0 Aug 23 01:07 exampleInside unshare, the same inode shows container UID 999:
podman unshare ls -ln ~/unshare-demo/data/total 0
-rw-r--r--. 1 999 0 0 Aug 23 01:07 exampleBoth listings describe the same file. The host kernel stores the mapped host ID (984038 = 983040 + 998); podman unshare shows the ID the container namespace uses. That difference is why permission fixes need namespace-aware tools.
Fix rootless ownership with podman unshare chown
You could compute subuid start + container UID by hand. podman unshare chown is simpler — you pass the container-visible ID and Podman applies the mapping.
Set ownership using container UID 999:
podman unshare chown 999:999 ~/unshare-demo/data/exampleInside the namespace the owner now matches what a UID 999 process expects:
podman unshare ls -ln ~/unshare-demo/data/total 0
-rw-r--r--. 1 999 999 0 Aug 23 01:07 exampleOn the host the kernel still stores subordinate numbers — both owner and group shifted together:
ls -ln ~/unshare-demo/data/total 0
-rw-r--r--. 1 984038 984038 0 Aug 23 01:07 exampleThe metadata on disk changed. This is not a virtual view — chown through unshare updates real host ownership using Podman's namespace translation.
Recursively fix a directory
Apply the same pattern to a tree when every file should belong to container UID 999:
podman unshare chown -R 999:999 ~/unshare-demo/data/Confirm every path now shows UID 999 inside the namespace:
podman unshare ls -lnR ~/unshare-demo/data//home/podtest/unshare-demo/data/:
total 0
-rw-r--r--. 1 999 999 0 Aug 23 01:07 example
drwxr-xr-x. 2 999 999 6 Aug 23 01:07 sub
/home/podtest/unshare-demo/data/sub:
total 0Recursive chown rewrites host filesystem metadata for every matched path. On large or shared trees that can be slow and disruptive — prefer targeted chown on the paths you know are wrong. When you are unsure which layer blocks access, diagnose first in Fix Podman volume permission denied instead of blanket chown -R on /home or application data.
podman unshare chown vs :U
Both change real host ownership — neither is a display-only trick.
podman unshare chown |
:U mount option |
|---|---|
| explicit administrative action | automatic adjustment at mount time |
| you choose exact target IDs | derives ownership from the container user |
easy to inspect before and after with unshare ls |
convenient but can recursively modify the source tree |
| change persists after the command | change persists after the container stops |
Use unshare chown when you need a specific container UID/GID and want to verify the result in both namespaces. Use :U when mount-time adjustment is acceptable. SELinux and mode-bit diagnosis still belong in the volume permissions guide.
Inspect a rootless container filesystem with podman mount
podman mount exposes a container's merged root filesystem on disk. Rootless Podman requires the mount namespace that unshare provides.
Create a stopped container for the demo:
podman create --name unshare-mount-demo docker.io/library/alpine:3.20 sleep 3600From a normal shell, rootless podman mount refuses to run:
podman mount unshare-mount-demoError: cannot run command "podman mount" in rootless mode, must execute `podman unshare` firstThe mount must happen inside the rootless namespace.
Use podman mount inside podman unshare
Run mount and list in one unshare invocation so the mount namespace stays valid:
podman unshare sh -c 'mnt=$(podman mount unshare-mount-demo); echo "MOUNT=$mnt"; ls -la "$mnt/etc/hostname"'MOUNT=/home/podtest/.local/share/containers/storage/overlay/025c855d0d69e01142dc3e1e6e0a0336a21472ac9a068baa833946adc46cdd2e/merged
-rw-r--r--. 1 root root 10 May 6 2024 /home/podtest/.local/share/containers/storage/overlay/025c855d0d69e01142dc3e1e6e0a0336a21472ac9a068baa833946adc46cdd2e/merged/etc/hostnameYou can also start an interactive shell with podman unshare and run podman mount CONTAINER from inside it. Either way, inspect files in the same session — do not copy the path to a normal shell and expect it to work.
Why rootless podman mount is invisible outside the namespace
Rootless Podman cannot attach overlay mounts into the host's initial mount namespace with host-root privileges. The merged path exists only inside Podman's user/mount namespace:
host shell namespace
≠
podman unshare mount namespaceCapture the path from unshare, then try the same path from your login shell:
podman unshare sh -c 'podman mount unshare-mount-demo'/home/podtest/.local/share/containers/storage/overlay/025c855d0d69e01142dc3e1e6e0a0336a21472ac9a068baa833946adc46cdd2e/mergedThe same path string from your login shell cannot see the mount:
ls /home/podtest/.local/share/containers/storage/overlay/025c855d0d69e01142dc3e1e6e0a0336a21472ac9a068baa833946adc46cdd2e/merged/etc/hostnamels: cannot access '/home/podtest/.local/share/containers/storage/overlay/025c855d0d69e01142dc3e1e6e0a0336a21472ac9a068baa833946adc46cdd2e/merged/etc/hostname': No such file or directoryThe string path is real; the mount is not visible outside unshare. That is expected rootless behavior, not a broken path.
Modify a stopped container's filesystem
A practical pattern: mount, edit the writable layer, unmount, then start the container.
podman unshare sh -c 'mnt=$(podman mount unshare-mount-demo); echo modified > "$mnt/tmp/unshare-test"; podman unmount unshare-mount-demo'Start the container and read the file from inside:
podman start unshare-mount-demoRead the file from inside the running container:
podman exec unshare-mount-demo cat /tmp/unshare-testmodifiedYou changed the container's writable layer — not the image itself. Useful for forensic inspection, repairing config, or retrieving data when a container will not start. Do not treat this as a routine way to patch production images.
Clean up when finished:
podman rm -f unshare-mount-demoUnmount the container filesystem
Release the overlay mount when you no longer need the path:
podman unshare podman unmount CONTAINEROr run podman unmount CONTAINER from inside an unshare shell. Leaving mounts attached serves no purpose and can confuse later maintenance. After unmount, podman mount CONTAINER must be run again before the merged path is available.
Enter the rootless network namespace
On Podman 5.8.2, --rootless-netns joins the rootless network namespace Netavark uses for bridge networking.
List addresses from that namespace:
podman unshare --rootless-netns ip -br addrlo UNKNOWN 127.0.0.1/8 ::1/128
enp0s3 UNKNOWN 10.0.2.15/24 fd17:625c:f037:2:a00:27ff:fe2d:cd83/64 fe80::ccd3:f6ff:fe89:e46a/64
podman1 UP 10.89.0.1/24 fe80::b4f2:1bff:fe4e:761a/64
veth0@if2 UP fe80::744e:d3ff:fe73:b7ce/64Routing table from the same namespace:
podman unshare --rootless-netns ip routedefault via 10.0.2.2 dev enp0s3 proto dhcp metric 116
10.0.2.0/24 dev enp0s3 proto kernel scope link metric 116
10.89.0.0/24 dev podman1 proto kernel scope link src 10.89.0.1Use this to inspect podman1, veth pairs, and bridge routes without guessing from the host namespace. Full pasta and bridge behavior lives in Rootless Podman networking.
Reach a rootless bridge container by IP
Create a user bridge network first:
podman network create unshare-bridgeStart a long-lived container on that bridge so you can read its IP:
podman run -d --name netns-demo --network unshare-bridge docker.io/library/alpine:3.20 sleep 600The inspect template prints the address Podman assigned:
podman inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' netns-demo10.89.0.2From the host's normal namespace, ping often fails even though the container is running:
ping -c1 -W1 10.89.0.2PING 10.89.0.2 (10.89.0.2) 56(84) bytes of data.
--- 10.89.0.2 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0msThe same address responds inside --rootless-netns:
podman unshare --rootless-netns ping -c1 -W2 10.89.0.2PING 10.89.0.2 (10.89.0.2) 56(84) bytes of data.
64 bytes from 10.89.0.2: icmp_seq=1 ttl=64 time=0.192 ms
--- 10.89.0.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.192/0.192/0.192/0.000 msThat is when --rootless-netns earns its place — debugging connectivity to bridge IPs the host namespace cannot reach directly.
Remove the demo container and network:
podman rm -f netns-demoDrop the bridge network once the container is gone:
podman network rm unshare-bridgepodman unshare is rootless-only
Rootful Podman does not provide this helper — root already has the privileges needed for host-namespace storage and mount operations:
sudo podman unshare idError: please use unshare with rootlessRun podman unshare, podman unshare chown, and podman unshare ls as the same unprivileged account that owns the rootless containers.
podman unshare is not available remotely
podman unshare manipulates namespaces on the local Linux host. The remote Podman client cannot enter your machine's user or mount namespaces over SSH. Run unshare on the host where rootless Podman stores containers, or SSH in as the rootless user and execute it there.
Environment variables inside podman unshare
Podman exports storage paths inside the namespace — useful for scripts that must target the correct rootless store:
podman unshare env | grep '^CONTAINERS_'CONTAINERS_GRAPHROOT=/home/podtest/.local/share/containers/storage
CONTAINERS_RUNROOT=/run/user/1014/containersCONTAINERS_GRAPHROOT is the images-and-layers store; CONTAINERS_RUNROOT is the runtime state directory. Read them for context; do not hand-edit storage internals. Path layout details live in Podman storage location.
podman unshare exit codes
Exit status follows the usual Podman conventions:
125— Podman command error (invalid subcommand or flag)126— command exists but cannot be invoked127— command not found insideunshare- otherwise — the child command's exit status
A failing child command returns its own code — podman unshare false prints nothing and exits 1.
An unknown executable returns 127:
podman unshare nosuchcmd999Error: exec: "nosuchcmd999": executable file not found in $PATHPodman itself returns 125 when the wrapped command fails at the Podman layer:
podman unshare podman invalidsubError: unrecognized command `podman invalidsub`
Try 'podman --help' for more informationWhen should you use podman unshare?
| Problem | Useful command |
|---|---|
| understand rootless UID mapping | podman unshare cat /proc/self/uid_map |
| inspect mapped ownership | podman unshare ls -ln |
| fix mapped ownership | podman unshare chown |
| inspect rootless mounted rootfs | podman unshare + podman mount |
| inspect rootless bridge namespace | podman unshare --rootless-netns |
| fix general SELinux denial | diagnose in volume permissions guide, not primarily unshare |
References
Summary
podman unshare is how you step into the same user namespace rootless Podman uses. Inside it you appear as namespace UID 0, but you still map to your normal host account — not host root. That is the view you need when a bind mount shows 984038 on the host and 999 inside a container: same inode, different numeric translation.
The highest-value operations are inspection and repair. Read uid_map and gid_map, compare ls -ln from your shell versus podman unshare ls -ln, and fix ownership with podman unshare chown using container-visible IDs instead of hand-calculating subordinate offsets. For filesystem surgery on a stopped container, run podman mount inside unshare — the merged path is not usable from a normal host shell even when the path string looks familiar.
--rootless-netns solves a different problem: reaching bridge-network container IPs that the host namespace cannot ping. Rootful Podman rejects unshare outright with please use unshare with rootless. When SELinux, mode bits, or mount-flag questions dominate, start with the volume permissions guide; use this page when the namespace mapping itself is what you need to see or change.

