diff --git a/meson.build b/meson.build index 7f5d465783..4f50b32cdf 100644 --- a/meson.build +++ b/meson.build @@ -568,6 +568,8 @@ foreach ident : [ ['memfd_create', '''#include '''], ['gettid', '''#include #include '''], + ['fchmodat2', '''#include + #include '''], # no known header declares fchmodat2 ['pivot_root', '''#include #include '''], # no known header declares pivot_root ['ioprio_get', '''#include '''], # no known header declares ioprio_get diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h index 83ec137fa5..d795efd8f2 100644 --- a/src/basic/missing_syscall.h +++ b/src/basic/missing_syscall.h @@ -32,6 +32,21 @@ /* ======================================================================= */ +#if !HAVE_FCHMODAT2 +static inline int missing_fchmodat2(int dirfd, const char *path, mode_t mode, int flags) { +# ifdef __NR_fchmodat2 + return syscall(__NR_fchmodat2, dirfd, path, mode, flags); +# else + errno = ENOSYS; + return -1; +# endif +} + +# define fchmodat2 missing_fchmodat2 +#endif + +/* ======================================================================= */ + #if !HAVE_PIVOT_ROOT static inline int missing_pivot_root(const char *new_root, const char *put_old) { return syscall(__NR_pivot_root, new_root, put_old); diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c index 56c4b3fd87..279a155cb0 100644 --- a/src/test/test-seccomp.c +++ b/src/test/test-seccomp.c @@ -21,7 +21,7 @@ #include "macro.h" #include "memory-util.h" #include "missing_sched.h" -#include "missing_syscall_def.h" +#include "missing_syscall.h" #include "nsflags.h" #include "nulstr-util.h" #include "process-util.h" @@ -1007,21 +1007,22 @@ static int real_open(const char *path, int flags, mode_t mode) { #endif } -static int try_fchmodat2(int dirfd, const char *path, int flags, mode_t mode) { +static int try_fchmodat2(int dirfd, const char *path, mode_t mode, int flags) { + int r; + /* glibc does not provide a direct wrapper for fchmodat2(). Let's hence define our own wrapper for * testing purposes that calls the real syscall, on architectures and in environments where * SYS_fchmodat2 is defined. Otherwise, let's just fall back to the glibc fchmodat() call. */ -#if defined __NR_fchmodat2 && __NR_fchmodat2 >= 0 - int r; - r = (int) syscall(__NR_fchmodat2, dirfd, path, flags, mode); + /* Not supported by fchmodat() */ + assert_se(!FLAGS_SET(flags, AT_EMPTY_PATH)); + + r = RET_NERRNO(fchmodat2(dirfd, path, mode, flags)); + if (r != -ENOSYS) + return r; + /* The syscall might still be unsupported by kernel or libseccomp. */ - if (r < 0 && errno == ENOSYS) - return fchmodat(dirfd, path, flags, mode); - return r; -#else - return fchmodat(dirfd, path, flags, mode); -#endif + return RET_NERRNO(fchmodat(dirfd, path, mode, flags)); } TEST(restrict_suid_sgid) {