podman: `overlay`-mode containerization breaks `apt`: `Invalid cross-device link`
Is this a BUG REPORT or FEATURE REQUEST?
/kind bug
Description
Running apt install libreadline-dev in certain container results in apt bailing out with error:
unable to install new version of './usr/include/readline': Invalid cross-device link
This is not reproducible with fuse-overlayfs, it is only reproducible with overlay. Image/container required to reproduce it is docker.io/kkharlamov/bugreport-enomem image.
Steps to reproduce the issue:
- Make sure you’re in
overlaymode, e.g. runpodman info --debug | grep fuse-overlayfsand check that there’s no output.overlayrequires kernel 5.16.0 or higher - Run
podman run --rm -it docker.io/kkharlamov/bugreport-enomem /bin/zsh - In container, execute
apt install libreadline-dev
Describe the results you received:
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
gyp javascript-common libasan6:i386 libatomic1:i386 libboost-dev libboost1.65-dev libc-ares2 libc6-dev:i386 libgomp1:i386 libhttp-parser2.7.1 libitm1:i386 libjs-async libjs-inherits libjs-jquery libjs-node-uuid libjs-underscore libquadmath0:i386 libstdc++6:i386
libubsan1:i386 libuv1-dev libyaml-cpp0.5v5 linux-libc-dev:i386 nodejs-doc python-chardet python-pkg-resources
Use 'apt autoremove' to remove them.
Suggested packages:
readline-doc
The following NEW packages will be installed:
libreadline-dev
0 upgraded, 1 newly installed, 0 to remove and 148 not upgraded.
Need to get 133 kB of archives.
After this operation, 728 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu bionic/main amd64 libreadline-dev amd64 7.0-3 [133 kB]
Fetched 133 kB in 1s (190 kB/s)
debconf: delaying package configuration, since apt-utils is not installed
Selecting previously unselected package libreadline-dev:amd64.
(Reading database ... 156394 files and directories currently installed.)
Preparing to unpack .../libreadline-dev_7.0-3_amd64.deb ...
Unpacking libreadline-dev:amd64 (7.0-3) ...
dpkg: error processing archive /var/cache/apt/archives/libreadline-dev_7.0-3_amd64.deb (--unpack):
unable to install new version of './usr/include/readline': Invalid cross-device link
dpkg-deb: error: paste subprocess was killed by signal (Broken pipe)
Errors were encountered while processing:
/var/cache/apt/archives/libreadline-dev_7.0-3_amd64.deb
E: Sub-process /usr/bin/dpkg returned an error code (1)
Describe the results you expected:
No errors
Workarounds:
-
Create
~/.config/containers/storage.confwith content:[storage] [storage.options] mount_program = "/usr/bin/fuse-overlayfs" -
(WARNING: this step will remove all images) execute
podman system reset -f
Output of podman version:
Version: 3.4.4
API Version: 3.4.4
Go Version: go1.17.4
Git Commit: f6526ada1025c2e3f88745ba83b8b461ca659933
Built: Thu Dec 9 21:30:40 2021
OS/Arch: linux/amd64
Output of podman info --debug:
host:
arch: amd64
buildahVersion: 1.23.1
cgroupControllers:
- memory
- pids
cgroupManager: systemd
cgroupVersion: v2
conmon:
package: /usr/bin/conmon is owned by conmon 1:2.0.32-2
path: /usr/bin/conmon
version: 'conmon version 2.0.32, commit: 436b460d1586c2e4ab4e845448449ddd9136767a'
cpus: 4
distribution:
distribution: arch
version: unknown
eventLogger: journald
hostname: constantine-N61Ja
idMappings:
gidmap:
- container_id: 0
host_id: 1000
size: 1
- container_id: 1
host_id: 165536
size: 65536
uidmap:
- container_id: 0
host_id: 1000
size: 1
- container_id: 1
host_id: 165536
size: 65536
kernel: 5.16.0-zen1-1-zen
linkmode: dynamic
logDriver: journald
memFree: 374030336
memTotal: 8228016128
ociRuntime:
name: crun
package: /usr/bin/crun is owned by crun 1.4-1
path: /usr/bin/crun
version: |-
crun version 1.4
commit: 3daded072ef008ef0840e8eccb0b52a7efbd165d
spec: 1.0.0
+SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +CRIU +YAJL
os: linux
remoteSocket:
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: /etc/containers/seccomp.json
selinuxEnabled: false
serviceIsRemote: false
slirp4netns:
executable: /usr/bin/slirp4netns
package: /usr/bin/slirp4netns is owned by slirp4netns 1.1.12-1
version: |-
slirp4netns version 1.1.12
commit: 7a104a101aa3278a2152351a082a6df71f57c9a3
libslirp: 4.6.1
SLIRP_CONFIG_VERSION_MAX: 3
libseccomp: 2.5.3
swapFree: 6222995456
swapTotal: 8053059584
uptime: 91h 40m 56.28s (Approximately 3.79 days)
plugins:
log:
- k8s-file
- none
- journald
network:
- bridge
- macvlan
volume:
- local
registries:
search:
- docker.io
- registry.fedoraproject.org
- quay.io
- registry.access.redhat.com
- registry.centos.org
store:
configFile: /home/constantine/.config/containers/storage.conf
containerStore:
number: 0
paused: 0
running: 0
stopped: 0
graphDriverName: overlay
graphOptions: {}
graphRoot: /home/constantine/.local/share/containers/storage
graphStatus:
Backing Filesystem: btrfs
Native Overlay Diff: "true"
Supports d_type: "true"
Using metacopy: "false"
imageStore:
number: 0
runRoot: /run/user/1000/containers
volumePath: /home/constantine/.local/share/containers/storage/volumes
version:
APIVersion: 3.4.4
Built: 1639074640
BuiltTime: Thu Dec 9 21:30:40 2021
GitCommit: f6526ada1025c2e3f88745ba83b8b461ca659933
GoVersion: go1.17.4
OsArch: linux/amd64
Version: 3.4.4
Package info (e.g. output of rpm -q podman or apt list podman):
Name : podman
Version : 3.4.4-1
Description : Tool and library for running OCI-based containers in pods
Architecture : x86_64
URL : https://github.com/containers/podman
Licenses : Apache
Groups : None
Provides : None
Depends On : cni-plugins conmon containers-common crun fuse-overlayfs iptables libdevmapper.so=1.02-64 libgpgme.so=11-64 libseccomp.so=2-64 slirp4netns
Optional Deps : apparmor: for AppArmor support
btrfs-progs: support btrfs backend devices [installed]
catatonit: --init flag support
podman-docker: for Docker-compatible CLI
Required By : None
Optional For : None
Conflicts With : None
Replaces : None
Installed Size : 72.79 MiB
Packager : David Runge <dvzrv@archlinux.org>
Build Date : Чт 09 дек 2021 21:30:40
Install Date : Пт 17 дек 2021 23:29:19
Install Reason : Explicitly installed
Install Script : No
Validated By : Signature
Have you tested with the latest version of Podman and have you checked the Podman Troubleshooting Guide? (https://github.com/containers/podman/blob/main/troubleshooting.md)
Yes
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 15 (11 by maintainers)
Commits related to this issue
- Use storage that better supports rootless overlayfs overlayfs -- the kernel's version, not fuse-overlayfs -- recently learned (as of linux 5.16.0, I believe) how to support rootless users. Previously... — committed to gcalin/podman by kousu 2 years ago
- Use storage that better supports rootless overlayfs overlayfs -- the kernel's version, not fuse-overlayfs -- recently learned (as of linux 5.16.0, I believe) how to support rootless users. Previously... — committed to gcalin/podman by kousu 2 years ago
- Use storage that better supports rootless overlayfs overlayfs -- the kernel's version, not fuse-overlayfs -- recently learned (as of linux 5.16.0, I believe) how to support rootless users. Previously... — committed to gcalin/podman by kousu 2 years ago
- Add option for pod logs to display different colors per container. Signed-off-by: Krzysztof Baran <krysbaran@gmail.com> Signed-off-by: Calin Georgescu <caling@protonmail.com> Improve the error messag... — committed to gcalin/podman by gcalin 2 years ago
- Use storage that better supports rootless overlayfs overlayfs -- the kernel's version, not fuse-overlayfs -- recently learned (as of linux 5.16.0, I believe) how to support rootless users. Previously... — committed to gcalin/podman by kousu 2 years ago
- Use storage that better supports rootless overlayfs overlayfs -- the kernel's version, not fuse-overlayfs -- recently learned (as of linux 5.16.0, I believe) how to support rootless users. Previously... — committed to gcalin/podman by kousu 2 years ago
- Use storage that better supports rootless overlayfs overlayfs -- the kernel's version, not fuse-overlayfs -- recently learned (as of linux 5.16.0, I believe) how to support rootless users. Previously... — committed to gcalin/podman by kousu 2 years ago
- Use storage that better supports rootless overlayfs overlayfs -- the kernel's version, not fuse-overlayfs -- recently learned (as of linux 5.16.0, I believe) how to support rootless users. Previously... — committed to gcalin/podman by kousu 2 years ago
- Use storage that better supports rootless overlayfs overlayfs -- the kernel's version, not fuse-overlayfs -- recently learned (as of linux 5.16.0, I believe) how to support rootless users. Previously... — committed to gcalin/podman by kousu 2 years ago
- Use storage that better supports rootless overlayfs overlayfs -- the kernel's version, not fuse-overlayfs -- recently learned (as of linux 5.16.0, I believe) how to support rootless users. Previously... — committed to gcalin/podman by kousu 2 years ago
- Use storage that better supports rootless overlayfs overlayfs -- the kernel's version, not fuse-overlayfs -- recently learned (as of linux 5.16.0, I believe) how to support rootless users. Previously... — committed to gcalin/podman by kousu 2 years ago
- Use storage that better supports rootless overlayfs overlayfs -- the kernel's version, not fuse-overlayfs -- recently learned (as of linux 5.16.0, I believe) how to support rootless users. Previously... — committed to gcalin/podman by kousu 2 years ago
- Use storage that better supports rootless overlayfs overlayfs -- the kernel's version, not fuse-overlayfs -- recently learned (as of linux 5.16.0, I believe) how to support rootless users. Previously... — committed to gbraad-redhat/podman by kousu 2 years ago
This is sort of beating the horse dead, but I have only been working on this in my spare time, and I want to be sure. I got stumped on https://github.com/containers/podman/issues/13432 too…
but anyway now I’ve been able to work out a minimal reproducer the replicates your bug without having to download anything, which shows that the issue really is the many layers:
I made a username with 3 characters in it (because https://github.com/containers/podman/issues/13432 showed me that 5 wouldn’t work at the moment).
A shorter or longer name will change the precise number of layers where the problem appears. With
USER=tst, it happens to appear at layer 50:Whereas layer 49 doesn’t have the problem:
To see that #13375 fixed it, build that version:
Then test using the fixed version:
and it finishes without error.
Thanks for this clue! I sat down with this again last night and was able to trace it out. There’s an oversight in storage.drivers.overlay that is only triggered when using
overlayfsdriverHere’s how I traced this out.
Symptoms
I took note that my
lower_layercreated by myrepro.sh(https://github.com/containers/podman/issues/13123#issuecomment-1047609910) and @Hi-Angel’s behaved differently: mine can runaptand make and rename folders (though it can’t rename a preexisting folder, one created in a lower overlay layer):but his fails on any
aptattempt because (as noted above https://github.com/containers/podman/issues/13123#issuecomment-1028789380)rename()fails – even on folders made in the top layer:I went searching for why.
Inspecting
I read up on user_namespaces(7) and I figured out with both containers running I could inspect “under their floorboards” by with by
nsentering their kernel namespace:What immediately stuck out:
I can see both containers’ mounts here, so podman must be sharing a single namespace between all containers.
Good to know though not directly relevant.
I can tell the first line is the smaller container (
lower_layer) because it is shorter – it has less layers to mount thandocker.io/kkharlamov/bugreport-enomem.I also confirmed this by
mktemping some files in each container and checking I could see the matching names viansenter -U -m -t 2950 ls /home/kousu/.local/share/containers/storage/overlay/*/merged/tmpThe smaller container was mounted with absolute paths, but the smaller one seems to be using relative paths.
The smaller container has
volatile,userxattr, but the larger container doesn’t.This last point confused me, so I used
strace -f -o container.trace podman run --rm -it docker.io/kkharlamov/bugreport-enomemto look closer, and found that indeed there was achdir()that went withmount():Root Cause
I read in https://www.kernel.org/doc/html/latest/filesystems/overlayfs.html that
I skimmed the rest of those docs and I still don’t really understand it all, except that indeed, overlayfs has to handle
rename()intricately, and that rootless mode needsuserxattr, so losing it must be the cause.But I wondered why
volatilewas also missing. And that was the string I pulled on to unravel the mystery.Tracing the Code
so
volatileis added because I passed--rm; but that didn’t seem to have anything to do with the bug. And sometimes in my experience that sort of counterintuitive connection is exactly what you need to highlight the relevant clues. I kept looking throughgit grep volatileand well, long story short, that word doesn’t show up that often, and I narrowed down where both flags get added:https://github.com/containers/podman/blob/86a057e6be434159e3e60add5a7a7d649e0b4ad5/vendor/github.com/containers/storage/drivers/overlay/overlay.go#L1471-L1484
and, 👏 to the podman team, just below there’s this comment which precisely fits the symptoms above:
https://github.com/containers/podman/blob/86a057e6be434159e3e60add5a7a7d649e0b4ad5/vendor/github.com/containers/storage/drivers/overlay/overlay.go#L1492-L1495
and the code that implements that comment overwrites
optshttps://github.com/containers/podman/blob/86a057e6be434159e3e60add5a7a7d649e0b4ad5/vendor/github.com/containers/storage/drivers/overlay/overlay.go#L1521-L1529
which fits the final symptom
volatileanduserxattrTa-dah
So, that was the bug. https://github.com/containers/podman/pull/13375 should fix it, and you should be able to use your container without
fuse-overlayfs, @Hi-Angel. Thanks for helping me solve it! “modified during 1.5 years by installing various packages and executing apodman commit” gave me exactly the insight I needed.