diff options
Diffstat (limited to 'tools/testing/selftests/exec/execveat.c')
-rw-r--r-- | tools/testing/selftests/exec/execveat.c | 170 |
1 files changed, 129 insertions, 41 deletions
diff --git a/tools/testing/selftests/exec/execveat.c b/tools/testing/selftests/exec/execveat.c index 67bf7254a48f..8fb7395fd35b 100644 --- a/tools/testing/selftests/exec/execveat.c +++ b/tools/testing/selftests/exec/execveat.c @@ -23,6 +23,11 @@ #include "../kselftest.h" +#define TESTS_EXPECTED 54 +#define TEST_NAME_LEN (PATH_MAX * 4) + +#define CHECK_COMM "CHECK_COMM" + static char longpath[2 * PATH_MAX] = ""; static char *envp[] = { "IN_TEST=yes", NULL, NULL }; static char *argv[] = { "execveat", "99", NULL }; @@ -43,71 +48,84 @@ static int execveat_(int fd, const char *path, char **argv, char **envp, static int _check_execveat_fail(int fd, const char *path, int flags, int expected_errno, const char *errno_str) { + char test_name[TEST_NAME_LEN]; int rc; errno = 0; - printf("Check failure of execveat(%d, '%s', %d) with %s... ", - fd, path?:"(null)", flags, errno_str); + snprintf(test_name, sizeof(test_name), + "Check failure of execveat(%d, '%s', %d) with %s", + fd, path?:"(null)", flags, errno_str); rc = execveat_(fd, path, argv, envp, flags); if (rc > 0) { - printf("[FAIL] (unexpected success from execveat(2))\n"); + ksft_print_msg("unexpected success from execveat(2)\n"); + ksft_test_result_fail("%s\n", test_name); return 1; } if (errno != expected_errno) { - printf("[FAIL] (expected errno %d (%s) not %d (%s)\n", - expected_errno, strerror(expected_errno), - errno, strerror(errno)); + ksft_print_msg("expected errno %d (%s) not %d (%s)\n", + expected_errno, strerror(expected_errno), + errno, strerror(errno)); + ksft_test_result_fail("%s\n", test_name); return 1; } - printf("[OK]\n"); + ksft_test_result_pass("%s\n", test_name); return 0; } static int check_execveat_invoked_rc(int fd, const char *path, int flags, int expected_rc, int expected_rc2) { + char test_name[TEST_NAME_LEN]; int status; int rc; pid_t child; int pathlen = path ? strlen(path) : 0; if (pathlen > 40) - printf("Check success of execveat(%d, '%.20s...%s', %d)... ", - fd, path, (path + pathlen - 20), flags); + snprintf(test_name, sizeof(test_name), + "Check success of execveat(%d, '%.20s...%s', %d)... ", + fd, path, (path + pathlen - 20), flags); else - printf("Check success of execveat(%d, '%s', %d)... ", - fd, path?:"(null)", flags); + snprintf(test_name, sizeof(test_name), + "Check success of execveat(%d, '%s', %d)... ", + fd, path?:"(null)", flags); + child = fork(); if (child < 0) { - printf("[FAIL] (fork() failed)\n"); + ksft_perror("fork() failed"); + ksft_test_result_fail("%s\n", test_name); return 1; } if (child == 0) { /* Child: do execveat(). */ rc = execveat_(fd, path, argv, envp, flags); - printf("[FAIL]: execveat() failed, rc=%d errno=%d (%s)\n", - rc, errno, strerror(errno)); - exit(1); /* should not reach here */ + ksft_print_msg("child execveat() failed, rc=%d errno=%d (%s)\n", + rc, errno, strerror(errno)); + exit(errno); } /* Parent: wait for & check child's exit status. */ rc = waitpid(child, &status, 0); if (rc != child) { - printf("[FAIL] (waitpid(%d,...) returned %d)\n", child, rc); + ksft_print_msg("waitpid(%d,...) returned %d\n", child, rc); + ksft_test_result_fail("%s\n", test_name); return 1; } if (!WIFEXITED(status)) { - printf("[FAIL] (child %d did not exit cleanly, status=%08x)\n", - child, status); + ksft_print_msg("child %d did not exit cleanly, status=%08x\n", + child, status); + ksft_test_result_fail("%s\n", test_name); return 1; } if ((WEXITSTATUS(status) != expected_rc) && (WEXITSTATUS(status) != expected_rc2)) { - printf("[FAIL] (child %d exited with %d not %d nor %d)\n", - child, WEXITSTATUS(status), expected_rc, expected_rc2); + ksft_print_msg("child %d exited with %d neither %d nor %d\n", + child, WEXITSTATUS(status), expected_rc, + expected_rc2); + ksft_test_result_fail("%s\n", test_name); return 1; } - printf("[OK]\n"); + ksft_test_result_pass("%s\n", test_name); return 0; } @@ -129,11 +147,9 @@ static int open_or_die(const char *filename, int flags) { int fd = open(filename, flags); - if (fd < 0) { - printf("Failed to open '%s'; " + if (fd < 0) + ksft_exit_fail_msg("Failed to open '%s'; " "check prerequisites are available\n", filename); - exit(1); - } return fd; } @@ -162,8 +178,7 @@ static int check_execveat_pathmax(int root_dfd, const char *src, int is_script) char *cwd = getcwd(NULL, 0); if (!cwd) { - printf("Failed to getcwd(), errno=%d (%s)\n", - errno, strerror(errno)); + ksft_perror("Failed to getcwd()"); return 2; } strcpy(longpath, cwd); @@ -193,12 +208,12 @@ static int check_execveat_pathmax(int root_dfd, const char *src, int is_script) */ fd = open(longpath, O_RDONLY); if (fd > 0) { - printf("Invoke copy of '%s' via filename of length %zu:\n", - src, strlen(longpath)); + ksft_print_msg("Invoke copy of '%s' via filename of length %zu:\n", + src, strlen(longpath)); fail += check_execveat(fd, "", AT_EMPTY_PATH); } else { - printf("Failed to open length %zu filename, errno=%d (%s)\n", - strlen(longpath), errno, strerror(errno)); + ksft_print_msg("Failed to open length %zu filename, errno=%d (%s)\n", + strlen(longpath), errno, strerror(errno)); fail++; } @@ -212,15 +227,41 @@ static int check_execveat_pathmax(int root_dfd, const char *src, int is_script) * "If the command name is found, but it is not an executable utility, * the exit status shall be 126."), so allow either. */ - if (is_script) + if (is_script) { + ksft_print_msg("Invoke script via root_dfd and relative filename\n"); fail += check_execveat_invoked_rc(root_dfd, longpath + 1, 0, 127, 126); - else + } else { + ksft_print_msg("Invoke exec via root_dfd and relative filename\n"); fail += check_execveat(root_dfd, longpath + 1, 0); + } return fail; } +static int check_execveat_comm(int fd, char *argv0, char *expected) +{ + char buf[128], *old_env, *old_argv0; + int ret; + + snprintf(buf, sizeof(buf), CHECK_COMM "=%s", expected); + + old_env = envp[1]; + envp[1] = buf; + + old_argv0 = argv[0]; + argv[0] = argv0; + + ksft_print_msg("Check execveat(AT_EMPTY_PATH)'s comm is %s\n", + expected); + ret = check_execveat_invoked_rc(fd, "", AT_EMPTY_PATH, 0, 0); + + envp[1] = old_env; + argv[0] = old_argv0; + + return ret; +} + static int run_tests(void) { int fail = 0; @@ -373,13 +414,21 @@ static int run_tests(void) fail += check_execveat_pathmax(root_dfd, "execveat", 0); fail += check_execveat_pathmax(root_dfd, "script", 1); + + /* /proc/pid/comm gives filename by default */ + fail += check_execveat_comm(fd, "sentinel", "execveat"); + /* /proc/pid/comm gives argv[0] when invoked via link */ + fail += check_execveat_comm(fd_symlink, "sentinel", "execveat"); + /* /proc/pid/comm gives filename if NULL is passed */ + fail += check_execveat_comm(fd, NULL, "execveat"); + return fail; } static void prerequisites(void) { int fd; - const char *script = "#!/bin/sh\nexit $*\n"; + const char *script = "#!/bin/bash\nexit $*\n"; /* Create ephemeral copies of files */ exe_cp("execveat", "execveat.ephemeral"); @@ -399,34 +448,73 @@ int main(int argc, char **argv) int ii; int rc; const char *verbose = getenv("VERBOSE"); + const char *check_comm = getenv(CHECK_COMM); - if (argc >= 2) { - /* If we are invoked with an argument, don't run tests. */ + if (argc >= 2 || check_comm) { + /* + * If we are invoked with an argument, or no arguments but a + * command to check, don't run tests. + */ const char *in_test = getenv("IN_TEST"); if (verbose) { - printf(" invoked with:"); + ksft_print_msg("invoked with:\n"); for (ii = 0; ii < argc; ii++) - printf(" [%d]='%s'", ii, argv[ii]); - printf("\n"); + ksft_print_msg("\t[%d]='%s\n'", ii, argv[ii]); + } + + /* If the tests wanted us to check the command, do so. */ + if (check_comm) { + /* TASK_COMM_LEN == 16 */ + char buf[32]; + int fd, ret; + + fd = open("/proc/self/comm", O_RDONLY); + if (fd < 0) { + ksft_perror("open() comm failed"); + exit(1); + } + + ret = read(fd, buf, sizeof(buf)); + if (ret < 0) { + ksft_perror("read() comm failed"); + close(fd); + exit(1); + } + close(fd); + + // trim off the \n + buf[ret-1] = 0; + + if (strcmp(buf, check_comm)) { + ksft_print_msg("bad comm, got: %s expected: %s\n", + buf, check_comm); + exit(1); + } + + exit(0); } /* Check expected environment transferred. */ if (!in_test || strcmp(in_test, "yes") != 0) { - printf("[FAIL] (no IN_TEST=yes in env)\n"); + ksft_print_msg("no IN_TEST=yes in env\n"); return 1; } /* Use the final argument as an exit code. */ rc = atoi(argv[argc - 1]); - fflush(stdout); + exit(rc); } else { + ksft_print_header(); + ksft_set_plan(TESTS_EXPECTED); prerequisites(); if (verbose) envp[1] = "VERBOSE=1"; rc = run_tests(); if (rc > 0) printf("%d tests failed\n", rc); + ksft_finished(); } + return rc; } |