I am including a script that demonstrates the issue.
To be more specific, unpacking a tar archive in the container, onto a host mounted filesystem, where the container has a symlink referencing a parent, fails in a way that does not yield similar behavior on a Linux host. This appears to be new since upgrading to podman 5.8 on MacOS.
I think the crux of the issue is that the link isn't created. It's not that it would not be supported to create the link. It's that a peculiar file is created by the openat call even though it returns an error.
There ought to have been a symlink created.
While this isn't podman output, this is the strace from within the container.
execve("/usr/bin/tar", ["tar", "xf", "project.tar"], 0xffffe84a5360 /* 7 vars */) = 0
brk(NULL) = 0xaaaaadf09000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xffff9ccd8000
faccessat(AT_FDCWD, "/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=4211, ...}) = 0
mmap(NULL, 4211, PROT_READ, MAP_PRIVATE, 3, 0) = 0xffff9ccd6000
close(3) = 0
openat(AT_FDCWD, "/lib/aarch64-linux-gnu/libacl.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0\267\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=67512, ...}) = 0
mmap(NULL, 196656, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_DENYWRITE, -1, 0) = 0xffff9cc71000
mmap(0xffff9cc80000, 131120, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0xffff9cc80000
munmap(0xffff9cc71000, 61440) = 0
munmap(0xffff9cca1000, 48) = 0
mprotect(0xffff9cc88000, 94208, PROT_NONE) = 0
mmap(0xffff9cc9f000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0xf000) = 0xffff9cc9f000
close(3) = 0
openat(AT_FDCWD, "/lib/aarch64-linux-gnu/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0\267\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=264424, ...}) = 0
mmap(NULL, 403000, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_DENYWRITE, -1, 0) = 0xffff9cc1d000
mmap(0xffff9cc20000, 337464, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0xffff9cc20000
munmap(0xffff9cc1d000, 12288) = 0
munmap(0xffff9cc73000, 50744) = 0
mprotect(0xffff9cc51000, 122880, PROT_NONE) = 0
mmap(0xffff9cc6f000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x3f000) = 0xffff9cc6f000
mmap(0xffff9cc71000, 5688, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xffff9cc71000
close(3) = 0
openat(AT_FDCWD, "/lib/aarch64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0\267\0\1\0\0\0\200$\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1716616, ...}) = 0
mmap(NULL, 1892368, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_DENYWRITE, -1, 0) = 0xffff9ca51000
mmap(0xffff9ca60000, 1826832, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0xffff9ca60000
munmap(0xffff9ca51000, 61440) = 0
munmap(0xffff9cc1f000, 16) = 0
mprotect(0xffff9cbfc000, 69632, PROT_NONE) = 0
mmap(0xffff9cc0d000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19d000) = 0xffff9cc0d000
mmap(0xffff9cc12000, 49168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xffff9cc12000
close(3) = 0
openat(AT_FDCWD, "/lib/aarch64-linux-gnu/libpcre2-8.so.0", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0\267\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0644, st_size=657952, ...}) = 0
mmap(NULL, 787080, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_DENYWRITE, -1, 0) = 0xffff9c99f000
mmap(0xffff9c9a0000, 721544, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0xffff9c9a0000
munmap(0xffff9c99f000, 4096) = 0
munmap(0xffff9ca51000, 57992) = 0
mprotect(0xffff9ca36000, 102400, PROT_NONE) = 0
mmap(0xffff9ca4f000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x9f000) = 0xffff9ca4f000
close(3) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xffff9ccd4000
set_tid_address(0xffff9ccd4ad0) = 57
set_robust_list(0xffff9ccd4ae0, 24) = 0
rseq(0xffff9ccd52c0, 0x20, 0, 0xd428bc00) = 0
mprotect(0xffff9cc0d000, 12288, PROT_READ) = 0
mprotect(0xffff9ca4f000, 4096, PROT_READ) = 0
mprotect(0xffff9cc6f000, 4096, PROT_READ) = 0
mprotect(0xffff9cc9f000, 4096, PROT_READ) = 0
mprotect(0xaaaaac79e000, 8192, PROT_READ) = 0
mprotect(0xffff9cce0000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
munmap(0xffff9ccd6000, 4211) = 0
statfs("/sys/fs/selinux", {f_type=TMPFS_MAGIC, f_bsize=4096, f_blocks=49742, f_bfree=49257, f_bavail=49257, f_files=49742, f_ffree=48796, f_fsid={val=[0x25f4f7c7, 0x5f477812]}, f_namelen=255, f_frsize=4096, f_flags=ST_VALID|ST_RDONLY|ST_NOSUID|ST_NODEV|ST_RELATIME}) = 0
statfs("/selinux", 0xfffffca8a310) = -1 ENOENT (No such file or directory)
getrandom("\x63\x71\x3b\x05\xfe\x1a\x3b\xa5", 8, GRND_NONBLOCK) = 8
brk(NULL) = 0xaaaaadf09000
brk(0xaaaaadf2a000) = 0xaaaaadf2a000
openat(AT_FDCWD, "/proc/filesystems", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
read(3, "nodev\tsysfs\nnodev\ttmpfs\nnodev\tbd"..., 1024) = 442
close(3) = 0
openat(AT_FDCWD, "/proc/mounts", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0444, st_size=0, ...}) = 0
read(3, "a2a0ee2c717462feb1de2f5afd59de5f"..., 1024) = 1024
read(3, "s/storage/overlay/l/DWNIFJNLXNBY"..., 1024) = 1024
read(3, "de64 0 0\ndevtmpfs /dev/zero devt"..., 1024) = 1024
read(3, "e,size=198968k,nr_inodes=49742,m"..., 1024) = 824
read(3, "", 1024) = 0
close(3) = 0
faccessat(AT_FDCWD, "/etc/selinux/config", F_OK) = -1 ENOENT (No such file or directory)
fcntl(0, F_GETFD) = 0
fcntl(1, F_GETFD) = 0
fcntl(2, F_GETFD) = 0
rt_sigaction(SIGCHLD, {sa_handler=SIG_DFL, sa_mask=[CHLD], sa_flags=SA_RESTART}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
geteuid() = 0
umask(000) = 022
openat(AT_FDCWD, "project.tar", O_RDONLY) = 3
read(3, "project/\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 10240) = 10240
fstat(3, {st_mode=S_IFREG|0644, st_size=10240, ...}) = 0
socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 4
connect(4, {sa_family=AF_UNIX, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
close(4) = 0
socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 4
connect(4, {sa_family=AF_UNIX, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
close(4) = 0
newfstatat(AT_FDCWD, "/etc/nsswitch.conf", {st_mode=S_IFREG|0644, st_size=494, ...}, 0) = 0
newfstatat(AT_FDCWD, "/", {st_mode=S_IFDIR|0555, st_size=73, ...}, 0) = 0
openat(AT_FDCWD, "/etc/nsswitch.conf", O_RDONLY|O_CLOEXEC) = 4
fstat(4, {st_mode=S_IFREG|0644, st_size=494, ...}) = 0
read(4, "# /etc/nsswitch.conf\n#\n# Example"..., 4096) = 494
read(4, "", 4096) = 0
fstat(4, {st_mode=S_IFREG|0644, st_size=494, ...}) = 0
close(4) = 0
openat(AT_FDCWD, "/etc/passwd", O_RDONLY|O_CLOEXEC) = 4
fstat(4, {st_mode=S_IFREG|0644, st_size=839, ...}) = 0
lseek(4, 0, SEEK_SET) = 0
read(4, "root:x:0:0:root:/root:/bin/bash\n"..., 4096) = 839
close(4) = 0
socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 4
connect(4, {sa_family=AF_UNIX, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
close(4) = 0
socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 4
connect(4, {sa_family=AF_UNIX, sun_path="/var/run/nscd/socket"}, 110) = -1 ENOENT (No such file or directory)
close(4) = 0
newfstatat(AT_FDCWD, "/etc/nsswitch.conf", {st_mode=S_IFREG|0644, st_size=494, ...}, 0) = 0
openat(AT_FDCWD, "/etc/group", O_RDONLY|O_CLOEXEC) = 4
fstat(4, {st_mode=S_IFREG|0644, st_size=434, ...}) = 0
lseek(4, 0, SEEK_SET) = 0
read(4, "root:x:0:\ndaemon:x:1:\nbin:x:2:\ns"..., 4096) = 434
close(4) = 0
mkdirat(AT_FDCWD, "project", 0700) = 0
mkdirat(AT_FDCWD, "project/inside", 0700) = 0
**openat(AT_FDCWD, "project/inside/foo", O_WRONLY|O_CREAT|O_EXCL, 000) = -1 EACCES (Permission denied)**
write(2, "tar: ", 5) = 5
write(2, "project/inside/foo: Cannot open", 31) = 31
write(2, ": Permission denied", 19) = 19
write(2, "\n", 1) = 1
utimensat(AT_FDCWD, "project/inside", [UTIME_OMIT, {tv_sec=1780074047, tv_nsec=0} /* 2026-05-29T17:00:47+0000 */], AT_SYMLINK_NOFOLLOW) = 0
fchownat(AT_FDCWD, "project/inside", 0, 0, AT_SYMLINK_NOFOLLOW) = 0
fchmodat2(AT_FDCWD, "project/inside", 0755, AT_SYMLINK_NOFOLLOW) = 0
openat(AT_FDCWD, "project/foo", O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY|O_NONBLOCK|O_CLOEXEC, 0600) = 4
write(4, "Fri May 29 17:00:47 UTC 2026\n", 29) = 29
utimensat(4, NULL, [UTIME_OMIT, {tv_sec=1780074047, tv_nsec=0} /* 2026-05-29T17:00:47+0000 */], 0) = 0
fchown(4, 0, 0) = 0
fchmod(4, 0644) = 0
close(4) = 0
close(3) = 0
utimensat(AT_FDCWD, "project", [UTIME_OMIT, {tv_sec=1780074047, tv_nsec=0} /* 2026-05-29T17:00:47+0000 */], AT_SYMLINK_NOFOLLOW) = 0
fchownat(AT_FDCWD, "project", 0, 0, AT_SYMLINK_NOFOLLOW) = 0
fchmodat2(AT_FDCWD, "project", 0755, AT_SYMLINK_NOFOLLOW) = 0
write(2, "tar: ", 5) = 5
write(2, "Exiting with failure status due "..., 50) = 50
write(2, "\n", 1) = 1
close(1) = 0
close(2) = 0
exit_group(2) = ?
+++ exited with 2 +++
There are two more things to share.
The workflow that leads to this issue is using a container to build historical firmware releases. We're pulling sources from git using git-archive and extracting them in the container. During one phase of the work, we mount the build directory on the host so we can more easily edit and analyze the sources. We started this work a few months ago and had no trouble with the un-archiving of the sources.
We were able to work-around the issue without too much inconvenience. We extract the archive into container directory (overlay) and then move it to the working directory, links and all.
Issue Description
I am including a script that demonstrates the issue.
To be more specific, unpacking a tar archive in the container, onto a host mounted filesystem, where the container has a symlink referencing a parent, fails in a way that does not yield similar behavior on a Linux host. This appears to be new since upgrading to podman 5.8 on MacOS.
Here is a run of the script:
Selecting previously unselected package strace.
(Reading database ... 4933 files and directories currently installed.)
Preparing to unpack .../strace_6.13+ds-1_arm64.deb ...
Unpacking strace (6.13+ds-1) ...
Setting up strace (6.13+ds-1) ...
tar: project/inside/foo: Cannot open: Permission denied
tar: Exiting with failure status due to previous errors
total 0
----------? 1 root root 0 May 29 17:00 foo
mkdirat(AT_FDCWD, "project/inside", 0700) = 0
openat(AT_FDCWD, "project/inside/foo", O_WRONLY|O_CREAT|O_EXCL, 000) = -1 EACCES (Permission denied)
write(2, "project/inside/foo: Cannot open", 31) = 31
utimensat(AT_FDCWD, "project/inside", [UTIME_OMIT, {tv_sec=1780074047, tv_nsec=0} /* 2026-05-29T17:00:47+0000 */], AT_SYMLINK_NOFOLLOW) = 0
fchownat(AT_FDCWD, "project/inside", 0, 0, AT_SYMLINK_NOFOLLOW) = 0
fchmodat2(AT_FDCWD, "project/inside", 0755, AT_SYMLINK_NOFOLLOW) = 0
Steps to reproduce the issue
Stepsto reproduce the issuelinkfail.sh
Describe the results you received
I think the crux of the issue is that the link isn't created. It's not that it would not be supported to create the link. It's that a peculiar file is created by the openat call even though it returns an error.
Describe the results you expected
There ought to have been a symlink created.
podman info output
Podman in a container
No
Privileged Or Rootless
Rootless
Upstream Latest Release
Yes
Additional environment details
Additional environment details
Additional information
There are two more things to share.
The workflow that leads to this issue is using a container to build historical firmware releases. We're pulling sources from git using git-archive and extracting them in the container. During one phase of the work, we mount the build directory on the host so we can more easily edit and analyze the sources. We started this work a few months ago and had no trouble with the un-archiving of the sources.
We were able to work-around the issue without too much inconvenience. We extract the archive into container directory (overlay) and then move it to the working directory, links and all.