this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Don't perform fchmodat on symlinks if told not to follow symlinks

In macOS (and some BSDs), symlinks have modifiable permissions, but in Linux, they do not.

Telling Linux to perform fchmodat on a symlink will cause it to modify the permissions on the symlink's target
(and return ENOENT if you try to modify permissions on a symlink that doesn't have a valid target)

+49 -2
+47 -1
src/kernel/emulation/linux/unistd/fchmodat.c
··· 6 6 #include "../vchroot_expand.h" 7 7 #include <mach/lkm.h> 8 8 #include <lkm/api.h> 9 + #include <stdio.h> 10 + #include "../stat/common.h" 11 + #include <sys/stat.h> 9 12 10 13 extern char* strcpy(char* dst, const char* src); 14 + extern long close_internal(int fd); 15 + 16 + #ifndef LINUX_O_PATH 17 + #define LINUX_O_PATH 0x200000 18 + #endif 19 + #ifndef LINUX_O_NOFOLLOW 20 + #define LINUX_O_NOFOLLOW 0x0100 21 + #endif 22 + #ifndef LINUX_O_CLOEXEC 23 + #define LINUX_O_CLOEXEC 0x1000000 24 + #endif 25 + #ifndef LINUX_AT_EMPTY_PATH 26 + #define LINUX_AT_EMPTY_PATH 0x1000 27 + #endif 28 + 29 + #ifndef __NR_fstatat64 30 + #define __NR_fstatat64 __NR_newfstatat 31 + #endif 32 + 33 + int do_linux_fchmodat(int fd, const char* path, int mode, int flag) { 34 + if (flag == 0) { 35 + return LINUX_SYSCALL(__NR_fchmodat, fd, path, mode); 36 + } else { 37 + struct linux_stat st; 38 + if (LINUX_SYSCALL(__NR_fstatat64, fd, path, &st, LINUX_AT_EMPTY_PATH | LINUX_AT_SYMLINK_NOFOLLOW) != 0) 39 + return -1; 40 + 41 + // on Linux, symlinks can't be chmodded (only their targets) 42 + // 43 + // we can't open a file handle directly on the symlink 44 + // and do fchmod/chmod on that because Linux ignores us 45 + // and follows the symlink anyways 46 + // 47 + // this still happens even if we try to open a file handle to 48 + // the symlink and modify it through `/proc/self/fd` 49 + // 50 + // so instead, just return success 51 + if (S_ISLNK(st.st_mode)) 52 + return 0; 53 + 54 + return LINUX_SYSCALL(__NR_fchmodat, fd, path, mode); 55 + } 56 + }; 11 57 12 58 long sys_fchmodat(int fd, const char* path, int mode, int flag) 13 59 { ··· 23 69 if (ret < 0) 24 70 return errno_linux_to_bsd(ret); 25 71 26 - ret = LINUX_SYSCALL(__NR_fchmodat, vc.dfd, vc.path, mode, atflags_bsd_to_linux(flag)); 72 + ret = do_linux_fchmodat(vc.dfd, vc.path, mode, atflags_bsd_to_linux(flag)); 27 73 if (ret < 0) 28 74 ret = errno_linux_to_bsd(ret); 29 75
+2 -1
src/kernel/emulation/linux/xattr/setattrlist_generic.c
··· 8 8 #include <stddef.h> 9 9 10 10 extern char *strcpy(char *dest, const char *src); 11 + extern int do_linux_fchmodat(int fd, const char* path, int mode, int flag); 11 12 12 13 #define ATTR_BIT_MAP_COUNT 5 13 14 ··· 125 126 { 126 127 int perms = *((int*) next); 127 128 #if HAS_PATH 128 - rv = LINUX_SYSCALL(__NR_chmod, vc.path, perms); 129 + rv = do_linux_fchmodat(LINUX_AT_FDCWD, vc.path, perms, LINUX_AT_SYMLINK_NOFOLLOW); 129 130 #else 130 131 rv = LINUX_SYSCALL(__NR_fchmod, fd, perms); 131 132 #endif