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

selftests/exec: Convert execveat test to generate KTAP output

Currently the execveat test does not produce KTAP output but rather a
custom format. This means that we only get a pass/fail for the suite, not
for each individual test that the suite does. Convert to using the standard
kselftest output functions which result in KTAP output being generated.

The main trick with this is that, being an exec() related test, the
program executes itself and returns specific exit codes to verify
success meaning that we need to only use the top level kselftest
header/summary functions when invoked directly rather than when run as
part of a test.

Signed-off-by: Mark Brown <broonie@kernel.org>
Reviewed-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>

authored by

Mark Brown and committed by
Shuah Khan
47903c1d 907f3302

+52 -35
+52 -35
tools/testing/selftests/exec/execveat.c
··· 23 23 24 24 #include "../kselftest.h" 25 25 26 + #define TESTS_EXPECTED 51 27 + #define TEST_NAME_LEN (PATH_MAX * 4) 28 + 26 29 static char longpath[2 * PATH_MAX] = ""; 27 30 static char *envp[] = { "IN_TEST=yes", NULL, NULL }; 28 31 static char *argv[] = { "execveat", "99", NULL }; ··· 46 43 static int _check_execveat_fail(int fd, const char *path, int flags, 47 44 int expected_errno, const char *errno_str) 48 45 { 46 + char test_name[TEST_NAME_LEN]; 49 47 int rc; 50 48 51 49 errno = 0; 52 - printf("Check failure of execveat(%d, '%s', %d) with %s... ", 53 - fd, path?:"(null)", flags, errno_str); 50 + snprintf(test_name, sizeof(test_name), 51 + "Check failure of execveat(%d, '%s', %d) with %s", 52 + fd, path?:"(null)", flags, errno_str); 54 53 rc = execveat_(fd, path, argv, envp, flags); 55 54 56 55 if (rc > 0) { 57 - printf("[FAIL] (unexpected success from execveat(2))\n"); 56 + ksft_print_msg("unexpected success from execveat(2)\n"); 57 + ksft_test_result_fail("%s\n", test_name); 58 58 return 1; 59 59 } 60 60 if (errno != expected_errno) { 61 - printf("[FAIL] (expected errno %d (%s) not %d (%s)\n", 62 - expected_errno, strerror(expected_errno), 63 - errno, strerror(errno)); 61 + ksft_print_msg("expected errno %d (%s) not %d (%s)\n", 62 + expected_errno, strerror(expected_errno), 63 + errno, strerror(errno)); 64 + ksft_test_result_fail("%s\n", test_name); 64 65 return 1; 65 66 } 66 - printf("[OK]\n"); 67 + ksft_test_result_pass("%s\n", test_name); 67 68 return 0; 68 69 } 69 70 70 71 static int check_execveat_invoked_rc(int fd, const char *path, int flags, 71 72 int expected_rc, int expected_rc2) 72 73 { 74 + char test_name[TEST_NAME_LEN]; 73 75 int status; 74 76 int rc; 75 77 pid_t child; 76 78 int pathlen = path ? strlen(path) : 0; 77 79 78 80 if (pathlen > 40) 79 - printf("Check success of execveat(%d, '%.20s...%s', %d)... ", 80 - fd, path, (path + pathlen - 20), flags); 81 + snprintf(test_name, sizeof(test_name), 82 + "Check success of execveat(%d, '%.20s...%s', %d)... ", 83 + fd, path, (path + pathlen - 20), flags); 81 84 else 82 - printf("Check success of execveat(%d, '%s', %d)... ", 83 - fd, path?:"(null)", flags); 85 + snprintf(test_name, sizeof(test_name), 86 + "Check success of execveat(%d, '%s', %d)... ", 87 + fd, path?:"(null)", flags); 88 + 84 89 child = fork(); 85 90 if (child < 0) { 86 - printf("[FAIL] (fork() failed)\n"); 91 + ksft_perror("fork() failed"); 92 + ksft_test_result_fail("%s\n", test_name); 87 93 return 1; 88 94 } 89 95 if (child == 0) { 90 96 /* Child: do execveat(). */ 91 97 rc = execveat_(fd, path, argv, envp, flags); 92 - printf("[FAIL]: execveat() failed, rc=%d errno=%d (%s)\n", 93 - rc, errno, strerror(errno)); 98 + ksft_print_msg("execveat() failed, rc=%d errno=%d (%s)\n", 99 + rc, errno, strerror(errno)); 100 + ksft_test_result_fail("%s\n", test_name); 94 101 exit(1); /* should not reach here */ 95 102 } 96 103 /* Parent: wait for & check child's exit status. */ 97 104 rc = waitpid(child, &status, 0); 98 105 if (rc != child) { 99 - printf("[FAIL] (waitpid(%d,...) returned %d)\n", child, rc); 106 + ksft_print_msg("waitpid(%d,...) returned %d\n", child, rc); 107 + ksft_test_result_fail("%s\n", test_name); 100 108 return 1; 101 109 } 102 110 if (!WIFEXITED(status)) { 103 - printf("[FAIL] (child %d did not exit cleanly, status=%08x)\n", 104 - child, status); 111 + ksft_print_msg("child %d did not exit cleanly, status=%08x\n", 112 + child, status); 113 + ksft_test_result_fail("%s\n", test_name); 105 114 return 1; 106 115 } 107 116 if ((WEXITSTATUS(status) != expected_rc) && 108 117 (WEXITSTATUS(status) != expected_rc2)) { 109 - printf("[FAIL] (child %d exited with %d not %d nor %d)\n", 110 - child, WEXITSTATUS(status), expected_rc, expected_rc2); 118 + ksft_print_msg("child %d exited with %d not %d nor %d\n", 119 + child, WEXITSTATUS(status), expected_rc, 120 + expected_rc2); 121 + ksft_test_result_fail("%s\n", test_name); 111 122 return 1; 112 123 } 113 - printf("[OK]\n"); 124 + ksft_test_result_pass("%s\n", test_name); 114 125 return 0; 115 126 } 116 127 ··· 146 129 { 147 130 int fd = open(filename, flags); 148 131 149 - if (fd < 0) { 150 - printf("Failed to open '%s'; " 132 + if (fd < 0) 133 + ksft_exit_fail_msg("Failed to open '%s'; " 151 134 "check prerequisites are available\n", filename); 152 - exit(1); 153 - } 154 135 return fd; 155 136 } 156 137 ··· 177 162 char *cwd = getcwd(NULL, 0); 178 163 179 164 if (!cwd) { 180 - printf("Failed to getcwd(), errno=%d (%s)\n", 181 - errno, strerror(errno)); 165 + ksft_perror("Failed to getcwd()"); 182 166 return 2; 183 167 } 184 168 strcpy(longpath, cwd); ··· 207 193 */ 208 194 fd = open(longpath, O_RDONLY); 209 195 if (fd > 0) { 210 - printf("Invoke copy of '%s' via filename of length %zu:\n", 211 - src, strlen(longpath)); 196 + ksft_print_msg("Invoke copy of '%s' via filename of length %zu:\n", 197 + src, strlen(longpath)); 212 198 fail += check_execveat(fd, "", AT_EMPTY_PATH); 213 199 } else { 214 - printf("Failed to open length %zu filename, errno=%d (%s)\n", 215 - strlen(longpath), errno, strerror(errno)); 200 + ksft_print_msg("Failed to open length %zu filename, errno=%d (%s)\n", 201 + strlen(longpath), errno, strerror(errno)); 216 202 fail++; 217 203 } 218 204 ··· 419 405 const char *in_test = getenv("IN_TEST"); 420 406 421 407 if (verbose) { 422 - printf(" invoked with:"); 408 + ksft_print_msg("invoked with:\n"); 423 409 for (ii = 0; ii < argc; ii++) 424 - printf(" [%d]='%s'", ii, argv[ii]); 425 - printf("\n"); 410 + ksft_print_msg("\t[%d]='%s\n'", ii, argv[ii]); 426 411 } 427 412 428 413 /* Check expected environment transferred. */ 429 414 if (!in_test || strcmp(in_test, "yes") != 0) { 430 - printf("[FAIL] (no IN_TEST=yes in env)\n"); 415 + ksft_print_msg("no IN_TEST=yes in env\n"); 431 416 return 1; 432 417 } 433 418 434 419 /* Use the final argument as an exit code. */ 435 420 rc = atoi(argv[argc - 1]); 436 - fflush(stdout); 421 + exit(rc); 437 422 } else { 423 + ksft_print_header(); 424 + ksft_set_plan(TESTS_EXPECTED); 438 425 prerequisites(); 439 426 if (verbose) 440 427 envp[1] = "VERBOSE=1"; 441 428 rc = run_tests(); 442 429 if (rc > 0) 443 430 printf("%d tests failed\n", rc); 431 + ksft_finished(); 444 432 } 433 + 445 434 return rc; 446 435 }