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
sys_pidfd_open(pid_t pid,unsigned int flags)19 static inline int sys_pidfd_open(pid_t pid, unsigned int flags)
20 {
21 return syscall(__NR_pidfd_open, pid, flags);
22 }
23
update_storage(int map_fd,int secureexec)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
run_set_secureexec(int map_fd,int secureexec)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
test_test_bprm_opts(void)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