While we're at it -- to make testing for error codes with ASSERT_*
easier, make the sys_* wrappers return -errno in case of an error.

For some reason, the <sys/sysinfo.h> include doesn't correct import
<asm/posix_types.h>, leading to compilation errors -- so just import
<asm/posix_types.h> manually.

Signed-off-by: Aleksa Sarai <cyp...@cyphar.com>
---
 tools/include/uapi/asm-generic/posix_types.h       | 101 +++++++++++++++++++++
 tools/testing/selftests/mount_setattr/Makefile     |   2 +-
 .../selftests/mount_setattr/mount_setattr_test.c   |  53 ++++++++++-
 3 files changed, 153 insertions(+), 3 deletions(-)

diff --git a/tools/include/uapi/asm-generic/posix_types.h 
b/tools/include/uapi/asm-generic/posix_types.h
new file mode 100644
index 000000000000..b5f7594eee7a
--- /dev/null
+++ b/tools/include/uapi/asm-generic/posix_types.h
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __ASM_GENERIC_POSIX_TYPES_H
+#define __ASM_GENERIC_POSIX_TYPES_H
+
+#include <asm/bitsperlong.h>
+/*
+ * This file is generally used by user-level software, so you need to
+ * be a little careful about namespace pollution etc.
+ *
+ * First the types that are often defined in different ways across
+ * architectures, so that you can override them.
+ */
+
+#ifndef __kernel_long_t
+typedef long           __kernel_long_t;
+typedef unsigned long  __kernel_ulong_t;
+#endif
+
+#ifndef __kernel_ino_t
+typedef __kernel_ulong_t __kernel_ino_t;
+#endif
+
+#ifndef __kernel_mode_t
+typedef unsigned int   __kernel_mode_t;
+#endif
+
+#ifndef __kernel_pid_t
+typedef int            __kernel_pid_t;
+#endif
+
+#ifndef __kernel_ipc_pid_t
+typedef int            __kernel_ipc_pid_t;
+#endif
+
+#ifndef __kernel_uid_t
+typedef unsigned int   __kernel_uid_t;
+typedef unsigned int   __kernel_gid_t;
+#endif
+
+#ifndef __kernel_suseconds_t
+typedef __kernel_long_t                __kernel_suseconds_t;
+#endif
+
+#ifndef __kernel_daddr_t
+typedef int            __kernel_daddr_t;
+#endif
+
+#ifndef __kernel_uid32_t
+typedef unsigned int   __kernel_uid32_t;
+typedef unsigned int   __kernel_gid32_t;
+#endif
+
+#ifndef __kernel_old_uid_t
+typedef __kernel_uid_t __kernel_old_uid_t;
+typedef __kernel_gid_t __kernel_old_gid_t;
+#endif
+
+#ifndef __kernel_old_dev_t
+typedef unsigned int   __kernel_old_dev_t;
+#endif
+
+/*
+ * Most 32 bit architectures use "unsigned int" size_t,
+ * and all 64 bit architectures use "unsigned long" size_t.
+ */
+#ifndef __kernel_size_t
+#if __BITS_PER_LONG != 64
+typedef unsigned int   __kernel_size_t;
+typedef int            __kernel_ssize_t;
+typedef int            __kernel_ptrdiff_t;
+#else
+typedef __kernel_ulong_t __kernel_size_t;
+typedef __kernel_long_t        __kernel_ssize_t;
+typedef __kernel_long_t        __kernel_ptrdiff_t;
+#endif
+#endif
+
+#ifndef __kernel_fsid_t
+typedef struct {
+       int     val[2];
+} __kernel_fsid_t;
+#endif
+
+/*
+ * anything below here should be completely generic
+ */
+typedef __kernel_long_t        __kernel_off_t;
+typedef long long      __kernel_loff_t;
+typedef __kernel_long_t        __kernel_old_time_t;
+#ifndef __KERNEL__
+typedef __kernel_long_t        __kernel_time_t;
+#endif
+typedef long long __kernel_time64_t;
+typedef __kernel_long_t        __kernel_clock_t;
+typedef int            __kernel_timer_t;
+typedef int            __kernel_clockid_t;
+typedef char *         __kernel_caddr_t;
+typedef unsigned short __kernel_uid16_t;
+typedef unsigned short __kernel_gid16_t;
+
+#endif /* __ASM_GENERIC_POSIX_TYPES_H */
diff --git a/tools/testing/selftests/mount_setattr/Makefile 
b/tools/testing/selftests/mount_setattr/Makefile
index 0c0d7b1234c1..3f260506fe60 100644
--- a/tools/testing/selftests/mount_setattr/Makefile
+++ b/tools/testing/selftests/mount_setattr/Makefile
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 # Makefile for mount selftests.
-CFLAGS = -g $(KHDR_INCLUDES) -Wall -O2 -pthread
+CFLAGS = -g $(KHDR_INCLUDES) $(TOOLS_INCLUDES) -Wall -O2 -pthread
 
 TEST_GEN_PROGS := mount_setattr_test
 
diff --git a/tools/testing/selftests/mount_setattr/mount_setattr_test.c 
b/tools/testing/selftests/mount_setattr/mount_setattr_test.c
index c6a8c732b802..36b8286e5f43 100644
--- a/tools/testing/selftests/mount_setattr/mount_setattr_test.c
+++ b/tools/testing/selftests/mount_setattr/mount_setattr_test.c
@@ -11,6 +11,7 @@
 #include <sys/wait.h>
 #include <sys/vfs.h>
 #include <sys/statvfs.h>
+#include <asm/posix_types.h> /* get __kernel_* typedefs */
 #include <sys/sysinfo.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -137,7 +138,8 @@
 static inline int sys_mount_setattr(int dfd, const char *path, unsigned int 
flags,
                                    struct mount_attr *attr, size_t size)
 {
-       return syscall(__NR_mount_setattr, dfd, path, flags, attr, size);
+       int ret = syscall(__NR_mount_setattr, dfd, path, flags, attr, size);
+       return ret >= 0 ? ret : -errno;
 }
 
 #ifndef OPEN_TREE_CLONE
@@ -152,9 +154,24 @@ static inline int sys_mount_setattr(int dfd, const char 
*path, unsigned int flag
 #define AT_RECURSIVE 0x8000 /* Apply to the entire subtree */
 #endif
 
+#define FSMOUNT_VALID_FLAGS                                                    
\
+       (MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOSUID | MOUNT_ATTR_NODEV |            \
+        MOUNT_ATTR_NOEXEC | MOUNT_ATTR__ATIME | MOUNT_ATTR_NODIRATIME |       \
+        MOUNT_ATTR_NOSYMFOLLOW)
+
+#define MOUNT_SETATTR_VALID_FLAGS (FSMOUNT_VALID_FLAGS | MOUNT_ATTR_IDMAP)
+
+#define MOUNT_SETATTR_PROPAGATION_FLAGS \
+       (MS_UNBINDABLE | MS_PRIVATE | MS_SLAVE | MS_SHARED)
+
+#ifndef CHECK_FIELDS
+#define CHECK_FIELDS (1ULL << 63)
+#endif
+
 static inline int sys_open_tree(int dfd, const char *filename, unsigned int 
flags)
 {
-       return syscall(__NR_open_tree, dfd, filename, flags);
+       int ret = syscall(__NR_open_tree, dfd, filename, flags);
+       return ret >= 0 ? ret : -errno;
 }
 
 static ssize_t write_nointr(int fd, const void *buf, size_t count)
@@ -1497,4 +1514,36 @@ TEST_F(mount_setattr, mount_attr_nosymfollow)
        ASSERT_EQ(close(fd), 0);
 }
 
+TEST_F(mount_setattr, check_fields)
+{
+       struct mount_attr_ext {
+               struct mount_attr inner;
+               uint64_t extra1;
+               uint64_t extra2;
+               uint64_t extra3;
+       } attr;
+
+       /* Set the structure to dummy values. */
+       memset(&attr, 0xAB, sizeof(attr));
+
+       if (!mount_setattr_supported())
+               SKIP(return, "mount_setattr syscall not supported");
+
+       /* Make sure that invalid sizes are detected even with CHECK_FIELDS. */
+       EXPECT_EQ(sys_mount_setattr(-1, "", 0, (struct mount_attr *) &attr, 
CHECK_FIELDS), -EINVAL);
+       EXPECT_EQ(sys_mount_setattr(-1, "", 0, (struct mount_attr *) &attr, 
CHECK_FIELDS | 0xF000), -E2BIG);
+
+       /* Actually get the CHECK_FIELDS results. */
+       ASSERT_EQ(sys_mount_setattr(-1, "", 0, (struct mount_attr *) &attr, 
CHECK_FIELDS | sizeof(attr)), -EEXTSYS_NOOP);
+
+       EXPECT_EQ(attr.inner.attr_set, MOUNT_SETATTR_VALID_FLAGS);
+       EXPECT_EQ(attr.inner.attr_clr, MOUNT_SETATTR_VALID_FLAGS);
+       EXPECT_EQ(attr.inner.propagation, MOUNT_SETATTR_PROPAGATION_FLAGS);
+       EXPECT_EQ(attr.inner.userns_fd, 0xFFFFFFFFFFFFFFFF);
+       /* Trailing fields outside ksize must be zeroed. */
+       EXPECT_EQ(attr.extra1, 0);
+       EXPECT_EQ(attr.extra2, 0);
+       EXPECT_EQ(attr.extra3, 0);
+}
+
 TEST_HARNESS_MAIN

-- 
2.46.1


Reply via email to