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