162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2014 Google, Inc. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Selftests for execveat(2). 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#ifndef _GNU_SOURCE 962306a36Sopenharmony_ci#define _GNU_SOURCE /* to get O_PATH, AT_EMPTY_PATH */ 1062306a36Sopenharmony_ci#endif 1162306a36Sopenharmony_ci#include <sys/sendfile.h> 1262306a36Sopenharmony_ci#include <sys/stat.h> 1362306a36Sopenharmony_ci#include <sys/syscall.h> 1462306a36Sopenharmony_ci#include <sys/types.h> 1562306a36Sopenharmony_ci#include <sys/wait.h> 1662306a36Sopenharmony_ci#include <errno.h> 1762306a36Sopenharmony_ci#include <fcntl.h> 1862306a36Sopenharmony_ci#include <limits.h> 1962306a36Sopenharmony_ci#include <stdio.h> 2062306a36Sopenharmony_ci#include <stdlib.h> 2162306a36Sopenharmony_ci#include <string.h> 2262306a36Sopenharmony_ci#include <unistd.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "../kselftest.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic char longpath[2 * PATH_MAX] = ""; 2762306a36Sopenharmony_cistatic char *envp[] = { "IN_TEST=yes", NULL, NULL }; 2862306a36Sopenharmony_cistatic char *argv[] = { "execveat", "99", NULL }; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic int execveat_(int fd, const char *path, char **argv, char **envp, 3162306a36Sopenharmony_ci int flags) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci#ifdef __NR_execveat 3462306a36Sopenharmony_ci return syscall(__NR_execveat, fd, path, argv, envp, flags); 3562306a36Sopenharmony_ci#else 3662306a36Sopenharmony_ci errno = ENOSYS; 3762306a36Sopenharmony_ci return -1; 3862306a36Sopenharmony_ci#endif 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define check_execveat_fail(fd, path, flags, errno) \ 4262306a36Sopenharmony_ci _check_execveat_fail(fd, path, flags, errno, #errno) 4362306a36Sopenharmony_cistatic int _check_execveat_fail(int fd, const char *path, int flags, 4462306a36Sopenharmony_ci int expected_errno, const char *errno_str) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci int rc; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci errno = 0; 4962306a36Sopenharmony_ci printf("Check failure of execveat(%d, '%s', %d) with %s... ", 5062306a36Sopenharmony_ci fd, path?:"(null)", flags, errno_str); 5162306a36Sopenharmony_ci rc = execveat_(fd, path, argv, envp, flags); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci if (rc > 0) { 5462306a36Sopenharmony_ci printf("[FAIL] (unexpected success from execveat(2))\n"); 5562306a36Sopenharmony_ci return 1; 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci if (errno != expected_errno) { 5862306a36Sopenharmony_ci printf("[FAIL] (expected errno %d (%s) not %d (%s)\n", 5962306a36Sopenharmony_ci expected_errno, strerror(expected_errno), 6062306a36Sopenharmony_ci errno, strerror(errno)); 6162306a36Sopenharmony_ci return 1; 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci printf("[OK]\n"); 6462306a36Sopenharmony_ci return 0; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic int check_execveat_invoked_rc(int fd, const char *path, int flags, 6862306a36Sopenharmony_ci int expected_rc, int expected_rc2) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci int status; 7162306a36Sopenharmony_ci int rc; 7262306a36Sopenharmony_ci pid_t child; 7362306a36Sopenharmony_ci int pathlen = path ? strlen(path) : 0; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (pathlen > 40) 7662306a36Sopenharmony_ci printf("Check success of execveat(%d, '%.20s...%s', %d)... ", 7762306a36Sopenharmony_ci fd, path, (path + pathlen - 20), flags); 7862306a36Sopenharmony_ci else 7962306a36Sopenharmony_ci printf("Check success of execveat(%d, '%s', %d)... ", 8062306a36Sopenharmony_ci fd, path?:"(null)", flags); 8162306a36Sopenharmony_ci child = fork(); 8262306a36Sopenharmony_ci if (child < 0) { 8362306a36Sopenharmony_ci printf("[FAIL] (fork() failed)\n"); 8462306a36Sopenharmony_ci return 1; 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci if (child == 0) { 8762306a36Sopenharmony_ci /* Child: do execveat(). */ 8862306a36Sopenharmony_ci rc = execveat_(fd, path, argv, envp, flags); 8962306a36Sopenharmony_ci printf("[FAIL]: execveat() failed, rc=%d errno=%d (%s)\n", 9062306a36Sopenharmony_ci rc, errno, strerror(errno)); 9162306a36Sopenharmony_ci exit(1); /* should not reach here */ 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci /* Parent: wait for & check child's exit status. */ 9462306a36Sopenharmony_ci rc = waitpid(child, &status, 0); 9562306a36Sopenharmony_ci if (rc != child) { 9662306a36Sopenharmony_ci printf("[FAIL] (waitpid(%d,...) returned %d)\n", child, rc); 9762306a36Sopenharmony_ci return 1; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci if (!WIFEXITED(status)) { 10062306a36Sopenharmony_ci printf("[FAIL] (child %d did not exit cleanly, status=%08x)\n", 10162306a36Sopenharmony_ci child, status); 10262306a36Sopenharmony_ci return 1; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci if ((WEXITSTATUS(status) != expected_rc) && 10562306a36Sopenharmony_ci (WEXITSTATUS(status) != expected_rc2)) { 10662306a36Sopenharmony_ci printf("[FAIL] (child %d exited with %d not %d nor %d)\n", 10762306a36Sopenharmony_ci child, WEXITSTATUS(status), expected_rc, expected_rc2); 10862306a36Sopenharmony_ci return 1; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci printf("[OK]\n"); 11162306a36Sopenharmony_ci return 0; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic int check_execveat(int fd, const char *path, int flags) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci return check_execveat_invoked_rc(fd, path, flags, 99, 99); 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic char *concat(const char *left, const char *right) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci char *result = malloc(strlen(left) + strlen(right) + 1); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci strcpy(result, left); 12462306a36Sopenharmony_ci strcat(result, right); 12562306a36Sopenharmony_ci return result; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic int open_or_die(const char *filename, int flags) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci int fd = open(filename, flags); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (fd < 0) { 13362306a36Sopenharmony_ci printf("Failed to open '%s'; " 13462306a36Sopenharmony_ci "check prerequisites are available\n", filename); 13562306a36Sopenharmony_ci exit(1); 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci return fd; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic void exe_cp(const char *src, const char *dest) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci int in_fd = open_or_die(src, O_RDONLY); 14362306a36Sopenharmony_ci int out_fd = open(dest, O_RDWR|O_CREAT|O_TRUNC, 0755); 14462306a36Sopenharmony_ci struct stat info; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci fstat(in_fd, &info); 14762306a36Sopenharmony_ci sendfile(out_fd, in_fd, NULL, info.st_size); 14862306a36Sopenharmony_ci close(in_fd); 14962306a36Sopenharmony_ci close(out_fd); 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci#define XX_DIR_LEN 200 15362306a36Sopenharmony_cistatic int check_execveat_pathmax(int root_dfd, const char *src, int is_script) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci int fail = 0; 15662306a36Sopenharmony_ci int ii, count, len; 15762306a36Sopenharmony_ci char longname[XX_DIR_LEN + 1]; 15862306a36Sopenharmony_ci int fd; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (*longpath == '\0') { 16162306a36Sopenharmony_ci /* Create a filename close to PATH_MAX in length */ 16262306a36Sopenharmony_ci char *cwd = getcwd(NULL, 0); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (!cwd) { 16562306a36Sopenharmony_ci printf("Failed to getcwd(), errno=%d (%s)\n", 16662306a36Sopenharmony_ci errno, strerror(errno)); 16762306a36Sopenharmony_ci return 2; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci strcpy(longpath, cwd); 17062306a36Sopenharmony_ci strcat(longpath, "/"); 17162306a36Sopenharmony_ci memset(longname, 'x', XX_DIR_LEN - 1); 17262306a36Sopenharmony_ci longname[XX_DIR_LEN - 1] = '/'; 17362306a36Sopenharmony_ci longname[XX_DIR_LEN] = '\0'; 17462306a36Sopenharmony_ci count = (PATH_MAX - 3 - strlen(cwd)) / XX_DIR_LEN; 17562306a36Sopenharmony_ci for (ii = 0; ii < count; ii++) { 17662306a36Sopenharmony_ci strcat(longpath, longname); 17762306a36Sopenharmony_ci mkdir(longpath, 0755); 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci len = (PATH_MAX - 3 - strlen(cwd)) - (count * XX_DIR_LEN); 18062306a36Sopenharmony_ci if (len <= 0) 18162306a36Sopenharmony_ci len = 1; 18262306a36Sopenharmony_ci memset(longname, 'y', len); 18362306a36Sopenharmony_ci longname[len] = '\0'; 18462306a36Sopenharmony_ci strcat(longpath, longname); 18562306a36Sopenharmony_ci free(cwd); 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci exe_cp(src, longpath); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* 19062306a36Sopenharmony_ci * Execute as a pre-opened file descriptor, which works whether this is 19162306a36Sopenharmony_ci * a script or not (because the interpreter sees a filename like 19262306a36Sopenharmony_ci * "/dev/fd/20"). 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_ci fd = open(longpath, O_RDONLY); 19562306a36Sopenharmony_ci if (fd > 0) { 19662306a36Sopenharmony_ci printf("Invoke copy of '%s' via filename of length %zu:\n", 19762306a36Sopenharmony_ci src, strlen(longpath)); 19862306a36Sopenharmony_ci fail += check_execveat(fd, "", AT_EMPTY_PATH); 19962306a36Sopenharmony_ci } else { 20062306a36Sopenharmony_ci printf("Failed to open length %zu filename, errno=%d (%s)\n", 20162306a36Sopenharmony_ci strlen(longpath), errno, strerror(errno)); 20262306a36Sopenharmony_ci fail++; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* 20662306a36Sopenharmony_ci * Execute as a long pathname relative to "/". If this is a script, 20762306a36Sopenharmony_ci * the interpreter will launch but fail to open the script because its 20862306a36Sopenharmony_ci * name ("/dev/fd/5/xxx....") is bigger than PATH_MAX. 20962306a36Sopenharmony_ci * 21062306a36Sopenharmony_ci * The failure code is usually 127 (POSIX: "If a command is not found, 21162306a36Sopenharmony_ci * the exit status shall be 127."), but some systems give 126 (POSIX: 21262306a36Sopenharmony_ci * "If the command name is found, but it is not an executable utility, 21362306a36Sopenharmony_ci * the exit status shall be 126."), so allow either. 21462306a36Sopenharmony_ci */ 21562306a36Sopenharmony_ci if (is_script) 21662306a36Sopenharmony_ci fail += check_execveat_invoked_rc(root_dfd, longpath + 1, 0, 21762306a36Sopenharmony_ci 127, 126); 21862306a36Sopenharmony_ci else 21962306a36Sopenharmony_ci fail += check_execveat(root_dfd, longpath + 1, 0); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci return fail; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic int run_tests(void) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci int fail = 0; 22762306a36Sopenharmony_ci char *fullname = realpath("execveat", NULL); 22862306a36Sopenharmony_ci char *fullname_script = realpath("script", NULL); 22962306a36Sopenharmony_ci char *fullname_symlink = concat(fullname, ".symlink"); 23062306a36Sopenharmony_ci int subdir_dfd = open_or_die("subdir", O_DIRECTORY|O_RDONLY); 23162306a36Sopenharmony_ci int subdir_dfd_ephemeral = open_or_die("subdir.ephemeral", 23262306a36Sopenharmony_ci O_DIRECTORY|O_RDONLY); 23362306a36Sopenharmony_ci int dot_dfd = open_or_die(".", O_DIRECTORY|O_RDONLY); 23462306a36Sopenharmony_ci int root_dfd = open_or_die("/", O_DIRECTORY|O_RDONLY); 23562306a36Sopenharmony_ci int dot_dfd_path = open_or_die(".", O_DIRECTORY|O_RDONLY|O_PATH); 23662306a36Sopenharmony_ci int dot_dfd_cloexec = open_or_die(".", O_DIRECTORY|O_RDONLY|O_CLOEXEC); 23762306a36Sopenharmony_ci int fd = open_or_die("execveat", O_RDONLY); 23862306a36Sopenharmony_ci int fd_path = open_or_die("execveat", O_RDONLY|O_PATH); 23962306a36Sopenharmony_ci int fd_symlink = open_or_die("execveat.symlink", O_RDONLY); 24062306a36Sopenharmony_ci int fd_denatured = open_or_die("execveat.denatured", O_RDONLY); 24162306a36Sopenharmony_ci int fd_denatured_path = open_or_die("execveat.denatured", 24262306a36Sopenharmony_ci O_RDONLY|O_PATH); 24362306a36Sopenharmony_ci int fd_script = open_or_die("script", O_RDONLY); 24462306a36Sopenharmony_ci int fd_ephemeral = open_or_die("execveat.ephemeral", O_RDONLY); 24562306a36Sopenharmony_ci int fd_ephemeral_path = open_or_die("execveat.path.ephemeral", 24662306a36Sopenharmony_ci O_RDONLY|O_PATH); 24762306a36Sopenharmony_ci int fd_script_ephemeral = open_or_die("script.ephemeral", O_RDONLY); 24862306a36Sopenharmony_ci int fd_cloexec = open_or_die("execveat", O_RDONLY|O_CLOEXEC); 24962306a36Sopenharmony_ci int fd_script_cloexec = open_or_die("script", O_RDONLY|O_CLOEXEC); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* Check if we have execveat at all, and bail early if not */ 25262306a36Sopenharmony_ci errno = 0; 25362306a36Sopenharmony_ci execveat_(-1, NULL, NULL, NULL, 0); 25462306a36Sopenharmony_ci if (errno == ENOSYS) { 25562306a36Sopenharmony_ci ksft_exit_skip( 25662306a36Sopenharmony_ci "ENOSYS calling execveat - no kernel support?\n"); 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci /* Change file position to confirm it doesn't affect anything */ 26062306a36Sopenharmony_ci lseek(fd, 10, SEEK_SET); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci /* Normal executable file: */ 26362306a36Sopenharmony_ci /* dfd + path */ 26462306a36Sopenharmony_ci fail += check_execveat(subdir_dfd, "../execveat", 0); 26562306a36Sopenharmony_ci fail += check_execveat(dot_dfd, "execveat", 0); 26662306a36Sopenharmony_ci fail += check_execveat(dot_dfd_path, "execveat", 0); 26762306a36Sopenharmony_ci /* absolute path */ 26862306a36Sopenharmony_ci fail += check_execveat(AT_FDCWD, fullname, 0); 26962306a36Sopenharmony_ci /* absolute path with nonsense dfd */ 27062306a36Sopenharmony_ci fail += check_execveat(99, fullname, 0); 27162306a36Sopenharmony_ci /* fd + no path */ 27262306a36Sopenharmony_ci fail += check_execveat(fd, "", AT_EMPTY_PATH); 27362306a36Sopenharmony_ci /* O_CLOEXEC fd + no path */ 27462306a36Sopenharmony_ci fail += check_execveat(fd_cloexec, "", AT_EMPTY_PATH); 27562306a36Sopenharmony_ci /* O_PATH fd */ 27662306a36Sopenharmony_ci fail += check_execveat(fd_path, "", AT_EMPTY_PATH); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* Mess with executable file that's already open: */ 27962306a36Sopenharmony_ci /* fd + no path to a file that's been renamed */ 28062306a36Sopenharmony_ci rename("execveat.ephemeral", "execveat.moved"); 28162306a36Sopenharmony_ci fail += check_execveat(fd_ephemeral, "", AT_EMPTY_PATH); 28262306a36Sopenharmony_ci /* fd + no path to a file that's been deleted */ 28362306a36Sopenharmony_ci unlink("execveat.moved"); /* remove the file now fd open */ 28462306a36Sopenharmony_ci fail += check_execveat(fd_ephemeral, "", AT_EMPTY_PATH); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* Mess with executable file that's already open with O_PATH */ 28762306a36Sopenharmony_ci /* fd + no path to a file that's been deleted */ 28862306a36Sopenharmony_ci unlink("execveat.path.ephemeral"); 28962306a36Sopenharmony_ci fail += check_execveat(fd_ephemeral_path, "", AT_EMPTY_PATH); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* Invalid argument failures */ 29262306a36Sopenharmony_ci fail += check_execveat_fail(fd, "", 0, ENOENT); 29362306a36Sopenharmony_ci fail += check_execveat_fail(fd, NULL, AT_EMPTY_PATH, EFAULT); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* Symlink to executable file: */ 29662306a36Sopenharmony_ci /* dfd + path */ 29762306a36Sopenharmony_ci fail += check_execveat(dot_dfd, "execveat.symlink", 0); 29862306a36Sopenharmony_ci fail += check_execveat(dot_dfd_path, "execveat.symlink", 0); 29962306a36Sopenharmony_ci /* absolute path */ 30062306a36Sopenharmony_ci fail += check_execveat(AT_FDCWD, fullname_symlink, 0); 30162306a36Sopenharmony_ci /* fd + no path, even with AT_SYMLINK_NOFOLLOW (already followed) */ 30262306a36Sopenharmony_ci fail += check_execveat(fd_symlink, "", AT_EMPTY_PATH); 30362306a36Sopenharmony_ci fail += check_execveat(fd_symlink, "", 30462306a36Sopenharmony_ci AT_EMPTY_PATH|AT_SYMLINK_NOFOLLOW); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci /* Symlink fails when AT_SYMLINK_NOFOLLOW set: */ 30762306a36Sopenharmony_ci /* dfd + path */ 30862306a36Sopenharmony_ci fail += check_execveat_fail(dot_dfd, "execveat.symlink", 30962306a36Sopenharmony_ci AT_SYMLINK_NOFOLLOW, ELOOP); 31062306a36Sopenharmony_ci fail += check_execveat_fail(dot_dfd_path, "execveat.symlink", 31162306a36Sopenharmony_ci AT_SYMLINK_NOFOLLOW, ELOOP); 31262306a36Sopenharmony_ci /* absolute path */ 31362306a36Sopenharmony_ci fail += check_execveat_fail(AT_FDCWD, fullname_symlink, 31462306a36Sopenharmony_ci AT_SYMLINK_NOFOLLOW, ELOOP); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* Non-regular file failure */ 31762306a36Sopenharmony_ci fail += check_execveat_fail(dot_dfd, "pipe", 0, EACCES); 31862306a36Sopenharmony_ci unlink("pipe"); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* Shell script wrapping executable file: */ 32162306a36Sopenharmony_ci /* dfd + path */ 32262306a36Sopenharmony_ci fail += check_execveat(subdir_dfd, "../script", 0); 32362306a36Sopenharmony_ci fail += check_execveat(dot_dfd, "script", 0); 32462306a36Sopenharmony_ci fail += check_execveat(dot_dfd_path, "script", 0); 32562306a36Sopenharmony_ci /* absolute path */ 32662306a36Sopenharmony_ci fail += check_execveat(AT_FDCWD, fullname_script, 0); 32762306a36Sopenharmony_ci /* fd + no path */ 32862306a36Sopenharmony_ci fail += check_execveat(fd_script, "", AT_EMPTY_PATH); 32962306a36Sopenharmony_ci fail += check_execveat(fd_script, "", 33062306a36Sopenharmony_ci AT_EMPTY_PATH|AT_SYMLINK_NOFOLLOW); 33162306a36Sopenharmony_ci /* O_CLOEXEC fd fails for a script (as script file inaccessible) */ 33262306a36Sopenharmony_ci fail += check_execveat_fail(fd_script_cloexec, "", AT_EMPTY_PATH, 33362306a36Sopenharmony_ci ENOENT); 33462306a36Sopenharmony_ci fail += check_execveat_fail(dot_dfd_cloexec, "script", 0, ENOENT); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* Mess with script file that's already open: */ 33762306a36Sopenharmony_ci /* fd + no path to a file that's been renamed */ 33862306a36Sopenharmony_ci rename("script.ephemeral", "script.moved"); 33962306a36Sopenharmony_ci fail += check_execveat(fd_script_ephemeral, "", AT_EMPTY_PATH); 34062306a36Sopenharmony_ci /* fd + no path to a file that's been deleted */ 34162306a36Sopenharmony_ci unlink("script.moved"); /* remove the file while fd open */ 34262306a36Sopenharmony_ci fail += check_execveat(fd_script_ephemeral, "", AT_EMPTY_PATH); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* Rename a subdirectory in the path: */ 34562306a36Sopenharmony_ci rename("subdir.ephemeral", "subdir.moved"); 34662306a36Sopenharmony_ci fail += check_execveat(subdir_dfd_ephemeral, "../script", 0); 34762306a36Sopenharmony_ci fail += check_execveat(subdir_dfd_ephemeral, "script", 0); 34862306a36Sopenharmony_ci /* Remove the subdir and its contents */ 34962306a36Sopenharmony_ci unlink("subdir.moved/script"); 35062306a36Sopenharmony_ci unlink("subdir.moved"); 35162306a36Sopenharmony_ci /* Shell loads via deleted subdir OK because name starts with .. */ 35262306a36Sopenharmony_ci fail += check_execveat(subdir_dfd_ephemeral, "../script", 0); 35362306a36Sopenharmony_ci fail += check_execveat_fail(subdir_dfd_ephemeral, "script", 0, ENOENT); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* Flag values other than AT_SYMLINK_NOFOLLOW => EINVAL */ 35662306a36Sopenharmony_ci fail += check_execveat_fail(dot_dfd, "execveat", 0xFFFF, EINVAL); 35762306a36Sopenharmony_ci /* Invalid path => ENOENT */ 35862306a36Sopenharmony_ci fail += check_execveat_fail(dot_dfd, "no-such-file", 0, ENOENT); 35962306a36Sopenharmony_ci fail += check_execveat_fail(dot_dfd_path, "no-such-file", 0, ENOENT); 36062306a36Sopenharmony_ci fail += check_execveat_fail(AT_FDCWD, "no-such-file", 0, ENOENT); 36162306a36Sopenharmony_ci /* Attempt to execute directory => EACCES */ 36262306a36Sopenharmony_ci fail += check_execveat_fail(dot_dfd, "", AT_EMPTY_PATH, EACCES); 36362306a36Sopenharmony_ci /* Attempt to execute non-executable => EACCES */ 36462306a36Sopenharmony_ci fail += check_execveat_fail(dot_dfd, "Makefile", 0, EACCES); 36562306a36Sopenharmony_ci fail += check_execveat_fail(fd_denatured, "", AT_EMPTY_PATH, EACCES); 36662306a36Sopenharmony_ci fail += check_execveat_fail(fd_denatured_path, "", AT_EMPTY_PATH, 36762306a36Sopenharmony_ci EACCES); 36862306a36Sopenharmony_ci /* Attempt to execute nonsense FD => EBADF */ 36962306a36Sopenharmony_ci fail += check_execveat_fail(99, "", AT_EMPTY_PATH, EBADF); 37062306a36Sopenharmony_ci fail += check_execveat_fail(99, "execveat", 0, EBADF); 37162306a36Sopenharmony_ci /* Attempt to execute relative to non-directory => ENOTDIR */ 37262306a36Sopenharmony_ci fail += check_execveat_fail(fd, "execveat", 0, ENOTDIR); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci fail += check_execveat_pathmax(root_dfd, "execveat", 0); 37562306a36Sopenharmony_ci fail += check_execveat_pathmax(root_dfd, "script", 1); 37662306a36Sopenharmony_ci return fail; 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic void prerequisites(void) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci int fd; 38262306a36Sopenharmony_ci const char *script = "#!/bin/sh\nexit $*\n"; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* Create ephemeral copies of files */ 38562306a36Sopenharmony_ci exe_cp("execveat", "execveat.ephemeral"); 38662306a36Sopenharmony_ci exe_cp("execveat", "execveat.path.ephemeral"); 38762306a36Sopenharmony_ci exe_cp("script", "script.ephemeral"); 38862306a36Sopenharmony_ci mkdir("subdir.ephemeral", 0755); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci fd = open("subdir.ephemeral/script", O_RDWR|O_CREAT|O_TRUNC, 0755); 39162306a36Sopenharmony_ci write(fd, script, strlen(script)); 39262306a36Sopenharmony_ci close(fd); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci mkfifo("pipe", 0755); 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ciint main(int argc, char **argv) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci int ii; 40062306a36Sopenharmony_ci int rc; 40162306a36Sopenharmony_ci const char *verbose = getenv("VERBOSE"); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci if (argc >= 2) { 40462306a36Sopenharmony_ci /* If we are invoked with an argument, don't run tests. */ 40562306a36Sopenharmony_ci const char *in_test = getenv("IN_TEST"); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci if (verbose) { 40862306a36Sopenharmony_ci printf(" invoked with:"); 40962306a36Sopenharmony_ci for (ii = 0; ii < argc; ii++) 41062306a36Sopenharmony_ci printf(" [%d]='%s'", ii, argv[ii]); 41162306a36Sopenharmony_ci printf("\n"); 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci /* Check expected environment transferred. */ 41562306a36Sopenharmony_ci if (!in_test || strcmp(in_test, "yes") != 0) { 41662306a36Sopenharmony_ci printf("[FAIL] (no IN_TEST=yes in env)\n"); 41762306a36Sopenharmony_ci return 1; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci /* Use the final argument as an exit code. */ 42162306a36Sopenharmony_ci rc = atoi(argv[argc - 1]); 42262306a36Sopenharmony_ci fflush(stdout); 42362306a36Sopenharmony_ci } else { 42462306a36Sopenharmony_ci prerequisites(); 42562306a36Sopenharmony_ci if (verbose) 42662306a36Sopenharmony_ci envp[1] = "VERBOSE=1"; 42762306a36Sopenharmony_ci rc = run_tests(); 42862306a36Sopenharmony_ci if (rc > 0) 42962306a36Sopenharmony_ci printf("%d tests failed\n", rc); 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci return rc; 43262306a36Sopenharmony_ci} 433