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