1 // SPDX-License-Identifier: GPL-2.0 2 3 /* 4 * Copyright (C) 2020 Google LLC. 5 */ 6 7 #include <test_progs.h> 8 #include <linux/limits.h> 9 10 #include "bprm_opts.skel.h" 11 #include "network_helpers.h" 12 13 #ifndef __NR_pidfd_open 14 #define __NR_pidfd_open 434 15 #endif 16 17 static const char * const bash_envp[] = { "TMPDIR=shouldnotbeset", NULL }; 18 19 static inline int sys_pidfd_open(pid_t pid, unsigned int flags) 20 { 21 return syscall(__NR_pidfd_open, pid, flags); 22 } 23 24 static int update_storage(int map_fd, int secureexec) 25 { 26 int task_fd, ret = 0; 27 28 task_fd = sys_pidfd_open(getpid(), 0); 29 if (task_fd < 0) 30 return errno; 31 32 ret = bpf_map_update_elem(map_fd, &task_fd, &secureexec, BPF_NOEXIST); 33 if (ret) 34 ret = errno; 35 36 close(task_fd); 37 return ret; 38 } 39 40 static int run_set_secureexec(int map_fd, int secureexec) 41 { 42 int child_pid, child_status, ret, null_fd; 43 44 child_pid = fork(); 45 if (child_pid == 0) { 46 null_fd = open("/dev/null", O_WRONLY); 47 if (null_fd == -1) 48 exit(errno); 49 dup2(null_fd, STDOUT_FILENO); 50 dup2(null_fd, STDERR_FILENO); 51 close(null_fd); 52 53 /* Ensure that all executions from hereon are 54 * secure by setting a local storage which is read by 55 * the bprm_creds_for_exec hook and sets bprm->secureexec. 56 */ 57 ret = update_storage(map_fd, secureexec); 58 if (ret) 59 exit(ret); 60 61 /* If the binary is executed with securexec=1, the dynamic 62 * loader ingores and unsets certain variables like LD_PRELOAD, 63 * TMPDIR etc. TMPDIR is used here to simplify the example, as 64 * LD_PRELOAD requires a real .so file. 65 * 66 * If the value of TMPDIR is set, the bash command returns 10 67 * and if the value is unset, it returns 20. 68 */ 69 execle("/bin/bash", "bash", "-c", 70 "[[ -z \"${TMPDIR}\" ]] || exit 10 && exit 20", NULL, 71 bash_envp); 72 exit(errno); 73 } else if (child_pid > 0) { 74 waitpid(child_pid, &child_status, 0); 75 ret = WEXITSTATUS(child_status); 76 77 /* If a secureexec occurred, the exit status should be 20 */ 78 if (secureexec && ret == 20) 79 return 0; 80 81 /* If normal execution happened, the exit code should be 10 */ 82 if (!secureexec && ret == 10) 83 return 0; 84 } 85 86 return -EINVAL; 87 } 88 89 void test_test_bprm_opts(void) 90 { 91 int err, duration = 0; 92 struct bprm_opts *skel = NULL; 93 94 skel = bprm_opts__open_and_load(); 95 if (CHECK(!skel, "skel_load", "skeleton failed\n")) 96 goto close_prog; 97 98 err = bprm_opts__attach(skel); 99 if (CHECK(err, "attach", "attach failed: %d\n", err)) 100 goto close_prog; 101 102 /* Run the test with the secureexec bit unset */ 103 err = run_set_secureexec(bpf_map__fd(skel->maps.secure_exec_task_map), 104 0 /* secureexec */); 105 if (CHECK(err, "run_set_secureexec:0", "err = %d\n", err)) 106 goto close_prog; 107 108 /* Run the test with the secureexec bit set */ 109 err = run_set_secureexec(bpf_map__fd(skel->maps.secure_exec_task_map), 110 1 /* secureexec */); 111 if (CHECK(err, "run_set_secureexec:1", "err = %d\n", err)) 112 goto close_prog; 113 114 close_prog: 115 bprm_opts__destroy(skel); 116 } 117