]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
vfs: add faccessat2 syscall
authorMiklos Szeredi <mszeredi@redhat.com>
Thu, 14 May 2020 14:44:25 +0000 (16:44 +0200)
committerMiklos Szeredi <mszeredi@redhat.com>
Thu, 14 May 2020 14:44:25 +0000 (16:44 +0200)
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.

Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
23 files changed:
arch/alpha/kernel/syscalls/syscall.tbl
arch/arm/tools/syscall.tbl
arch/arm64/include/asm/unistd.h
arch/arm64/include/asm/unistd32.h
arch/ia64/kernel/syscalls/syscall.tbl
arch/m68k/kernel/syscalls/syscall.tbl
arch/microblaze/kernel/syscalls/syscall.tbl
arch/mips/kernel/syscalls/syscall_n32.tbl
arch/mips/kernel/syscalls/syscall_n64.tbl
arch/mips/kernel/syscalls/syscall_o32.tbl
arch/parisc/kernel/syscalls/syscall.tbl
arch/powerpc/kernel/syscalls/syscall.tbl
arch/s390/kernel/syscalls/syscall.tbl
arch/sh/kernel/syscalls/syscall.tbl
arch/sparc/kernel/syscalls/syscall.tbl
arch/x86/entry/syscalls/syscall_32.tbl
arch/x86/entry/syscalls/syscall_64.tbl
arch/xtensa/kernel/syscalls/syscall.tbl
fs/internal.h
fs/open.c
include/linux/syscalls.h
include/uapi/asm-generic/unistd.h
include/uapi/linux/fcntl.h

index 36d42da7466aae5ccd8a8a70d0e70014ae63c2df..5ddd128d4b7ac0c6cdbf65dbc4bacb993c2a5413 100644 (file)
 # 545 reserved for clone3
 547    common  openat2                         sys_openat2
 548    common  pidfd_getfd                     sys_pidfd_getfd
+549    common  faccessat2                      sys_faccessat2
index 4d1cf74a2caac645c4b217134a066a12bcbe7056..d5cae5ffede0cd6e38846407b9fdce94fd352752 100644 (file)
 435    common  clone3                          sys_clone3
 437    common  openat2                         sys_openat2
 438    common  pidfd_getfd                     sys_pidfd_getfd
+439    common  faccessat2                      sys_faccessat2
index 803039d504de609b188e62abd2fc102f00d73db5..3b859596840de5238645308ecd1bf389401822c5 100644 (file)
@@ -38,7 +38,7 @@
 #define __ARM_NR_compat_set_tls                (__ARM_NR_COMPAT_BASE + 5)
 #define __ARM_NR_COMPAT_END            (__ARM_NR_COMPAT_BASE + 0x800)
 
-#define __NR_compat_syscalls           439
+#define __NR_compat_syscalls           440
 #endif
 
 #define __ARCH_WANT_SYS_CLONE
index c1c61635f89c374c80cab2410e87fbe261209540..6d95d0c8bf2f47f29d028a2d3c4754d6a3c7a4e3 100644 (file)
@@ -883,6 +883,8 @@ __SYSCALL(__NR_clone3, sys_clone3)
 __SYSCALL(__NR_openat2, sys_openat2)
 #define __NR_pidfd_getfd 438
 __SYSCALL(__NR_pidfd_getfd, sys_pidfd_getfd)
+#define __NR_faccessat2 439
+__SYSCALL(__NR_faccessat2, sys_faccessat2)
 
 /*
  * Please add new compat syscalls above this comment and update
index 042911e670b80179a74e0b55f8f8a644ccb49f1c..49e325b604b31917c1e3c967a2c1bae71c81ea7a 100644 (file)
 # 435 reserved for clone3
 437    common  openat2                         sys_openat2
 438    common  pidfd_getfd                     sys_pidfd_getfd
+439    common  faccessat2                      sys_faccessat2
index f4f49fcb76d0fe3e7107cc9e68a70aabf34ccb27..f71b1bbcc1988c3e082b17b2d39520282930c1aa 100644 (file)
 435    common  clone3                          __sys_clone3
 437    common  openat2                         sys_openat2
 438    common  pidfd_getfd                     sys_pidfd_getfd
+439    common  faccessat2                      sys_faccessat2
index 4c67b11f9c9ef83f70fb3b7cb891dbe81e271564..edacc4561f2b3bd30f28c86328da667c4ae63049 100644 (file)
 435    common  clone3                          sys_clone3
 437    common  openat2                         sys_openat2
 438    common  pidfd_getfd                     sys_pidfd_getfd
+439    common  faccessat2                      sys_faccessat2
index 1f9e8ad636cce34a128d143e604b6847caae0438..f777141f52568fcac820d2ab9bfa5a7075d32314 100644 (file)
 435    n32     clone3                          __sys_clone3
 437    n32     openat2                         sys_openat2
 438    n32     pidfd_getfd                     sys_pidfd_getfd
+439    n32     faccessat2                      sys_faccessat2
index c0b9d802dbf6dd82c9b4be2a799871a5df8ef3db..da8c76394e178fc4ca26522684eee4e5ac0a4a2a 100644 (file)
 435    n64     clone3                          __sys_clone3
 437    n64     openat2                         sys_openat2
 438    n64     pidfd_getfd                     sys_pidfd_getfd
+439    n64     faccessat2                      sys_faccessat2
index ac586774c980537ed69d85ab4850adb79cd2c9e8..13280625d312e98dcebdaafaca210a353c4a43d9 100644 (file)
 435    o32     clone3                          __sys_clone3
 437    o32     openat2                         sys_openat2
 438    o32     pidfd_getfd                     sys_pidfd_getfd
+439    o32     faccessat2                      sys_faccessat2
index 52a15f5cd1308d222a821a231244d0471ab7be07..5a758fa6ec52427615cb8a0dfbfc938b4dc0d96c 100644 (file)
 435    common  clone3                          sys_clone3_wrapper
 437    common  openat2                         sys_openat2
 438    common  pidfd_getfd                     sys_pidfd_getfd
+439    common  faccessat2                      sys_faccessat2
index 220ae11555f2e1d739a8d0faefd2f416c35b00b2..f833a319082247ecc302f9bd25806c7677a64221 100644 (file)
 435    spu     clone3                          sys_ni_syscall
 437    common  openat2                         sys_openat2
 438    common  pidfd_getfd                     sys_pidfd_getfd
+439    common  faccessat2                      sys_faccessat2
index bd7bd3581a0fcd4f830d774c8fb98b53fa0066db..bfdcb7633957355c4fa5b4d397f52e13534a5141 100644 (file)
 435  common    clone3                  sys_clone3                      sys_clone3
 437  common    openat2                 sys_openat2                     sys_openat2
 438  common    pidfd_getfd             sys_pidfd_getfd                 sys_pidfd_getfd
+439  common    faccessat2              sys_faccessat2                  sys_faccessat2
index c7a30fcd135f89cc4882ed67e8c6bf5a4ea54347..acc35daa1b7924eb697cd822892d757174e51d90 100644 (file)
 # 435 reserved for clone3
 437    common  openat2                         sys_openat2
 438    common  pidfd_getfd                     sys_pidfd_getfd
+439    common  faccessat2                      sys_faccessat2
index f13615ecdecce2f69adbd13576b03a6aa4d8fbef..8004a276cb74be3c2e2ff0f9053d884f3936cc61 100644 (file)
 # 435 reserved for clone3
 437    common  openat2                 sys_openat2
 438    common  pidfd_getfd                     sys_pidfd_getfd
+439    common  faccessat2                      sys_faccessat2
index 54581ac671b41ab0280f5690df817d7c2763283b..d8f8a1a69ed11f7e11bbba2bb17301dc7501cae1 100644 (file)
 435    i386    clone3                  sys_clone3
 437    i386    openat2                 sys_openat2
 438    i386    pidfd_getfd             sys_pidfd_getfd
+439    i386    faccessat2              sys_faccessat2
index 37b844f839bc4f4b07f292a26ee5d5987ccdcd1c..78847b32e1370f56f273020e64a36e0a054bded4 100644 (file)
 435    common  clone3                  sys_clone3
 437    common  openat2                 sys_openat2
 438    common  pidfd_getfd             sys_pidfd_getfd
+439    common  faccessat2              sys_faccessat2
 
 #
 # x32-specific system call numbers start at 512 to avoid cache impact
index 85a9ab1bc04dab5cae943dbe168aedfe452fa6de..69d0d73876b31070dd3d3a98a83b411e7dded16e 100644 (file)
 435    common  clone3                          sys_clone3
 437    common  openat2                         sys_openat2
 438    common  pidfd_getfd                     sys_pidfd_getfd
+439    common  faccessat2                      sys_faccessat2
index aa5d45524e87da09d728abe6c7868bce8fb4d030..0d467e32dd7e90a5f3f542d177e98bb331b57f8e 100644 (file)
@@ -126,7 +126,6 @@ extern struct open_how build_open_how(int flags, umode_t mode);
 extern int build_open_flags(const struct open_how *how, struct open_flags *op);
 
 long do_sys_ftruncate(unsigned int fd, loff_t length, int small);
-long do_faccessat(int dfd, const char __user *filename, int mode);
 int do_fchmodat(int dfd, const char __user *filename, umode_t mode);
 int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group,
                int flag);
index 0ea3cd1a12501c71ef203027e7d4772ebedb5366..e62b1db06638910d2401c9d685400cfbd506ae99 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -394,20 +394,30 @@ static const struct cred *access_override_creds(void)
        return old_cred;
 }
 
-long do_faccessat(int dfd, const char __user *filename, int mode)
+long do_faccessat(int dfd, const char __user *filename, int mode, int flags)
 {
        struct path path;
        struct inode *inode;
        int res;
        unsigned int lookup_flags = LOOKUP_FOLLOW;
-       const struct cred *old_cred;
+       const struct cred *old_cred = NULL;
 
        if (mode & ~S_IRWXO)    /* where's F_OK, X_OK, W_OK, R_OK? */
                return -EINVAL;
 
-       old_cred = access_override_creds();
-       if (!old_cred)
-               return -ENOMEM;
+       if (flags & ~(AT_EACCESS | AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH))
+               return -EINVAL;
+
+       if (flags & AT_SYMLINK_NOFOLLOW)
+               lookup_flags &= ~LOOKUP_FOLLOW;
+       if (flags & AT_EMPTY_PATH)
+               lookup_flags |= LOOKUP_EMPTY;
+
+       if (!(flags & AT_EACCESS)) {
+               old_cred = access_override_creds();
+               if (!old_cred)
+                       return -ENOMEM;
+       }
 
 retry:
        res = user_path_at(dfd, filename, lookup_flags, &path);
@@ -450,18 +460,26 @@ out_path_release:
                goto retry;
        }
 out:
-       revert_creds(old_cred);
+       if (old_cred)
+               revert_creds(old_cred);
+
        return res;
 }
 
 SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode)
 {
-       return do_faccessat(dfd, filename, mode);
+       return do_faccessat(dfd, filename, mode, 0);
+}
+
+SYSCALL_DEFINE4(faccessat2, int, dfd, const char __user *, filename, int, mode,
+               int, flags)
+{
+       return do_faccessat(dfd, filename, mode, flags);
 }
 
 SYSCALL_DEFINE2(access, const char __user *, filename, int, mode)
 {
-       return do_faccessat(AT_FDCWD, filename, mode);
+       return do_faccessat(AT_FDCWD, filename, mode, 0);
 }
 
 int ksys_chdir(const char __user *filename)
index 1815065d52f37a699e7d49df244f273a4f266a10..7c354c2955f51e78fbfd638dd3109f30a9398e0f 100644 (file)
@@ -428,6 +428,8 @@ asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length);
 #endif
 asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len);
 asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode);
+asmlinkage long sys_faccessat2(int dfd, const char __user *filename, int mode,
+                              int flags);
 asmlinkage long sys_chdir(const char __user *filename);
 asmlinkage long sys_fchdir(unsigned int fd);
 asmlinkage long sys_chroot(const char __user *filename);
@@ -1333,11 +1335,11 @@ static inline int ksys_chmod(const char __user *filename, umode_t mode)
        return do_fchmodat(AT_FDCWD, filename, mode);
 }
 
-extern long do_faccessat(int dfd, const char __user *filename, int mode);
+long do_faccessat(int dfd, const char __user *filename, int mode, int flags);
 
 static inline long ksys_access(const char __user *filename, int mode)
 {
-       return do_faccessat(AT_FDCWD, filename, mode);
+       return do_faccessat(AT_FDCWD, filename, mode, 0);
 }
 
 extern int do_fchownat(int dfd, const char __user *filename, uid_t user,
index 3a3201e4618ef8c7445895b26f6eebbaea1574f9..f4a01305d9a65c14fe46652970ec3195a8bce61c 100644 (file)
@@ -855,9 +855,11 @@ __SYSCALL(__NR_clone3, sys_clone3)
 __SYSCALL(__NR_openat2, sys_openat2)
 #define __NR_pidfd_getfd 438
 __SYSCALL(__NR_pidfd_getfd, sys_pidfd_getfd)
+#define __NR_faccessat2 439
+__SYSCALL(__NR_faccessat2, sys_faccessat2)
 
 #undef __NR_syscalls
-#define __NR_syscalls 439
+#define __NR_syscalls 440
 
 /*
  * 32 bit systems traditionally used different
index ca88b7bce55385b41203284196923d09250f2ea3..2f86b2ad6d7e9d6bd7478c369dc301899a37a791 100644 (file)
 #define DN_ATTRIB      0x00000020      /* File changed attibutes */
 #define DN_MULTISHOT   0x80000000      /* Don't remove notifier */
 
+/*
+ * The constants AT_REMOVEDIR and AT_EACCESS have the same value.  AT_EACCESS is
+ * meaningful only to faccessat, while AT_REMOVEDIR is meaningful only to
+ * unlinkat.  The two functions do completely different things and therefore,
+ * the flags can be allowed to overlap.  For example, passing AT_REMOVEDIR to
+ * faccessat would be undefined behavior and thus treating it equivalent to
+ * AT_EACCESS is valid undefined behavior.
+ */
 #define AT_FDCWD               -100    /* Special value used to indicate
                                            openat should use the current
                                            working directory. */
 #define AT_SYMLINK_NOFOLLOW    0x100   /* Do not follow symbolic links.  */
+#define AT_EACCESS             0x200   /* Test access permitted for
+                                           effective IDs, not real IDs.  */
 #define AT_REMOVEDIR           0x200   /* Remove directory instead of
                                            unlinking file.  */
 #define AT_SYMLINK_FOLLOW      0x400   /* Follow symbolic links.  */