From d8b0be856c0dfc5f3c3ab84488a0f7576f23fa85 Mon Sep 17 00:00:00 2001 From: Francesco Lavra Date: Sat, 5 Oct 2024 13:53:23 +0200 Subject: [PATCH] stat/fstat/statx: retrieve file permissions from metadata Instead of hardcoding file permission bits, retrieve them from the file metadata. With this change, the execute permission bit is set when the user program invokes stat() on the executable file; this is required in order to avoid "BinaryNotMarkedExecutable" errors when running tigerbeetle (https://github.com/tigerbeetle/tigerbeetle). --- src/unix/filesystem.c | 34 +++++++++++++++++++++++++--------- src/unix/filesystem.h | 2 +- src/unix/syscall.c | 2 +- test/runtime/symlink.c | 2 -- 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/unix/filesystem.c b/src/unix/filesystem.c index 4f577db2a..501eace10 100644 --- a/src/unix/filesystem.c +++ b/src/unix/filesystem.c @@ -20,24 +20,40 @@ sysreturn sysreturn_from_fs_status_value(status s) return rv; } -u16 file_mode_from_type(int type) +u16 stat_mode(process p, int type, tuple meta) { + u16 mode; switch (type) { case FDESC_TYPE_REGULAR: - return S_IFREG | 0644; + mode = S_IFREG; + break; case FDESC_TYPE_DIRECTORY: - return S_IFDIR | 0777; + mode = S_IFDIR; + break; case FDESC_TYPE_STDIO: case FDESC_TYPE_SPECIAL: /* assuming only character devices */ - return S_IFCHR; + mode = S_IFCHR; + break; case FDESC_TYPE_SOCKET: - return S_IFSOCK; + mode = S_IFSOCK; + break; case FDESC_TYPE_PIPE: - return S_IFIFO; + mode = S_IFIFO; + break; case FDESC_TYPE_SYMLINK: - return S_IFLNK; + mode = S_IFLNK; + break; + default: + return 0; } - return 0; + u32 perms = file_meta_perms(p, meta); + if (perms & ACCESS_PERM_READ) + mode |= 0444; + if (perms & ACCESS_PERM_WRITE) + mode |= 0222; + if (perms & ACCESS_PERM_EXEC) + mode |= 0111; + return mode; } void file_readahead(file f, u64 offset, u64 len) @@ -355,7 +371,7 @@ static sysreturn statx_internal(filesystem fs, int type, tuple n, fsfile f, stru if (!validate_user_memory(statxbuf, sizeof(struct rlimit), true) || context_set_err(ctx)) return -EFAULT; zero(statxbuf, sizeof(*statxbuf)); - statxbuf->stx_mode = file_mode_from_type(type); + statxbuf->stx_mode = stat_mode(current->p, type, n); statxbuf->stx_mask = STATX_TYPE | STATX_MODE; switch (type) { case FDESC_TYPE_REGULAR: diff --git a/src/unix/filesystem.h b/src/unix/filesystem.h index 94c0f26c3..b1c5c4e71 100644 --- a/src/unix/filesystem.h +++ b/src/unix/filesystem.h @@ -24,7 +24,7 @@ sysreturn sysreturn_from_fs_status_value(status s); -u16 file_mode_from_type(int type); +u16 stat_mode(process p, int type, tuple meta); /* Perform read-ahead following a userspace read request. * offset and len arguments refer to the byte range being read from userspace, diff --git a/src/unix/syscall.c b/src/unix/syscall.c index 3398c0438..e7d43c6e1 100755 --- a/src/unix/syscall.c +++ b/src/unix/syscall.c @@ -1447,7 +1447,7 @@ sysreturn openat(int dirfd, const char *name, int flags, int mode) static void fill_stat(int type, filesystem fs, fsfile f, tuple n, struct stat *s) { zero(s, sizeof(struct stat)); - s->st_mode = file_mode_from_type(type); + s->st_mode = stat_mode(current->p, type, n); switch (type) { case FDESC_TYPE_REGULAR: if (f) { diff --git a/test/runtime/symlink.c b/test/runtime/symlink.c index 7cd79ad04..7812e4c59 100644 --- a/test/runtime/symlink.c +++ b/test/runtime/symlink.c @@ -91,7 +91,6 @@ int main(int argc, char **argv) test_assert((faccessat(AT_FDCWD, "link", F_OK, AT_SYMLINK_NOFOLLOW) == 0)); test_assert((faccessat(AT_FDCWD, "link", R_OK|W_OK, AT_SYMLINK_NOFOLLOW) == 0)); - test_assert((faccessat(AT_FDCWD, "link", X_OK, AT_SYMLINK_NOFOLLOW) == -1 && (errno == EACCES))); test_assert((faccessat(AT_FDCWD, "link", F_OK, 0) == -1) && (errno == ENOENT)); fd = open("target", O_RDWR | O_CREAT, S_IRWXU); @@ -99,7 +98,6 @@ int main(int argc, char **argv) close(fd); test_assert((faccessat(AT_FDCWD, "link", F_OK, 0) == 0)); - test_assert((faccessat(AT_FDCWD, "link", X_OK, AT_SYMLINK_NOFOLLOW) == -1 && (errno == EACCES))); test_assert((faccessat(AT_FDCWD, "link", X_OK|R_OK|W_OK, 0) == 0)); test_assert((access("link", F_OK) == 0)); test_assert((access("link", X_OK|R_OK|W_OK) == 0));