static int test_pidfd_send_signal_syscall_support(void) { int pidfd, ret; const char *test_name = "pidfd_send_signal check for support"; pidfd = open("/proc/self", O_DIRECTORY | O_CLOEXEC); if (pidfd < 0) ksft_exit_fail_msg( "%s test: Failed to open process file descriptor\n", test_name); ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0); if (ret < 0) { /* * pidfd_send_signal() will currently return ENOSYS when * CONFIG_PROC_FS is not set. */ if (errno == ENOSYS) ksft_exit_skip( "%s test: pidfd_send_signal() syscall not supported (Ensure that CONFIG_PROC_FS=y is set)\n", test_name); ksft_exit_fail_msg("%s test: Failed to send signal\n", test_name); } close(pidfd); ksft_test_result_pass( "%s test: pidfd_send_signal() syscall is supported. Tests can be executed\n", test_name); return 0; }
/* * Straightforward test to see whether pidfd_send_signal() works is to send * a signal to ourself. */ static int test_pidfd_send_signal_simple_success(void) { int pidfd, ret; const char *test_name = "pidfd_send_signal send SIGUSR1"; pidfd = open("/proc/self", O_DIRECTORY | O_CLOEXEC); if (pidfd < 0) ksft_exit_fail_msg( "%s test: Failed to open process file descriptor\n", test_name); signal(SIGUSR1, set_signal_received_on_sigusr1); ret = sys_pidfd_send_signal(pidfd, SIGUSR1, NULL, 0); close(pidfd); if (ret < 0) ksft_exit_fail_msg("%s test: Failed to send signal\n", test_name); if (signal_received != 1) ksft_exit_fail_msg("%s test: Failed to receive signal\n", test_name); signal_received = 0; ksft_test_result_pass("%s test: Sent signal\n", test_name); return 0; }
void suspend(void) { int power_state_fd; struct sigevent event = {}; int timerfd; int err; struct itimerspec spec = {}; if (getuid() != 0) ksft_exit_skip("Please run the test as root - Exiting.\n"); power_state_fd = open("/sys/power/state", O_RDWR); if (power_state_fd < 0) ksft_exit_fail_msg( "open(\"/sys/power/state\") failed %s)\n", strerror(errno)); timerfd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0); if (timerfd < 0) ksft_exit_fail_msg("timerfd_create() failed\n"); spec.it_value.tv_sec = 5; err = timerfd_settime(timerfd, 0, &spec, NULL); if (err < 0) ksft_exit_fail_msg("timerfd_settime() failed\n"); if (write(power_state_fd, "mem", strlen("mem")) != strlen("mem")) ksft_exit_fail_msg("Failed to enter Suspend state\n"); close(timerfd); close(power_state_fd); }
static void __do_binderfs_test(void) { int fd, ret, saved_errno; size_t len; ssize_t wret; bool keep = false; struct binderfs_device device = { 0 }; struct binder_version version = { 0 }; change_to_mountns(); ret = mkdir("/dev/binderfs", 0755); if (ret < 0) { if (errno != EEXIST) ksft_exit_fail_msg( "%s - Failed to create binderfs mountpoint\n", strerror(errno)); keep = true; } ret = mount(NULL, "/dev/binderfs", "binder", 0, 0); if (ret < 0) { if (errno != ENODEV) ksft_exit_fail_msg("%s - Failed to mount binderfs\n", strerror(errno)); keep ? : rmdir_protect_errno("/dev/binderfs"); ksft_exit_skip( "The Android binderfs filesystem is not available\n"); } /* binderfs mount test passed */ ksft_inc_pass_cnt(); memcpy(device.name, "my-binder", strlen("my-binder")); fd = open("/dev/binderfs/binder-control", O_RDONLY | O_CLOEXEC); if (fd < 0) ksft_exit_fail_msg( "%s - Failed to open binder-control device\n", strerror(errno)); ret = ioctl(fd, BINDER_CTL_ADD, &device); saved_errno = errno; close(fd); errno = saved_errno; if (ret < 0) { keep ? : rmdir_protect_errno("/dev/binderfs"); ksft_exit_fail_msg( "%s - Failed to allocate new binder device\n", strerror(errno)); }
static void change_to_mountns(void) { int ret; ret = unshare(CLONE_NEWNS); if (ret < 0) ksft_exit_fail_msg("%s - Failed to unshare mount namespace\n", strerror(errno)); ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0); if (ret < 0) ksft_exit_fail_msg("%s - Failed to mount / as private\n", strerror(errno)); }
static int test_pidfd_send_signal_exited_fail(void) { int pidfd, ret, saved_errno; char buf[256]; pid_t pid; const char *test_name = "pidfd_send_signal signal exited process"; pid = fork(); if (pid < 0) ksft_exit_fail_msg("%s test: Failed to create new process\n", test_name); if (pid == 0) _exit(EXIT_SUCCESS); snprintf(buf, sizeof(buf), "/proc/%d", pid); pidfd = open(buf, O_DIRECTORY | O_CLOEXEC); (void)wait_for_pid(pid); if (pidfd < 0) ksft_exit_fail_msg( "%s test: Failed to open process file descriptor\n", test_name); ret = sys_pidfd_send_signal(pidfd, 0, NULL, 0); saved_errno = errno; close(pidfd); if (ret == 0) ksft_exit_fail_msg( "%s test: Managed to send signal to process even though it should have failed\n", test_name); if (saved_errno != ESRCH) ksft_exit_fail_msg( "%s test: Expected to receive ESRCH as errno value but received %d instead\n", test_name, saved_errno); ksft_test_result_pass("%s test: Failed to send signal as expected\n", test_name); return 0; }
static void change_to_userns(void) { int ret; uid_t uid; gid_t gid; /* {g,u}id_map files only allow a max of 4096 bytes written to them */ char idmap[4096]; uid = getuid(); gid = getgid(); ret = unshare(CLONE_NEWUSER); if (ret < 0) ksft_exit_fail_msg("%s - Failed to unshare user namespace\n", strerror(errno)); write_to_file("/proc/self/setgroups", "deny", strlen("deny"), ENOENT); ret = snprintf(idmap, sizeof(idmap), "0 %d 1", uid); if (ret < 0 || (size_t)ret >= sizeof(idmap)) ksft_exit_fail_msg("%s - Failed to prepare uid mapping\n", strerror(errno)); write_to_file("/proc/self/uid_map", idmap, strlen(idmap), 0); ret = snprintf(idmap, sizeof(idmap), "0 %d 1", gid); if (ret < 0 || (size_t)ret >= sizeof(idmap)) ksft_exit_fail_msg("%s - Failed to prepare uid mapping\n", strerror(errno)); write_to_file("/proc/self/gid_map", idmap, strlen(idmap), 0); ret = setgid(0); if (ret) ksft_exit_fail_msg("%s - Failed to setgid(0)\n", strerror(errno)); ret = setuid(0); if (ret) ksft_exit_fail_msg("%s - Failed to setgid(0)\n", strerror(errno)); }
static bool bool_arg(char **argv, int i) { if (!strcmp(argv[i], "0")) return false; else if (!strcmp(argv[i], "1")) return true; else { ksft_exit_fail_msg("wrong argv[%d]\n", i); return false; } }
static void write_to_file(const char *filename, const void *buf, size_t count, int allowed_errno) { int fd, saved_errno; ssize_t ret; fd = open(filename, O_WRONLY | O_CLOEXEC); if (fd < 0) ksft_exit_fail_msg("%s - Failed to open file %s\n", strerror(errno), filename); ret = write_nointr(fd, buf, count); if (ret < 0) { if (allowed_errno && (errno == allowed_errno)) { close(fd); return; } goto on_error; } if ((size_t)ret != count) goto on_error; close(fd); return; on_error: saved_errno = errno; close(fd); errno = saved_errno; if (ret < 0) ksft_exit_fail_msg("%s - Failed to write to file %s\n", strerror(errno), filename); ksft_exit_fail_msg("Failed to write to file %s\n", filename); }
int main(int argc, char **argv) { int opt; bool do_suspend = true; bool succeeded = true; cpu_set_t available_cpus; int err; int cpu; ksft_print_header(); while ((opt = getopt(argc, argv, "n")) != -1) { switch (opt) { case 'n': do_suspend = false; break; default: printf("Usage: %s [-n]\n", argv[0]); printf(" -n: do not trigger a suspend/resume cycle before the test\n"); return -1; } } if (do_suspend) suspend(); err = sched_getaffinity(0, sizeof(available_cpus), &available_cpus); if (err < 0) ksft_exit_fail_msg("sched_getaffinity() failed\n"); for (cpu = 0; cpu < CPU_SETSIZE; cpu++) { bool test_success; if (!CPU_ISSET(cpu, &available_cpus)) continue; test_success = run_test(cpu); if (test_success) { ksft_test_result_pass("CPU %d\n", cpu); } else { ksft_test_result_fail("CPU %d\n", cpu); succeeded = false; } } if (succeeded) ksft_exit_pass(); else ksft_exit_fail(); }
int main(int argc, char **argv) { const char *atsec = ""; /* * Be careful just in case a setgid or setcapped copy of this * helper gets out. */ if (argc != 5) ksft_exit_fail_msg("wrong argc\n"); #ifdef HAVE_GETAUXVAL if (getauxval(AT_SECURE)) atsec = " (AT_SECURE is set)"; else atsec = " (AT_SECURE is not set)"; #endif capng_get_caps_process(); if (capng_have_capability(CAPNG_EFFECTIVE, CAP_NET_BIND_SERVICE) != bool_arg(argv, 1)) { ksft_print_msg("Wrong effective state%s\n", atsec); return 1; } if (capng_have_capability(CAPNG_PERMITTED, CAP_NET_BIND_SERVICE) != bool_arg(argv, 2)) { ksft_print_msg("Wrong permitted state%s\n", atsec); return 1; } if (capng_have_capability(CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE) != bool_arg(argv, 3)) { ksft_print_msg("Wrong inheritable state%s\n", atsec); return 1; } if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_NET_BIND_SERVICE, 0, 0, 0) != bool_arg(argv, 4)) { ksft_print_msg("Wrong ambient state%s\n", atsec); return 1; } ksft_print_msg("%s: Capabilities after execve were correct\n", "validate_cap:"); return 0; }
static int test_pidfd_send_signal_recycled_pid_fail(void) { int i, ret; pid_t pid1; const char *test_name = "pidfd_send_signal signal recycled pid"; ret = unshare(CLONE_NEWPID); if (ret < 0) ksft_exit_fail_msg("%s test: Failed to unshare pid namespace\n", test_name); ret = unshare(CLONE_NEWNS); if (ret < 0) ksft_exit_fail_msg( "%s test: Failed to unshare mount namespace\n", test_name); ret = mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0); if (ret < 0) ksft_exit_fail_msg("%s test: Failed to remount / private\n", test_name); /* pid 1 in new pid namespace */ pid1 = fork(); if (pid1 < 0) ksft_exit_fail_msg("%s test: Failed to create new process\n", test_name); if (pid1 == 0) { char buf[256]; pid_t pid2; int pidfd = -1; (void)umount2("/proc", MNT_DETACH); ret = mount("proc", "/proc", "proc", 0, NULL); if (ret < 0) _exit(PIDFD_ERROR); /* grab pid PID_RECYCLE */ for (i = 0; i <= PIDFD_MAX_DEFAULT; i++) { pid2 = fork(); if (pid2 < 0) _exit(PIDFD_ERROR); if (pid2 == 0) _exit(PIDFD_PASS); if (pid2 == PID_RECYCLE) { snprintf(buf, sizeof(buf), "/proc/%d", pid2); ksft_print_msg("pid to recycle is %d\n", pid2); pidfd = open(buf, O_DIRECTORY | O_CLOEXEC); } if (wait_for_pid(pid2)) _exit(PIDFD_ERROR); if (pid2 >= PID_RECYCLE) break; } /* * We want to be as predictable as we can so if we haven't been * able to grab pid PID_RECYCLE skip the test. */ if (pid2 != PID_RECYCLE) { /* skip test */ close(pidfd); _exit(PIDFD_SKIP); } if (pidfd < 0) _exit(PIDFD_ERROR); for (i = 0; i <= PIDFD_MAX_DEFAULT; i++) { char c; int pipe_fds[2]; pid_t recycled_pid; int child_ret = PIDFD_PASS; ret = pipe2(pipe_fds, O_CLOEXEC); if (ret < 0) _exit(PIDFD_ERROR); recycled_pid = fork(); if (recycled_pid < 0) _exit(PIDFD_ERROR); if (recycled_pid == 0) { close(pipe_fds[1]); (void)read(pipe_fds[0], &c, 1); close(pipe_fds[0]); _exit(PIDFD_PASS); } /* * Stop the child so we can inspect whether we have * recycled pid PID_RECYCLE. */ close(pipe_fds[0]); ret = kill(recycled_pid, SIGSTOP); close(pipe_fds[1]); if (ret) { (void)wait_for_pid(recycled_pid); _exit(PIDFD_ERROR); } /* * We have recycled the pid. Try to signal it. This * needs to fail since this is a different process than * the one the pidfd refers to. */ if (recycled_pid == PID_RECYCLE) { ret = sys_pidfd_send_signal(pidfd, SIGCONT, NULL, 0); if (ret && errno == ESRCH) child_ret = PIDFD_XFAIL; else child_ret = PIDFD_FAIL; } /* let the process move on */ ret = kill(recycled_pid, SIGCONT); if (ret) (void)kill(recycled_pid, SIGKILL); if (wait_for_pid(recycled_pid)) _exit(PIDFD_ERROR); switch (child_ret) { case PIDFD_FAIL: /* fallthrough */ case PIDFD_XFAIL: _exit(child_ret); case PIDFD_PASS: break; default: /* not reached */ _exit(PIDFD_ERROR); } /* * If the user set a custom pid_max limit we could be * in the millions. * Skip the test in this case. */ if (recycled_pid > PIDFD_MAX_DEFAULT) _exit(PIDFD_SKIP); } /* failed to recycle pid */ _exit(PIDFD_SKIP); } ret = wait_for_pid(pid1); switch (ret) { case PIDFD_FAIL: ksft_exit_fail_msg( "%s test: Managed to signal recycled pid %d\n", test_name, PID_RECYCLE); case PIDFD_PASS: ksft_exit_fail_msg("%s test: Failed to recycle pid %d\n", test_name, PID_RECYCLE); case PIDFD_SKIP: ksft_print_msg("%s test: Skipping test\n", test_name); ret = 0; break; case PIDFD_XFAIL: ksft_test_result_pass( "%s test: Failed to signal recycled pid as expected\n", test_name); ret = 0; break; default /* PIDFD_ERROR */: ksft_exit_fail_msg("%s test: Error while running tests\n", test_name); } return ret; }