git: 15e715fe7c0b - stable/13 - linux(4): Implement faccessat2 system call.

From: Dmitry Chagin <dchagin_at_FreeBSD.org>
Date: Fri, 17 Jun 2022 19:37:54 UTC
The branch stable/13 has been updated by dchagin:

URL: https://cgit.FreeBSD.org/src/commit/?id=15e715fe7c0bb495787a1fec9de8aecd732304ed

commit 15e715fe7c0bb495787a1fec9de8aecd732304ed
Author:     Dmitry Chagin <dchagin@FreeBSD.org>
AuthorDate: 2021-08-12 08:40:42 +0000
Commit:     Dmitry Chagin <dchagin@FreeBSD.org>
CommitDate: 2022-06-17 19:33:26 +0000

    linux(4): Implement faccessat2 system call.
    
    It's used by bash on arm64 with glibc-2.32.
    
    Reviewed by:            trasz
    Differential Revision:  https://reviews.freebsd.org/D31345
    MFC after:              2 weeks
    
    (cherry picked from commit 13d79be9950dd820628906dcad4f4f1365b307b9)
---
 sys/amd64/linux/syscalls.master   |  7 +++++-
 sys/amd64/linux32/syscalls.master |  7 +++++-
 sys/arm64/linux/syscalls.master   |  7 +++++-
 sys/compat/linux/linux_file.c     | 45 +++++++++++++++++++++++++++++++++------
 sys/i386/linux/syscalls.master    |  7 +++++-
 5 files changed, 62 insertions(+), 11 deletions(-)

diff --git a/sys/amd64/linux/syscalls.master b/sys/amd64/linux/syscalls.master
index 4762a2ccc6a5..b9b88a036e61 100644
--- a/sys/amd64/linux/syscalls.master
+++ b/sys/amd64/linux/syscalls.master
@@ -2094,7 +2094,12 @@
 		int linux_pidfd_getfd(void);
 	}
 439    AUE_NULL		STD {
-		int linux_faccessat2(void);
+		int linux_faccessat2(
+		    l_int dfd,
+		    const char *filename,
+		    l_int amode,
+		    l_int flags
+		);
 	}
 440    AUE_NULL		STD {
 		int linux_process_madvise(void);
diff --git a/sys/amd64/linux32/syscalls.master b/sys/amd64/linux32/syscalls.master
index be6c150eebfa..60f227142f01 100644
--- a/sys/amd64/linux32/syscalls.master
+++ b/sys/amd64/linux32/syscalls.master
@@ -2496,7 +2496,12 @@
 		int linux_pidfd_getfd(void);
 	}
 439    AUE_NULL		STD {
-		int linux_faccessat2(void);
+		int linux_faccessat2(
+		    l_int dfd,
+		    const char *filename,
+		    l_int amode,
+		    l_int flags
+		);
 	}
 440    AUE_NULL		STD {
 		int linux_process_madvise(void);
diff --git a/sys/arm64/linux/syscalls.master b/sys/arm64/linux/syscalls.master
index ca45e33d4190..7b4ebbb2c2e9 100644
--- a/sys/arm64/linux/syscalls.master
+++ b/sys/arm64/linux/syscalls.master
@@ -1743,7 +1743,12 @@
 		int linux_pidfd_getfd(void);
 	}
 439    AUE_NULL		STD {
-		int linux_faccessat2(void);
+		int linux_faccessat2(
+		    l_int dfd,
+		    const char *filename,
+		    l_int amode,
+		    l_int flags
+		);
 	}
 440    AUE_NULL		STD {
 		int linux_process_madvise(void);
diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c
index 013c435756fb..a1146c6a195a 100644
--- a/sys/compat/linux/linux_file.c
+++ b/sys/compat/linux/linux_file.c
@@ -70,6 +70,7 @@ __FBSDID("$FreeBSD$");
 
 static int	linux_common_open(struct thread *, int, const char *, int, int,
 		    enum uio_seg);
+static int	linux_do_accessat(struct thread *t, int, const char *, int, int);
 static int	linux_getdents_error(struct thread *, int, int);
 
 static struct bsd_to_linux_bitmap seal_bitmap[] = {
@@ -675,28 +676,58 @@ linux_access(struct thread *td, struct linux_access_args *args)
 }
 #endif
 
-int
-linux_faccessat(struct thread *td, struct linux_faccessat_args *args)
+static int
+linux_do_accessat(struct thread *td, int ldfd, const char *filename,
+    int amode, int flags)
 {
 	char *path;
 	int error, dfd;
 
 	/* Linux convention. */
-	if (args->amode & ~(F_OK | X_OK | W_OK | R_OK))
+	if (amode & ~(F_OK | X_OK | W_OK | R_OK))
 		return (EINVAL);
 
-	dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+	dfd = (ldfd == LINUX_AT_FDCWD) ? AT_FDCWD : ldfd;
 	if (!LUSECONVPATH(td)) {
-		error = kern_accessat(td, dfd, args->filename, UIO_USERSPACE, 0, args->amode);
+		error = kern_accessat(td, dfd, filename, UIO_USERSPACE, flags, amode);
 	} else {
-		LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
-		error = kern_accessat(td, dfd, path, UIO_SYSSPACE, 0, args->amode);
+		LCONVPATHEXIST_AT(td, filename, &path, dfd);
+		error = kern_accessat(td, dfd, path, UIO_SYSSPACE, flags, amode);
 		LFREEPATH(path);
 	}
 
 	return (error);
 }
 
+int
+linux_faccessat(struct thread *td, struct linux_faccessat_args *args)
+{
+
+	return (linux_do_accessat(td, args->dfd, args->filename, args->amode,
+	    0));
+}
+
+int
+linux_faccessat2(struct thread *td, struct linux_faccessat2_args *args)
+{
+	int flags, unsupported;
+
+	/* XXX. AT_SYMLINK_NOFOLLOW is not supported by kern_accessat */
+	unsupported = args->flags & ~(LINUX_AT_EACCESS | LINUX_AT_EMPTY_PATH);
+	if (unsupported != 0) {
+		linux_msg(td, "faccessat2 unsupported flag 0x%x", unsupported);
+		return (EINVAL);
+	}
+
+	flags = (args->flags & LINUX_AT_EACCESS) == 0 ? 0 :
+	    AT_EACCESS;
+	flags |= (args->flags & LINUX_AT_EMPTY_PATH) == 0 ? 0 :
+	    AT_EMPTY_PATH;
+	return (linux_do_accessat(td, args->dfd, args->filename, args->amode,
+	    flags));
+}
+
+
 #ifdef LINUX_LEGACY_SYSCALLS
 int
 linux_unlink(struct thread *td, struct linux_unlink_args *args)
diff --git a/sys/i386/linux/syscalls.master b/sys/i386/linux/syscalls.master
index acbe5628e7ce..3a70c1352b44 100644
--- a/sys/i386/linux/syscalls.master
+++ b/sys/i386/linux/syscalls.master
@@ -2514,7 +2514,12 @@
 		int linux_pidfd_getfd(void);
 	}
 439    AUE_NULL		STD {
-		int linux_faccessat2(void);
+		int linux_faccessat2(
+		    l_int dfd,
+		    const char *filename,
+		    l_int amode,
+		    l_int flags
+		);
 	}
 440    AUE_NULL		STD {
 		int linux_process_madvise(void);