History

vfs: add faccessat2 syscall

POSIX defines faccessat() as having a fourth "flags" argument, while the linux syscall doesn't have it. Glibc tries to emulate AT_EACCESS and AT_SYMLINK_NOFOLLOW, but AT_EACCESS emulation is broken. Add a new faccessat(2) syscall with the added flags argument and implement both flags. The value of AT_EACCESS is defined in glibc headers to be the same as AT_REMOVEDIR. Use this value for the kernel interface as well, together with the explanatory comment. Also add AT_EMPTY_PATH support, which is not documented by POSIX, but can be useful and is trivial to implement.

Miklos Szeredi committed 6 years ago

Commit c8ffd8b1 parent 55923e423 files · +62 −13Browse files

Unified · Split

23 files
  1. arch/alpha/kernel/syscalls/syscall.tbl +1 −0
  2. arch/arm/tools/syscall.tbl +1 −0
  3. arch/arm64/include/asm/unistd.h +1 −1
  4. arch/arm64/include/asm/unistd32.h +2 −0
  5. arch/ia64/kernel/syscalls/syscall.tbl +1 −0
  6. arch/m68k/kernel/syscalls/syscall.tbl +1 −0
  7. arch/microblaze/kernel/syscalls/syscall.tbl +1 −0
  8. arch/mips/kernel/syscalls/syscall_n32.tbl +1 −0
  9. arch/mips/kernel/syscalls/syscall_n64.tbl +1 −0
  10. arch/mips/kernel/syscalls/syscall_o32.tbl +1 −0
  11. arch/parisc/kernel/syscalls/syscall.tbl +1 −0
  12. arch/powerpc/kernel/syscalls/syscall.tbl +1 −0
  13. arch/s390/kernel/syscalls/syscall.tbl +1 −0
  14. arch/sh/kernel/syscalls/syscall.tbl +1 −0
  15. arch/sparc/kernel/syscalls/syscall.tbl +1 −0
  16. arch/x86/entry/syscalls/syscall_32.tbl +1 −0
  17. arch/x86/entry/syscalls/syscall_64.tbl +1 −0
  18. arch/xtensa/kernel/syscalls/syscall.tbl +1 −0
  19. fs/internal.h +0 −1
  20. fs/open.c +26 −8
  21. include/linux/syscalls.h +4 −2
  22. include/uapi/asm-generic/unistd.h +3 −1
  23. include/uapi/linux/fcntl.h +10 −0
arch/alpha/kernel/syscalls/syscall.tbl+1−0
@@ -477,3 +477,4 @@ · 476 unmodified lines
477# 545 reserved for clone3477# 545 reserved for clone3
478547 common openat2 sys_openat2478547 common openat2 sys_openat2
479548 common pidfd_getfd sys_pidfd_getfd479548 common pidfd_getfd sys_pidfd_getfd
480549 common faccessat2 sys_faccessat2
arch/arm/tools/syscall.tbl+1−0
@@ -451,3 +451,4 @@ · 450 unmodified lines
451435 common clone3 sys_clone3451435 common clone3 sys_clone3
452437 common openat2 sys_openat2452437 common openat2 sys_openat2
453438 common pidfd_getfd sys_pidfd_getfd453438 common pidfd_getfd sys_pidfd_getfd
454439 common faccessat2 sys_faccessat2
arch/arm64/include/asm/unistd.h+1−1
@@ -38,7 +38,7 @@ · 37 unmodified lines
38#define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE + 5)38#define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE + 5)
39#define __ARM_NR_COMPAT_END (__ARM_NR_COMPAT_BASE + 0x800)39#define __ARM_NR_COMPAT_END (__ARM_NR_COMPAT_BASE + 0x800)
40 40
41#define __NR_compat_syscalls 43941#define __NR_compat_syscalls 440
42#endif42#endif
43 43
44#define __ARCH_WANT_SYS_CLONE44#define __ARCH_WANT_SYS_CLONE
arch/arm64/include/asm/unistd32.h+2−0
@@ -883,6 +883,8 @@ __SYSCALL(__NR_clone3, sys_clone3) · 882 unmodified lines
883__SYSCALL(__NR_openat2, sys_openat2)883__SYSCALL(__NR_openat2, sys_openat2)
884#define __NR_pidfd_getfd 438884#define __NR_pidfd_getfd 438
885__SYSCALL(__NR_pidfd_getfd, sys_pidfd_getfd)885__SYSCALL(__NR_pidfd_getfd, sys_pidfd_getfd)
886#define __NR_faccessat2 439
887__SYSCALL(__NR_faccessat2, sys_faccessat2)
886 888
887/*889/*
888 * Please add new compat syscalls above this comment and update890 * Please add new compat syscalls above this comment and update
arch/ia64/kernel/syscalls/syscall.tbl+1−0
@@ -358,3 +358,4 @@ · 357 unmodified lines
358# 435 reserved for clone3358# 435 reserved for clone3
359437 common openat2 sys_openat2359437 common openat2 sys_openat2
360438 common pidfd_getfd sys_pidfd_getfd360438 common pidfd_getfd sys_pidfd_getfd
361439 common faccessat2 sys_faccessat2
arch/m68k/kernel/syscalls/syscall.tbl+1−0
@@ -437,3 +437,4 @@ · 436 unmodified lines
437435 common clone3 __sys_clone3437435 common clone3 __sys_clone3
438437 common openat2 sys_openat2438437 common openat2 sys_openat2
439438 common pidfd_getfd sys_pidfd_getfd439438 common pidfd_getfd sys_pidfd_getfd
440439 common faccessat2 sys_faccessat2
arch/microblaze/kernel/syscalls/syscall.tbl+1−0
@@ -443,3 +443,4 @@ · 442 unmodified lines
443435 common clone3 sys_clone3443435 common clone3 sys_clone3
444437 common openat2 sys_openat2444437 common openat2 sys_openat2
445438 common pidfd_getfd sys_pidfd_getfd445438 common pidfd_getfd sys_pidfd_getfd
446439 common faccessat2 sys_faccessat2
arch/mips/kernel/syscalls/syscall_n32.tbl+1−0
@@ -376,3 +376,4 @@ · 375 unmodified lines
376435 n32 clone3 __sys_clone3376435 n32 clone3 __sys_clone3
377437 n32 openat2 sys_openat2377437 n32 openat2 sys_openat2
378438 n32 pidfd_getfd sys_pidfd_getfd378438 n32 pidfd_getfd sys_pidfd_getfd
379439 n32 faccessat2 sys_faccessat2
arch/mips/kernel/syscalls/syscall_n64.tbl+1−0
@@ -352,3 +352,4 @@ · 351 unmodified lines
352435 n64 clone3 __sys_clone3352435 n64 clone3 __sys_clone3
353437 n64 openat2 sys_openat2353437 n64 openat2 sys_openat2
354438 n64 pidfd_getfd sys_pidfd_getfd354438 n64 pidfd_getfd sys_pidfd_getfd
355439 n64 faccessat2 sys_faccessat2
arch/mips/kernel/syscalls/syscall_o32.tbl+1−0
@@ -425,3 +425,4 @@ · 424 unmodified lines
425435 o32 clone3 __sys_clone3425435 o32 clone3 __sys_clone3
426437 o32 openat2 sys_openat2426437 o32 openat2 sys_openat2
427438 o32 pidfd_getfd sys_pidfd_getfd427438 o32 pidfd_getfd sys_pidfd_getfd
428439 o32 faccessat2 sys_faccessat2
arch/parisc/kernel/syscalls/syscall.tbl+1−0
@@ -435,3 +435,4 @@ · 434 unmodified lines
435435 common clone3 sys_clone3_wrapper435435 common clone3 sys_clone3_wrapper
436437 common openat2 sys_openat2436437 common openat2 sys_openat2
437438 common pidfd_getfd sys_pidfd_getfd437438 common pidfd_getfd sys_pidfd_getfd
438439 common faccessat2 sys_faccessat2
arch/powerpc/kernel/syscalls/syscall.tbl+1−0
@@ -527,3 +527,4 @@ · 526 unmodified lines
527435 spu clone3 sys_ni_syscall527435 spu clone3 sys_ni_syscall
528437 common openat2 sys_openat2528437 common openat2 sys_openat2
529438 common pidfd_getfd sys_pidfd_getfd529438 common pidfd_getfd sys_pidfd_getfd
530439 common faccessat2 sys_faccessat2
arch/s390/kernel/syscalls/syscall.tbl+1−0
@@ -440,3 +440,4 @@ · 439 unmodified lines
440435 common clone3 sys_clone3 sys_clone3440435 common clone3 sys_clone3 sys_clone3
441437 common openat2 sys_openat2 sys_openat2441437 common openat2 sys_openat2 sys_openat2
442438 common pidfd_getfd sys_pidfd_getfd sys_pidfd_getfd442438 common pidfd_getfd sys_pidfd_getfd sys_pidfd_getfd
443439 common faccessat2 sys_faccessat2 sys_faccessat2
arch/sh/kernel/syscalls/syscall.tbl+1−0
@@ -440,3 +440,4 @@ · 439 unmodified lines
440# 435 reserved for clone3440# 435 reserved for clone3
441437 common openat2 sys_openat2441437 common openat2 sys_openat2
442438 common pidfd_getfd sys_pidfd_getfd442438 common pidfd_getfd sys_pidfd_getfd
443439 common faccessat2 sys_faccessat2
arch/sparc/kernel/syscalls/syscall.tbl+1−0
@@ -483,3 +483,4 @@ · 482 unmodified lines
483# 435 reserved for clone3483# 435 reserved for clone3
484437 common openat2 sys_openat2484437 common openat2 sys_openat2
485438 common pidfd_getfd sys_pidfd_getfd485438 common pidfd_getfd sys_pidfd_getfd
486439 common faccessat2 sys_faccessat2
arch/x86/entry/syscalls/syscall_32.tbl+1−0
@@ -442,3 +442,4 @@ · 441 unmodified lines
442435 i386 clone3 sys_clone3442435 i386 clone3 sys_clone3
443437 i386 openat2 sys_openat2443437 i386 openat2 sys_openat2
444438 i386 pidfd_getfd sys_pidfd_getfd444438 i386 pidfd_getfd sys_pidfd_getfd
445439 i386 faccessat2 sys_faccessat2
arch/x86/entry/syscalls/syscall_64.tbl+1−0
@@ -359,6 +359,7 @@ · 358 unmodified lines
359435 common clone3 sys_clone3359435 common clone3 sys_clone3
360437 common openat2 sys_openat2360437 common openat2 sys_openat2
361438 common pidfd_getfd sys_pidfd_getfd361438 common pidfd_getfd sys_pidfd_getfd
362439 common faccessat2 sys_faccessat2
362 363
363#364#
364# x32-specific system call numbers start at 512 to avoid cache impact365# x32-specific system call numbers start at 512 to avoid cache impact
arch/xtensa/kernel/syscalls/syscall.tbl+1−0
@@ -408,3 +408,4 @@ · 407 unmodified lines
408435 common clone3 sys_clone3408435 common clone3 sys_clone3
409437 common openat2 sys_openat2409437 common openat2 sys_openat2
410438 common pidfd_getfd sys_pidfd_getfd410438 common pidfd_getfd sys_pidfd_getfd
411439 common faccessat2 sys_faccessat2
fs/internal.h+0−1
@@ -126,7 +126,6 @@ extern struct open_how build_open_how(int flags, umode_t mode); · 125 unmodified lines
126extern int build_open_flags(const struct open_how *how, struct open_flags *op);126extern int build_open_flags(const struct open_how *how, struct open_flags *op);
127 127
128long do_sys_ftruncate(unsigned int fd, loff_t length, int small);128long do_sys_ftruncate(unsigned int fd, loff_t length, int small);
129long do_faccessat(int dfd, const char __user *filename, int mode);
130int do_fchmodat(int dfd, const char __user *filename, umode_t mode);129int do_fchmodat(int dfd, const char __user *filename, umode_t mode);
131int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group,130int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group,
132 int flag);131 int flag);
fs/open.c+26−8
@@ -394,20 +394,30 @@ static const struct cred *access_override_creds(void) · 393 unmodified lines
394 return old_cred;394 return old_cred;
395}395}
396 396
397long do_faccessat(int dfd, const char __user *filename, int mode)397long do_faccessat(int dfd, const char __user *filename, int mode, int flags)
398{398{
399 struct path path;399 struct path path;
400 struct inode *inode;400 struct inode *inode;
401 int res;401 int res;
402 unsigned int lookup_flags = LOOKUP_FOLLOW;402 unsigned int lookup_flags = LOOKUP_FOLLOW;
403 const struct cred *old_cred;403 const struct cred *old_cred = NULL;
404 404
405 if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */405 if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */
406 return -EINVAL;406 return -EINVAL;
407 407
408 old_cred = access_override_creds();408 if (flags & ~(AT_EACCESS | AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH))
409 if (!old_cred)409 return -EINVAL;
410 return -ENOMEM;410
411 if (flags & AT_SYMLINK_NOFOLLOW)
412 lookup_flags &= ~LOOKUP_FOLLOW;
413 if (flags & AT_EMPTY_PATH)
414 lookup_flags |= LOOKUP_EMPTY;
415
416 if (!(flags & AT_EACCESS)) {
417 old_cred = access_override_creds();
418 if (!old_cred)
419 return -ENOMEM;
420 }
411 421
412retry:422retry:
413 res = user_path_at(dfd, filename, lookup_flags, &path);423 res = user_path_at(dfd, filename, lookup_flags, &path);
@@ -450,18 +460,26 @@ out_path_release: · 36 unmodified lines
450 goto retry;460 goto retry;
451 }461 }
452out:462out:
453 revert_creds(old_cred);463 if (old_cred)
464 revert_creds(old_cred);
465
454 return res;466 return res;
455}467}
456 468
457SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)469SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
458{470{
459 return do_faccessat(dfd, filename, mode);471 return do_faccessat(dfd, filename, mode, 0);
472}
473
474SYSCALL_DEFINE4(faccessat2, int, dfd, const char __user *, filename, int, mode,
475 int, flags)
476{
477 return do_faccessat(dfd, filename, mode, flags);
460}478}
461 479
462SYSCALL_DEFINE2(access, const char __user *, filename, int, mode)480SYSCALL_DEFINE2(access, const char __user *, filename, int, mode)
463{481{
464 return do_faccessat(AT_FDCWD, filename, mode);482 return do_faccessat(AT_FDCWD, filename, mode, 0);
465}483}
466 484
467int ksys_chdir(const char __user *filename)485int ksys_chdir(const char __user *filename)
include/linux/syscalls.h+4−2
@@ -428,6 +428,8 @@ asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length); · 427 unmodified lines
428#endif428#endif
429asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len);429asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len);
430asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode);430asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode);
431asmlinkage long sys_faccessat2(int dfd, const char __user *filename, int mode,
432 int flags);
431asmlinkage long sys_chdir(const char __user *filename);433asmlinkage long sys_chdir(const char __user *filename);
432asmlinkage long sys_fchdir(unsigned int fd);434asmlinkage long sys_fchdir(unsigned int fd);
433asmlinkage long sys_chroot(const char __user *filename);435asmlinkage long sys_chroot(const char __user *filename);
@@ -1333,11 +1335,11 @@ static inline int ksys_chmod(const char __user *filename, umode_t mode) · 899 unmodified lines
1333 return do_fchmodat(AT_FDCWD, filename, mode);1335 return do_fchmodat(AT_FDCWD, filename, mode);
1334}1336}
1335 1337
1336extern long do_faccessat(int dfd, const char __user *filename, int mode);1338long do_faccessat(int dfd, const char __user *filename, int mode, int flags);
1337 1339
1338static inline long ksys_access(const char __user *filename, int mode)1340static inline long ksys_access(const char __user *filename, int mode)
1339{1341{
1340 return do_faccessat(AT_FDCWD, filename, mode);1342 return do_faccessat(AT_FDCWD, filename, mode, 0);
1341}1343}
1342 1344
1343extern int do_fchownat(int dfd, const char __user *filename, uid_t user,1345extern int do_fchownat(int dfd, const char __user *filename, uid_t user,
include/uapi/asm-generic/unistd.h+3−1
@@ -855,9 +855,11 @@ __SYSCALL(__NR_clone3, sys_clone3) · 854 unmodified lines
855__SYSCALL(__NR_openat2, sys_openat2)855__SYSCALL(__NR_openat2, sys_openat2)
856#define __NR_pidfd_getfd 438856#define __NR_pidfd_getfd 438
857__SYSCALL(__NR_pidfd_getfd, sys_pidfd_getfd)857__SYSCALL(__NR_pidfd_getfd, sys_pidfd_getfd)
858#define __NR_faccessat2 439
859__SYSCALL(__NR_faccessat2, sys_faccessat2)
858 860
859#undef __NR_syscalls861#undef __NR_syscalls
860#define __NR_syscalls 439862#define __NR_syscalls 440
861 863
862/*864/*
863 * 32 bit systems traditionally used different865 * 32 bit systems traditionally used different
include/uapi/linux/fcntl.h+10−0
@@ -84,10 +84,20 @@ · 83 unmodified lines
84#define DN_ATTRIB 0x00000020 /* File changed attibutes */84#define DN_ATTRIB 0x00000020 /* File changed attibutes */
85#define DN_MULTISHOT 0x80000000 /* Don't remove notifier */85#define DN_MULTISHOT 0x80000000 /* Don't remove notifier */
86 86
87/*
88 * The constants AT_REMOVEDIR and AT_EACCESS have the same value. AT_EACCESS is
89 * meaningful only to faccessat, while AT_REMOVEDIR is meaningful only to
90 * unlinkat. The two functions do completely different things and therefore,
91 * the flags can be allowed to overlap. For example, passing AT_REMOVEDIR to
92 * faccessat would be undefined behavior and thus treating it equivalent to
93 * AT_EACCESS is valid undefined behavior.
94 */
87#define AT_FDCWD -100 /* Special value used to indicate95#define AT_FDCWD -100 /* Special value used to indicate
88 openat should use the current96 openat should use the current
89 working directory. */97 working directory. */
90#define AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */98#define AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */
99#define AT_EACCESS 0x200 /* Test access permitted for
100 effective IDs, not real IDs. */
91#define AT_REMOVEDIR 0x200 /* Remove directory instead of101#define AT_REMOVEDIR 0x200 /* Remove directory instead of
92 unlinking file. */102 unlinking file. */
93#define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */103#define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */