Under chroot="/" and fs_mount, the supervisor rewrites paths for openat/statx/newfstatat/faccessat/readlinkat/etc., but not the xattr family. So getxattr/lgetxattr/listxattr on a path under an fs_mount target resolve against the real (empty) mount point instead of the mounted source which leads to ENOENT.
Reproducible via ls -l, which probes xattrs for the ACL + / SELinux . indicator: the listing is correct (mediated statx), but ls also prints ls: <path>: No such file or directory and exits non-zero.
Repro (sandlock 0.8.1):
import os
from sandlock import Sandbox
src = "/tmp/xattr-demo"; os.makedirs(src, exist_ok=True)
open(src + "/f.txt", "w").write("hi")
sb = Sandbox(chroot="/", fs_mount={"/mnt": src},
fs_readable=["/usr","/lib","/lib64","/bin","/sbin","/etc","/dev","/mnt"],
fs_writable=["/mnt"], cwd="/mnt")
print(sb.run(["/bin/ls", "-l", "/mnt/f.txt"]))
# stdout: correct listing | stderr: "ls: /mnt/f.txt: No such file or directory" | exit 1
Inside the sandbox, os.stat("/mnt/f.txt") succeeds while lgetxattr("/mnt/f.txt", "system.posix_acl_access") returns errno 2 (ENOENT) — confirming it hit the real /mnt. statx/newfstatat/stat(1) are all fine; only *xattr is affected.
Under
chroot="/"andfs_mount, the supervisor rewrites paths foropenat/statx/newfstatat/faccessat/readlinkat/etc., but not thexattrfamily. Sogetxattr/lgetxattr/listxattron a path under anfs_mounttarget resolve against the real (empty) mount point instead of the mounted source which leads toENOENT.Reproducible via
ls -l, which probes xattrs for the ACL+/ SELinux.indicator: the listing is correct (mediatedstatx), butlsalso printsls: <path>: No such file or directoryand exits non-zero.Repro (sandlock 0.8.1):
Inside the sandbox,
os.stat("/mnt/f.txt")succeeds whilelgetxattr("/mnt/f.txt", "system.posix_acl_access")returnserrno 2 (ENOENT)— confirming it hit the real/mnt.statx/newfstatat/stat(1)are all fine; only*xattris affected.