Skip to content

Honor O_PATH semantics across fd consumers#8

Merged
jserv merged 1 commit intomainfrom
opath
May 5, 2026
Merged

Honor O_PATH semantics across fd consumers#8
jserv merged 1 commit intomainfrom
opath

Conversation

@jserv
Copy link
Copy Markdown
Contributor

@jserv jserv commented May 5, 2026

Linux O_PATH descriptors carry only path reference: read, write, lseek, ftruncate, fsync/fdatasync, flock, ioctl, fchmod, fchown, getdents64, fsetxattr, and fremovexattr must all return EBADF. Our translate_open_flags maps O_PATH to a plain O_RDONLY host fd, so without explicit gating the host call would silently succeed and diverge from Linux semantics on every one of those paths.

Add host_fd_ref_open_io in syscall/internal.h that snapshots the fd entry and rejects FD_PATH with -EBADF. Wire it into sys_lseek and sys_ftruncate (fs.c), sc_fsync_common and sc_flock (syscall.c), and sys_fsetxattr / sys_fremovexattr (fs-xattr.c). sys_getdents64 gains an explicit FD_PATH gate ahead of the dir==NULL check so an O_PATH directory reports EBADF rather than ENOTDIR. io.c's host_fd_ref_open_regular_io now delegates to the shared helper. fchdir, fstat, fstatfs, close, dup, fcntl(CLOEXEC/DUPFD/GETFL), and *at() dirfd usage stay allowed, matching Linux.

Audit also surfaced an aarch64 syscall-number bug. SYS_fgetxattr was 16 (real value 10) and SYS_fremovexattr was 18 (real value 16) per include/uapi/asm-generic/unistd.h. Guest fremovexattr was being dispatched to the fgetxattr handler, which then ran with garbage size/value pointers from the unused argument registers; the missing FD_PATH check kept this hidden until tests/test-opath.c exercised it. Numbers in src/syscall/abi.h now match upstream.


Summary by cubic

Enforce Linux O_PATH semantics so ops that need a real file now return EBADF on O_PATH fds, and fix aarch64 xattr syscall numbers. This aligns behavior with Linux and prevents silent success.

  • Bug Fixes
    • Added host_fd_ref_open_io to reject FD_PATH; used by lseek, ftruncate, fsync/fdatasync, flock, fsetxattr, fremovexattr; getdents64 now returns EBADF for O_PATH dirs; io.c delegates to the helper.
    • Kept allowed O_PATH ops: fstat, fstatfs, close, dup, fcntl(CLOEXEC/DUPFD/GETFL), fchdir, and use as a *at() dirfd.
    • Corrected aarch64 xattr syscall numbers to match asm-generic (fgetxattr=10, fremovexattr=16) to fix mis-dispatch.
    • Added test-opath and updated test manifest.

Written for commit b23f003. Summary will update on new commits.

Linux O_PATH descriptors carry only path reference: read, write, lseek,
ftruncate, fsync/fdatasync, flock, ioctl, fchmod, fchown, getdents64,
fsetxattr, and fremovexattr must all return EBADF.
Our translate_open_flags maps O_PATH to a plain O_RDONLY host fd, so
without explicit gating the host call would silently succeed and diverge
from Linux semantics on every one of those paths.

Add host_fd_ref_open_io in syscall/internal.h that snapshots the fd
entry and rejects FD_PATH with -EBADF. Wire it into sys_lseek and
sys_ftruncate (fs.c), sc_fsync_common and sc_flock (syscall.c), and
sys_fsetxattr / sys_fremovexattr (fs-xattr.c). sys_getdents64 gains an
explicit FD_PATH gate ahead of the dir==NULL check so an O_PATH directory
reports EBADF rather than ENOTDIR. io.c's host_fd_ref_open_regular_io now
delegates to the shared helper. fchdir, fstat, fstatfs, close, dup,
fcntl(CLOEXEC/DUPFD/GETFL), and *at() dirfd usage stay allowed, matching
Linux.

Audit also surfaced an aarch64 syscall-number bug. SYS_fgetxattr was 16
(real value 10) and SYS_fremovexattr was 18 (real value 16) per
include/uapi/asm-generic/unistd.h. Guest fremovexattr was being
dispatched to the fgetxattr handler, which then ran with garbage
size/value pointers from the unused argument registers; the missing
FD_PATH check kept this hidden until tests/test-opath.c exercised it.
Numbers in src/syscall/abi.h now match upstream.
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 8 files

@jserv jserv merged commit a49ea1d into main May 5, 2026
5 checks passed
@jserv jserv deleted the opath branch May 5, 2026 04:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant