Skip to content

Commit

Permalink
stat/fstat/statx: retrieve file permissions from metadata
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
francescolavra committed Oct 5, 2024
1 parent 2c94576 commit d8b0be8
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 13 deletions.
34 changes: 25 additions & 9 deletions src/unix/filesystem.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion src/unix/filesystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion src/unix/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 0 additions & 2 deletions test/runtime/symlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,13 @@ 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);
test_assert(fd >= 0);
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));
Expand Down

0 comments on commit d8b0be8

Please sign in to comment.