Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include <netinet/in.h>
4 : #include <pwd.h>
5 : #include <sys/capability.h>
6 : #include <sys/prctl.h>
7 : #include <sys/socket.h>
8 : #include <sys/wait.h>
9 : #include <unistd.h>
10 :
11 : #include "alloc-util.h"
12 : #include "capability-util.h"
13 : #include "fd-util.h"
14 : #include "fileio.h"
15 : #include "macro.h"
16 : #include "missing_prctl.h"
17 : #include "parse-util.h"
18 : #include "tests.h"
19 : #include "util.h"
20 :
21 : static uid_t test_uid = -1;
22 : static gid_t test_gid = -1;
23 :
24 : #if HAS_FEATURE_ADDRESS_SANITIZER
25 : /* Keep CAP_SYS_PTRACE when running under Address Sanitizer */
26 : static const uint64_t test_flags = UINT64_C(1) << CAP_SYS_PTRACE;
27 : #else
28 : /* We keep CAP_DAC_OVERRIDE to avoid errors with gcov when doing test coverage */
29 : static const uint64_t test_flags = UINT64_C(1) << CAP_DAC_OVERRIDE;
30 : #endif
31 :
32 : /* verify cap_last_cap() against /proc/sys/kernel/cap_last_cap */
33 1 : static void test_last_cap_file(void) {
34 1 : _cleanup_free_ char *content = NULL;
35 1 : unsigned long val = 0;
36 : int r;
37 :
38 1 : r = read_one_line_file("/proc/sys/kernel/cap_last_cap", &content);
39 1 : assert_se(r >= 0);
40 :
41 1 : r = safe_atolu(content, &val);
42 1 : assert_se(r >= 0);
43 1 : assert_se(val != 0);
44 1 : assert_se(val == cap_last_cap());
45 1 : }
46 :
47 : /* verify cap_last_cap() against syscall probing */
48 1 : static void test_last_cap_probe(void) {
49 1 : unsigned long p = (unsigned long)CAP_LAST_CAP;
50 :
51 1 : if (prctl(PR_CAPBSET_READ, p) < 0) {
52 0 : for (p--; p > 0; p --)
53 0 : if (prctl(PR_CAPBSET_READ, p) >= 0)
54 0 : break;
55 : } else {
56 0 : for (;; p++)
57 1 : if (prctl(PR_CAPBSET_READ, p+1) < 0)
58 1 : break;
59 : }
60 :
61 1 : assert_se(p != 0);
62 1 : assert_se(p == cap_last_cap());
63 1 : }
64 :
65 0 : static void fork_test(void (*test_func)(void)) {
66 0 : pid_t pid = 0;
67 :
68 0 : pid = fork();
69 0 : assert_se(pid >= 0);
70 0 : if (pid == 0) {
71 0 : test_func();
72 0 : exit(EXIT_SUCCESS);
73 0 : } else if (pid > 0) {
74 : int status;
75 :
76 0 : assert_se(waitpid(pid, &status, 0) > 0);
77 0 : assert_se(WIFEXITED(status) && WEXITSTATUS(status) == 0);
78 : }
79 0 : }
80 :
81 0 : static void show_capabilities(void) {
82 : cap_t caps;
83 : char *text;
84 :
85 0 : caps = cap_get_proc();
86 0 : assert_se(caps);
87 :
88 0 : text = cap_to_text(caps, NULL);
89 0 : assert_se(text);
90 :
91 0 : log_info("Capabilities:%s", text);
92 0 : cap_free(caps);
93 0 : cap_free(text);
94 0 : }
95 :
96 0 : static int setup_tests(bool *run_ambient) {
97 : struct passwd *nobody;
98 : int r;
99 :
100 0 : nobody = getpwnam(NOBODY_USER_NAME);
101 0 : if (!nobody)
102 0 : return log_error_errno(SYNTHETIC_ERRNO(ENOENT), "Could not find nobody user: %m");
103 :
104 0 : test_uid = nobody->pw_uid;
105 0 : test_gid = nobody->pw_gid;
106 :
107 0 : *run_ambient = false;
108 :
109 0 : r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
110 :
111 : /* There's support for PR_CAP_AMBIENT if the prctl() call
112 : * succeeded or error code was something else than EINVAL. The
113 : * EINVAL check should be good enough to rule out false
114 : * positives. */
115 :
116 0 : if (r >= 0 || errno != EINVAL)
117 0 : *run_ambient = true;
118 :
119 0 : return 0;
120 : }
121 :
122 0 : static void test_drop_privileges_keep_net_raw(void) {
123 : int sock;
124 :
125 0 : sock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
126 0 : assert_se(sock >= 0);
127 0 : safe_close(sock);
128 :
129 0 : assert_se(drop_privileges(test_uid, test_gid, test_flags | (1ULL << CAP_NET_RAW)) >= 0);
130 0 : assert_se(getuid() == test_uid);
131 0 : assert_se(getgid() == test_gid);
132 0 : show_capabilities();
133 :
134 0 : sock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
135 0 : assert_se(sock >= 0);
136 0 : safe_close(sock);
137 0 : }
138 :
139 0 : static void test_drop_privileges_dontkeep_net_raw(void) {
140 : int sock;
141 :
142 0 : sock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
143 0 : assert_se(sock >= 0);
144 0 : safe_close(sock);
145 :
146 0 : assert_se(drop_privileges(test_uid, test_gid, test_flags) >= 0);
147 0 : assert_se(getuid() == test_uid);
148 0 : assert_se(getgid() == test_gid);
149 0 : show_capabilities();
150 :
151 0 : sock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
152 0 : assert_se(sock < 0);
153 0 : }
154 :
155 0 : static void test_drop_privileges_fail(void) {
156 0 : assert_se(drop_privileges(test_uid, test_gid, test_flags) >= 0);
157 0 : assert_se(getuid() == test_uid);
158 0 : assert_se(getgid() == test_gid);
159 :
160 0 : assert_se(drop_privileges(test_uid, test_gid, test_flags) < 0);
161 0 : assert_se(drop_privileges(0, 0, test_flags) < 0);
162 0 : }
163 :
164 0 : static void test_drop_privileges(void) {
165 0 : fork_test(test_drop_privileges_keep_net_raw);
166 0 : fork_test(test_drop_privileges_dontkeep_net_raw);
167 0 : fork_test(test_drop_privileges_fail);
168 0 : }
169 :
170 0 : static void test_have_effective_cap(void) {
171 0 : assert_se(have_effective_cap(CAP_KILL));
172 0 : assert_se(have_effective_cap(CAP_CHOWN));
173 :
174 0 : assert_se(drop_privileges(test_uid, test_gid, test_flags | (1ULL << CAP_KILL)) >= 0);
175 0 : assert_se(getuid() == test_uid);
176 0 : assert_se(getgid() == test_gid);
177 :
178 0 : assert_se(have_effective_cap(CAP_KILL));
179 0 : assert_se(!have_effective_cap(CAP_CHOWN));
180 0 : }
181 :
182 0 : static void test_update_inherited_set(void) {
183 : cap_t caps;
184 0 : uint64_t set = 0;
185 : cap_flag_value_t fv;
186 :
187 0 : caps = cap_get_proc();
188 0 : assert_se(caps);
189 :
190 0 : set = (UINT64_C(1) << CAP_CHOWN);
191 :
192 0 : assert_se(!capability_update_inherited_set(caps, set));
193 0 : assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv));
194 0 : assert(fv == CAP_SET);
195 :
196 0 : cap_free(caps);
197 0 : }
198 :
199 0 : static void test_set_ambient_caps(void) {
200 : cap_t caps;
201 0 : uint64_t set = 0;
202 : cap_flag_value_t fv;
203 :
204 0 : assert_se(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0) == 0);
205 :
206 0 : set = (UINT64_C(1) << CAP_CHOWN);
207 :
208 0 : assert_se(!capability_ambient_set_apply(set, true));
209 :
210 0 : caps = cap_get_proc();
211 0 : assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv));
212 0 : assert(fv == CAP_SET);
213 0 : cap_free(caps);
214 :
215 0 : assert_se(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0) == 1);
216 0 : }
217 :
218 1 : static void test_ensure_cap_64bit(void) {
219 1 : _cleanup_free_ char *content = NULL;
220 1 : unsigned long p = 0;
221 : int r;
222 :
223 1 : r = read_one_line_file("/proc/sys/kernel/cap_last_cap", &content);
224 1 : if (r == -ENOENT) /* kernel pre 3.2 */
225 0 : return;
226 1 : assert_se(r >= 0);
227 :
228 1 : assert_se(safe_atolu(content, &p) >= 0);
229 :
230 : /* If caps don't fit into 64bit anymore, we have a problem, fail the test. */
231 1 : assert_se(p <= 63);
232 :
233 : /* Also check for the header definition */
234 : assert_se(CAP_LAST_CAP <= 63);
235 : }
236 :
237 1 : int main(int argc, char *argv[]) {
238 : bool run_ambient;
239 :
240 1 : test_setup_logging(LOG_INFO);
241 :
242 1 : test_ensure_cap_64bit();
243 :
244 1 : test_last_cap_file();
245 1 : test_last_cap_probe();
246 :
247 1 : log_info("have ambient caps: %s", yes_no(ambient_capabilities_supported()));
248 :
249 1 : if (getuid() != 0)
250 1 : return log_tests_skipped("not running as root");
251 :
252 0 : if (setup_tests(&run_ambient) < 0)
253 0 : return log_tests_skipped("setup failed");
254 :
255 0 : show_capabilities();
256 :
257 0 : test_drop_privileges();
258 0 : test_update_inherited_set();
259 :
260 0 : fork_test(test_have_effective_cap);
261 :
262 0 : if (run_ambient)
263 0 : fork_test(test_set_ambient_caps);
264 :
265 0 : return 0;
266 : }
|