Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests: Handle old glibc without execveat(2)

Add an execveat(2) wrapper because glibc < 2.34 does not have one. This
fixes the check-exec tests and samples.

Cc: Günther Noack <gnoack@google.com>
Cc: Jeff Xu <jeffxu@chromium.org>
Cc: Kees Cook <kees@kernel.org>
Cc: Mimi Zohar <zohar@linux.ibm.com>
Cc: Paul Moore <paul@paul-moore.com>
Cc: Roberto Sassu <roberto.sassu@huawei.com>
Cc: Serge Hallyn <serge@hallyn.com>
Cc: Stefan Berger <stefanb@linux.ibm.com>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Reported-by: Nathan Chancellor <nathan@kernel.org>
Closes: https://lore.kernel.org/r/20250114205645.GA2825031@ax162
Signed-off-by: Mickaël Salaün <mic@digikod.net>
Reviewed-by: Günther Noack <gnoack3000@gmail.com>
Link: https://lore.kernel.org/r/20250115144753.311152-1-mic@digikod.net
Signed-off-by: Kees Cook <kees@kernel.org>

authored by

Mickaël Salaün and committed by
Kees Cook
38567b97 95b3cdaf

+26 -6
+9 -2
samples/check-exec/inc.c
··· 21 21 #include <stdlib.h> 22 22 #include <string.h> 23 23 #include <sys/prctl.h> 24 + #include <sys/syscall.h> 24 25 #include <unistd.h> 26 + 27 + static int sys_execveat(int dirfd, const char *pathname, char *const argv[], 28 + char *const envp[], int flags) 29 + { 30 + return syscall(__NR_execveat, dirfd, pathname, argv, envp, flags); 31 + } 25 32 26 33 /* Returns 1 on error, 0 otherwise. */ 27 34 static int interpret_buffer(char *buffer, size_t buffer_size) ··· 85 78 * script execution. We must use the script file descriptor instead of 86 79 * the script path name to avoid race conditions. 87 80 */ 88 - err = execveat(fileno(script), "", script_argv, envp, 89 - AT_EMPTY_PATH | AT_EXECVE_CHECK); 81 + err = sys_execveat(fileno(script), "", script_argv, envp, 82 + AT_EMPTY_PATH | AT_EXECVE_CHECK); 90 83 if (err && restrict_stream) { 91 84 perror("ERROR: Script execution check"); 92 85 return 1;
+9 -2
tools/testing/selftests/exec/check-exec.c
··· 22 22 #include <sys/prctl.h> 23 23 #include <sys/socket.h> 24 24 #include <sys/stat.h> 25 + #include <sys/syscall.h> 25 26 #include <sys/sysmacros.h> 26 27 #include <unistd.h> 27 28 ··· 31 30 #include <linux/fcntl.h> 32 31 33 32 #include "../kselftest_harness.h" 33 + 34 + static int sys_execveat(int dirfd, const char *pathname, char *const argv[], 35 + char *const envp[], int flags) 36 + { 37 + return syscall(__NR_execveat, dirfd, pathname, argv, envp, flags); 38 + } 34 39 35 40 static void drop_privileges(struct __test_metadata *const _metadata) 36 41 { ··· 226 219 * test framework as an error. With AT_EXECVE_CHECK, we only check a 227 220 * potential successful execution. 228 221 */ 229 - access_ret = 230 - execveat(fd, "", argv, NULL, AT_EMPTY_PATH | AT_EXECVE_CHECK); 222 + access_ret = sys_execveat(fd, "", argv, NULL, 223 + AT_EMPTY_PATH | AT_EXECVE_CHECK); 231 224 access_errno = errno; 232 225 if (err_code) { 233 226 EXPECT_EQ(-1, access_ret);
+8 -2
tools/testing/selftests/landlock/fs_test.c
··· 59 59 } 60 60 #endif 61 61 62 + static int sys_execveat(int dirfd, const char *pathname, char *const argv[], 63 + char *const envp[], int flags) 64 + { 65 + return syscall(__NR_execveat, dirfd, pathname, argv, envp, flags); 66 + } 67 + 62 68 #ifndef RENAME_EXCHANGE 63 69 #define RENAME_EXCHANGE (1 << 1) 64 70 #endif ··· 2024 2018 int ret; 2025 2019 char *const argv[] = { (char *)path, NULL }; 2026 2020 2027 - ret = execveat(AT_FDCWD, path, argv, NULL, 2028 - AT_EMPTY_PATH | AT_EXECVE_CHECK); 2021 + ret = sys_execveat(AT_FDCWD, path, argv, NULL, 2022 + AT_EMPTY_PATH | AT_EXECVE_CHECK); 2029 2023 if (err) { 2030 2024 EXPECT_EQ(-1, ret); 2031 2025 EXPECT_EQ(errno, err);