1. Empty Path Bug (Bypasses ENOENT Check)
Problem
When a guest process triggers a path-based system call with an empty path "" (e.g., openat(dirfd, "", flags) without AT_EMPTY_PATH), it is expected to fail with ENOENT.
However, in path_translate_at (src/syscall/path.c), the following condition is checked to detect ordinary relative paths:
if (tx->guest_path == path && path[0] != '/') {
Because the empty string "" does not start with / (i.e. path[0] == '\0' != '/'), this condition evaluates to true.
The code then resolves the path relative to the directory descriptor dirfd using dirfd_guest_base_path(dirfd, base, sizeof(base)), which writes the path of the parent directory itself into tx->guest_buf. As a result:
- The empty path
"" is translated to the directory path itself (e.g., /usr/bin/ or /).
- The subsequent host call succeeds and returns a descriptor/details for the directory, rather than returning
ENOENT.
Linux/POSIX Standard Behavior
Unless AT_EMPTY_PATH is set, passing an empty path to file-based syscalls (such as openat, fstatat, fchmodat, fchownat) must fail with -ENOENT.
2. Non-Directory dirfd Bug (Returns EBADF instead of ENOTDIR)
Problem
If a guest process calls a system call like openat(dirfd, "relative_path", ...) where dirfd is a valid file descriptor pointing to a regular file (not a directory), the call should fail with ENOTDIR.
In the new relative path resolution code, dirfd_guest_base_path is called to find the base directory. However, dirfd_guest_base_path rejects any non-directory file descriptors with EBADF:
if (snap.type != FD_DIR) {
errno = EBADF;
return -1;
}
As a result:
path_translate_at returns -1 with errno = EBADF.
- The system call surfaces
-EBADF (Bad File Descriptor) to the guest process instead of the correct -ENOTDIR (Not a Directory).
Linux/POSIX Standard Behavior
If dirfd is a valid, open file descriptor but does not refer to a directory, trying to resolve a relative path through it must fail with ENOTDIR. EBADF should only be returned if the file descriptor is not open or is invalid.
1. Empty Path Bug (Bypasses
ENOENTCheck)Problem
When a guest process triggers a path-based system call with an empty path
""(e.g.,openat(dirfd, "", flags)withoutAT_EMPTY_PATH), it is expected to fail withENOENT.However, in
path_translate_at(src/syscall/path.c), the following condition is checked to detect ordinary relative paths:Because the empty string
""does not start with/(i.e.path[0] == '\0' != '/'), this condition evaluates to true.The code then resolves the path relative to the directory descriptor
dirfdusingdirfd_guest_base_path(dirfd, base, sizeof(base)), which writes the path of the parent directory itself intotx->guest_buf. As a result:""is translated to the directory path itself (e.g.,/usr/bin/or/).ENOENT.Linux/POSIX Standard Behavior
Unless
AT_EMPTY_PATHis set, passing an empty path to file-based syscalls (such asopenat,fstatat,fchmodat,fchownat) must fail with-ENOENT.2. Non-Directory
dirfdBug (ReturnsEBADFinstead ofENOTDIR)Problem
If a guest process calls a system call like
openat(dirfd, "relative_path", ...)wheredirfdis a valid file descriptor pointing to a regular file (not a directory), the call should fail withENOTDIR.In the new relative path resolution code,
dirfd_guest_base_pathis called to find the base directory. However,dirfd_guest_base_pathrejects any non-directory file descriptors withEBADF:As a result:
path_translate_atreturns-1witherrno = EBADF.-EBADF(Bad File Descriptor) to the guest process instead of the correct-ENOTDIR(Not a Directory).Linux/POSIX Standard Behavior
If
dirfdis a valid, open file descriptor but does not refer to a directory, trying to resolve a relative path through it must fail withENOTDIR.EBADFshould only be returned if the file descriptor is not open or is invalid.