]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/analyze/analyze-security.c
analyze: check for RestrictSUIDSGID= in "systemd-analyze security"
[thirdparty/systemd.git] / src / analyze / analyze-security.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <sched.h>
4 #include <sys/utsname.h>
5
6 #include "analyze-security.h"
7 #include "bus-error.h"
8 #include "bus-unit-util.h"
9 #include "bus-util.h"
10 #include "env-util.h"
11 #include "format-table.h"
12 #include "in-addr-util.h"
13 #include "locale-util.h"
14 #include "macro.h"
15 #include "missing.h"
16 #include "nulstr-util.h"
17 #include "parse-util.h"
18 #include "path-util.h"
19 #include "pretty-print.h"
20 #if HAVE_SECCOMP
21 # include "seccomp-util.h"
22 #endif
23 #include "set.h"
24 #include "stdio-util.h"
25 #include "strv.h"
26 #include "terminal-util.h"
27 #include "unit-def.h"
28 #include "unit-name.h"
29
30 struct security_info {
31 char *id;
32 char *type;
33 char *load_state;
34 char *fragment_path;
35 bool default_dependencies;
36
37 uint64_t ambient_capabilities;
38 uint64_t capability_bounding_set;
39
40 char *user;
41 char **supplementary_groups;
42 bool dynamic_user;
43
44 bool ip_address_deny_all;
45 bool ip_address_allow_localhost;
46 bool ip_address_allow_other;
47
48 char *keyring_mode;
49 bool lock_personality;
50 bool memory_deny_write_execute;
51 bool no_new_privileges;
52 char *notify_access;
53 bool protect_hostname;
54
55 bool private_devices;
56 bool private_mounts;
57 bool private_network;
58 bool private_tmp;
59 bool private_users;
60
61 bool protect_control_groups;
62 bool protect_kernel_modules;
63 bool protect_kernel_tunables;
64
65 char *protect_home;
66 char *protect_system;
67
68 bool remove_ipc;
69
70 bool restrict_address_family_inet;
71 bool restrict_address_family_unix;
72 bool restrict_address_family_netlink;
73 bool restrict_address_family_packet;
74 bool restrict_address_family_other;
75
76 uint64_t restrict_namespaces;
77 bool restrict_realtime;
78 bool restrict_suid_sgid;
79
80 char *root_directory;
81 char *root_image;
82
83 bool delegate;
84 char *device_policy;
85 bool device_allow_non_empty;
86
87 char **system_call_architectures;
88
89 bool system_call_filter_whitelist;
90 Set *system_call_filter;
91
92 uint32_t _umask;
93 };
94
95 struct security_assessor {
96 const char *id;
97 const char *description_good;
98 const char *description_bad;
99 const char *description_na;
100 const char *url;
101 uint64_t weight;
102 uint64_t range;
103 int (*assess)(const struct security_assessor *a, const struct security_info *info, const void *data, uint64_t *ret_badness, char **ret_description);
104 size_t offset;
105 uint64_t parameter;
106 bool default_dependencies_only;
107 };
108
109 static void security_info_free(struct security_info *i) {
110 if (!i)
111 return;
112
113 free(i->id);
114 free(i->type);
115 free(i->load_state);
116 free(i->fragment_path);
117
118 free(i->user);
119
120 free(i->protect_home);
121 free(i->protect_system);
122
123 free(i->root_directory);
124 free(i->root_image);
125
126 free(i->keyring_mode);
127 free(i->notify_access);
128
129 free(i->device_policy);
130
131 strv_free(i->supplementary_groups);
132 strv_free(i->system_call_architectures);
133
134 set_free_free(i->system_call_filter);
135 }
136
137 static bool security_info_runs_privileged(const struct security_info *i) {
138 assert(i);
139
140 if (STRPTR_IN_SET(i->user, "0", "root"))
141 return true;
142
143 if (i->dynamic_user)
144 return false;
145
146 return isempty(i->user);
147 }
148
149 static int assess_bool(
150 const struct security_assessor *a,
151 const struct security_info *info,
152 const void *data,
153 uint64_t *ret_badness,
154 char **ret_description) {
155
156 const bool *b = data;
157
158 assert(b);
159 assert(ret_badness);
160 assert(ret_description);
161
162 *ret_badness = a->parameter ? *b : !*b;
163 *ret_description = NULL;
164
165 return 0;
166 }
167
168 static int assess_user(
169 const struct security_assessor *a,
170 const struct security_info *info,
171 const void *data,
172 uint64_t *ret_badness,
173 char **ret_description) {
174
175 _cleanup_free_ char *d = NULL;
176 uint64_t b;
177
178 assert(ret_badness);
179 assert(ret_description);
180
181 if (streq_ptr(info->user, NOBODY_USER_NAME)) {
182 d = strdup("Service runs under as '" NOBODY_USER_NAME "' user, which should not be used for services");
183 b = 9;
184 } else if (info->dynamic_user && !STR_IN_SET(info->user, "0", "root")) {
185 d = strdup("Service runs under a transient non-root user identity");
186 b = 0;
187 } else if (info->user && !STR_IN_SET(info->user, "0", "root", "")) {
188 d = strdup("Service runs under a static non-root user identity");
189 b = 0;
190 } else {
191 *ret_badness = 10;
192 *ret_description = NULL;
193 return 0;
194 }
195
196 if (!d)
197 return log_oom();
198
199 *ret_badness = b;
200 *ret_description = TAKE_PTR(d);
201
202 return 0;
203 }
204
205 static int assess_protect_home(
206 const struct security_assessor *a,
207 const struct security_info *info,
208 const void *data,
209 uint64_t *ret_badness,
210 char **ret_description) {
211
212 const char *description;
213 uint64_t badness;
214 char *copy;
215 int r;
216
217 assert(ret_badness);
218 assert(ret_description);
219
220 badness = 10;
221 description = "Service has full access to home directories";
222
223 r = parse_boolean(info->protect_home);
224 if (r < 0) {
225 if (streq_ptr(info->protect_home, "read-only")) {
226 badness = 5;
227 description = "Service has read-only access to home directories";
228 } else if (streq_ptr(info->protect_home, "tmpfs")) {
229 badness = 1;
230 description = "Service has access to fake empty home directories";
231 }
232 } else if (r > 0) {
233 badness = 0;
234 description = "Service has no access to home directories";
235 }
236
237 copy = strdup(description);
238 if (!copy)
239 return log_oom();
240
241 *ret_badness = badness;
242 *ret_description = copy;
243
244 return 0;
245 }
246
247 static int assess_protect_system(
248 const struct security_assessor *a,
249 const struct security_info *info,
250 const void *data,
251 uint64_t *ret_badness,
252 char **ret_description) {
253
254 const char *description;
255 uint64_t badness;
256 char *copy;
257 int r;
258
259 assert(ret_badness);
260 assert(ret_description);
261
262 badness = 10;
263 description = "Service has full access to the OS file hierarchy";
264
265 r = parse_boolean(info->protect_system);
266 if (r < 0) {
267 if (streq_ptr(info->protect_system, "full")) {
268 badness = 3;
269 description = "Service has very limited write access to the OS file hierarchy";
270 } else if (streq_ptr(info->protect_system, "strict")) {
271 badness = 0;
272 description = "Service has strict read-only access to the OS file hierarchy";
273 }
274 } else if (r > 0) {
275 badness = 5;
276 description = "Service has limited write access to the OS file hierarchy";
277 }
278
279 copy = strdup(description);
280 if (!copy)
281 return log_oom();
282
283 *ret_badness = badness;
284 *ret_description = copy;
285
286 return 0;
287 }
288
289 static int assess_root_directory(
290 const struct security_assessor *a,
291 const struct security_info *info,
292 const void *data,
293 uint64_t *ret_badness,
294 char **ret_description) {
295
296 assert(ret_badness);
297 assert(ret_description);
298
299 *ret_badness =
300 (isempty(info->root_directory) ||
301 path_equal(info->root_directory, "/")) &&
302 (isempty(info->root_image) ||
303 path_equal(info->root_image, "/"));
304 *ret_description = NULL;
305
306 return 0;
307 }
308
309 static int assess_capability_bounding_set(
310 const struct security_assessor *a,
311 const struct security_info *info,
312 const void *data,
313 uint64_t *ret_badness,
314 char **ret_description) {
315
316 assert(ret_badness);
317 assert(ret_description);
318
319 *ret_badness = !!(info->capability_bounding_set & a->parameter);
320 *ret_description = NULL;
321
322 return 0;
323 }
324
325 static int assess_umask(
326 const struct security_assessor *a,
327 const struct security_info *info,
328 const void *data,
329 uint64_t *ret_badness,
330 char **ret_description) {
331
332 char *copy = NULL;
333 const char *d;
334 uint64_t b;
335
336 assert(ret_badness);
337 assert(ret_description);
338
339 if (!FLAGS_SET(info->_umask, 0002)) {
340 d = "Files created by service are world-writable by default";
341 b = 10;
342 } else if (!FLAGS_SET(info->_umask, 0004)) {
343 d = "Files created by service are world-readable by default";
344 b = 5;
345 } else if (!FLAGS_SET(info->_umask, 0020)) {
346 d = "Files created by service are group-writable by default";
347 b = 2;
348 } else if (!FLAGS_SET(info->_umask, 0040)) {
349 d = "Files created by service are group-readable by default";
350 b = 1;
351 } else {
352 d = "Files created by service are accessible only by service's own user by default";
353 b = 0;
354 }
355
356 copy = strdup(d);
357 if (!copy)
358 return log_oom();
359
360 *ret_badness = b;
361 *ret_description = copy;
362
363 return 0;
364 }
365
366 static int assess_keyring_mode(
367 const struct security_assessor *a,
368 const struct security_info *info,
369 const void *data,
370 uint64_t *ret_badness,
371 char **ret_description) {
372
373 assert(ret_badness);
374 assert(ret_description);
375
376 *ret_badness = !streq_ptr(info->keyring_mode, "private");
377 *ret_description = NULL;
378
379 return 0;
380 }
381
382 static int assess_notify_access(
383 const struct security_assessor *a,
384 const struct security_info *info,
385 const void *data,
386 uint64_t *ret_badness,
387 char **ret_description) {
388
389 assert(ret_badness);
390 assert(ret_description);
391
392 *ret_badness = streq_ptr(info->notify_access, "all");
393 *ret_description = NULL;
394
395 return 0;
396 }
397
398 static int assess_remove_ipc(
399 const struct security_assessor *a,
400 const struct security_info *info,
401 const void *data,
402 uint64_t *ret_badness,
403 char **ret_description) {
404
405 assert(ret_badness);
406 assert(ret_description);
407
408 if (security_info_runs_privileged(info))
409 *ret_badness = UINT64_MAX;
410 else
411 *ret_badness = !info->remove_ipc;
412
413 *ret_description = NULL;
414 return 0;
415 }
416
417 static int assess_supplementary_groups(
418 const struct security_assessor *a,
419 const struct security_info *info,
420 const void *data,
421 uint64_t *ret_badness,
422 char **ret_description) {
423
424 assert(ret_badness);
425 assert(ret_description);
426
427 if (security_info_runs_privileged(info))
428 *ret_badness = UINT64_MAX;
429 else
430 *ret_badness = !strv_isempty(info->supplementary_groups);
431
432 *ret_description = NULL;
433 return 0;
434 }
435
436 static int assess_restrict_namespaces(
437 const struct security_assessor *a,
438 const struct security_info *info,
439 const void *data,
440 uint64_t *ret_badness,
441 char **ret_description) {
442
443 assert(ret_badness);
444 assert(ret_description);
445
446 *ret_badness = !!(info->restrict_namespaces & a->parameter);
447 *ret_description = NULL;
448
449 return 0;
450 }
451
452 static int assess_system_call_architectures(
453 const struct security_assessor *a,
454 const struct security_info *info,
455 const void *data,
456 uint64_t *ret_badness,
457 char **ret_description) {
458
459 char *d;
460 uint64_t b;
461
462 assert(ret_badness);
463 assert(ret_description);
464
465 if (strv_isempty(info->system_call_architectures)) {
466 b = 10;
467 d = strdup("Service may execute system calls with all ABIs");
468 } else if (strv_equal(info->system_call_architectures, STRV_MAKE("native"))) {
469 b = 0;
470 d = strdup("Service may execute system calls only with native ABI");
471 } else {
472 b = 8;
473 d = strdup("Service may execute system calls with multiple ABIs");
474 }
475
476 if (!d)
477 return log_oom();
478
479 *ret_badness = b;
480 *ret_description = d;
481
482 return 0;
483 }
484
485 #if HAVE_SECCOMP
486
487 static bool syscall_names_in_filter(Set *s, bool whitelist, const SyscallFilterSet *f) {
488 const char *syscall;
489
490 NULSTR_FOREACH(syscall, f->value) {
491 int id;
492
493 if (syscall[0] == '@') {
494 const SyscallFilterSet *g;
495
496 assert_se(g = syscall_filter_set_find(syscall));
497 if (syscall_names_in_filter(s, whitelist, g))
498 return true; /* bad! */
499
500 continue;
501 }
502
503 /* Let's see if the system call actually exists on this platform, before complaining */
504 id = seccomp_syscall_resolve_name(syscall);
505 if (id < 0)
506 continue;
507
508 if (set_contains(s, syscall) == whitelist) {
509 log_debug("Offending syscall filter item: %s", syscall);
510 return true; /* bad! */
511 }
512 }
513
514 return false;
515 }
516
517 static int assess_system_call_filter(
518 const struct security_assessor *a,
519 const struct security_info *info,
520 const void *data,
521 uint64_t *ret_badness,
522 char **ret_description) {
523
524 const SyscallFilterSet *f;
525 char *d = NULL;
526 uint64_t b;
527
528 assert(a);
529 assert(info);
530 assert(ret_badness);
531 assert(ret_description);
532
533 assert(a->parameter < _SYSCALL_FILTER_SET_MAX);
534 f = syscall_filter_sets + a->parameter;
535
536 if (!info->system_call_filter_whitelist && set_isempty(info->system_call_filter)) {
537 d = strdup("Service does not filter system calls");
538 b = 10;
539 } else {
540 bool bad;
541
542 log_debug("Analyzing system call filter, checking against: %s", f->name);
543 bad = syscall_names_in_filter(info->system_call_filter, info->system_call_filter_whitelist, f);
544 log_debug("Result: %s", bad ? "bad" : "good");
545
546 if (info->system_call_filter_whitelist) {
547 if (bad) {
548 (void) asprintf(&d, "System call whitelist defined for service, and %s is included", f->name);
549 b = 9;
550 } else {
551 (void) asprintf(&d, "System call whitelist defined for service, and %s is not included", f->name);
552 b = 0;
553 }
554 } else {
555 if (bad) {
556 (void) asprintf(&d, "System call blacklist defined for service, and %s is not included", f->name);
557 b = 10;
558 } else {
559 (void) asprintf(&d, "System call blacklist defined for service, and %s is included", f->name);
560 b = 5;
561 }
562 }
563 }
564
565 if (!d)
566 return log_oom();
567
568 *ret_badness = b;
569 *ret_description = d;
570
571 return 0;
572 }
573
574 #endif
575
576 static int assess_ip_address_allow(
577 const struct security_assessor *a,
578 const struct security_info *info,
579 const void *data,
580 uint64_t *ret_badness,
581 char **ret_description) {
582
583 char *d = NULL;
584 uint64_t b;
585
586 assert(info);
587 assert(ret_badness);
588 assert(ret_description);
589
590 if (!info->ip_address_deny_all) {
591 d = strdup("Service does not define an IP address whitelist");
592 b = 10;
593 } else if (info->ip_address_allow_other) {
594 d = strdup("Service defines IP address whitelist with non-localhost entries");
595 b = 5;
596 } else if (info->ip_address_allow_localhost) {
597 d = strdup("Service defines IP address whitelits with only localhost entries");
598 b = 2;
599 } else {
600 d = strdup("Service blocks all IP address ranges");
601 b = 0;
602 }
603
604 if (!d)
605 return log_oom();
606
607 *ret_badness = b;
608 *ret_description = d;
609
610 return 0;
611 }
612
613 static int assess_device_allow(
614 const struct security_assessor *a,
615 const struct security_info *info,
616 const void *data,
617 uint64_t *ret_badness,
618 char **ret_description) {
619
620 char *d = NULL;
621 uint64_t b;
622
623 assert(info);
624 assert(ret_badness);
625 assert(ret_description);
626
627 if (STRPTR_IN_SET(info->device_policy, "strict", "closed")) {
628
629 if (info->device_allow_non_empty) {
630 d = strdup("Service has a device ACL with some special devices");
631 b = 5;
632 } else {
633 d = strdup("Service has a minimal device ACL");
634 b = 0;
635 }
636 } else {
637 d = strdup("Service has no device ACL");
638 b = 10;
639 }
640
641 if (!d)
642 return log_oom();
643
644 *ret_badness = b;
645 *ret_description = d;
646
647 return 0;
648 }
649
650 static int assess_ambient_capabilities(
651 const struct security_assessor *a,
652 const struct security_info *info,
653 const void *data,
654 uint64_t *ret_badness,
655 char **ret_description) {
656
657 assert(ret_badness);
658 assert(ret_description);
659
660 *ret_badness = info->ambient_capabilities != 0;
661 *ret_description = NULL;
662
663 return 0;
664 }
665
666 static const struct security_assessor security_assessor_table[] = {
667 {
668 .id = "User=/DynamicUser=",
669 .description_bad = "Service runs as root user",
670 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#User=",
671 .weight = 2000,
672 .range = 10,
673 .assess = assess_user,
674 },
675 {
676 .id = "SupplementaryGroups=",
677 .description_good = "Service has no supplementary groups",
678 .description_bad = "Service runs with supplementary groups",
679 .description_na = "Service runs as root, option does not matter",
680 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SupplementaryGroups=",
681 .weight = 200,
682 .range = 1,
683 .assess = assess_supplementary_groups,
684 },
685 {
686 .id = "PrivateDevices=",
687 .description_good = "Service has no access to hardware devices",
688 .description_bad = "Service potentially has access to hardware devices",
689 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#PrivateDevices=",
690 .weight = 1000,
691 .range = 1,
692 .assess = assess_bool,
693 .offset = offsetof(struct security_info, private_devices),
694 },
695 {
696 .id = "PrivateMounts=",
697 .description_good = "Service cannot install system mounts",
698 .description_bad = "Service may install system mounts",
699 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#PrivateMounts=",
700 .weight = 1000,
701 .range = 1,
702 .assess = assess_bool,
703 .offset = offsetof(struct security_info, private_mounts),
704 },
705 {
706 .id = "PrivateNetwork=",
707 .description_good = "Service has no access to the host's network",
708 .description_bad = "Service has access to the host's network",
709 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#PrivateNetwork=",
710 .weight = 2500,
711 .range = 1,
712 .assess = assess_bool,
713 .offset = offsetof(struct security_info, private_network),
714 },
715 {
716 .id = "PrivateTmp=",
717 .description_good = "Service has no access to other software's temporary files",
718 .description_bad = "Service has access to other software's temporary files",
719 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#PrivateTmp=",
720 .weight = 1000,
721 .range = 1,
722 .assess = assess_bool,
723 .offset = offsetof(struct security_info, private_tmp),
724 .default_dependencies_only = true,
725 },
726 {
727 .id = "PrivateUsers=",
728 .description_good = "Service does not have access to other users",
729 .description_bad = "Service has access to other users",
730 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#PrivateUsers=",
731 .weight = 1000,
732 .range = 1,
733 .assess = assess_bool,
734 .offset = offsetof(struct security_info, private_users),
735 },
736 {
737 .id = "ProtectControlGroups=",
738 .description_good = "Service cannot modify the control group file system",
739 .description_bad = "Service may modify to the control group file system",
740 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectControlGroups=",
741 .weight = 1000,
742 .range = 1,
743 .assess = assess_bool,
744 .offset = offsetof(struct security_info, protect_control_groups),
745 },
746 {
747 .id = "ProtectKernelModules=",
748 .description_good = "Service cannot load or read kernel modules",
749 .description_bad = "Service may load or read kernel modules",
750 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectKernelModules=",
751 .weight = 1000,
752 .range = 1,
753 .assess = assess_bool,
754 .offset = offsetof(struct security_info, protect_kernel_modules),
755 },
756 {
757 .id = "ProtectKernelTunables=",
758 .description_good = "Service cannot alter kernel tunables (/proc/sys, …)",
759 .description_bad = "Service may alter kernel tunables",
760 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectKernelTunables=",
761 .weight = 1000,
762 .range = 1,
763 .assess = assess_bool,
764 .offset = offsetof(struct security_info, protect_kernel_tunables),
765 },
766 {
767 .id = "ProtectHome=",
768 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectHome=",
769 .weight = 1000,
770 .range = 10,
771 .assess = assess_protect_home,
772 .default_dependencies_only = true,
773 },
774 {
775 .id = "ProtectHostname=",
776 .description_good = "Service cannot change system host/domainname",
777 .description_bad = "Service may change system host/domainname",
778 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectHostname=",
779 .weight = 50,
780 .range = 1,
781 .assess = assess_bool,
782 .offset = offsetof(struct security_info, protect_hostname),
783 },
784 {
785 .id = "ProtectSystem=",
786 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectSystem=",
787 .weight = 1000,
788 .range = 10,
789 .assess = assess_protect_system,
790 .default_dependencies_only = true,
791 },
792 {
793 .id = "RootDirectory=/RootImage=",
794 .description_good = "Service has its own root directory/image",
795 .description_bad = "Service runs within the host's root directory",
796 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RootDirectory=",
797 .weight = 200,
798 .range = 1,
799 .assess = assess_root_directory,
800 .default_dependencies_only = true,
801 },
802 {
803 .id = "LockPersonality=",
804 .description_good = "Service cannot change ABI personality",
805 .description_bad = "Service may change ABI personality",
806 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#LockPersonality=",
807 .weight = 100,
808 .range = 1,
809 .assess = assess_bool,
810 .offset = offsetof(struct security_info, lock_personality),
811 },
812 {
813 .id = "MemoryDenyWriteExecute=",
814 .description_good = "Service cannot create writable executable memory mappings",
815 .description_bad = "Service may create writable executable memory mappings",
816 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#MemoryDenyWriteExecute=",
817 .weight = 100,
818 .range = 1,
819 .assess = assess_bool,
820 .offset = offsetof(struct security_info, memory_deny_write_execute),
821 },
822 {
823 .id = "NoNewPrivileges=",
824 .description_good = "Service processes cannot acquire new privileges",
825 .description_bad = "Service processes may acquire new privileges",
826 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#NoNewPrivileges=",
827 .weight = 1000,
828 .range = 1,
829 .assess = assess_bool,
830 .offset = offsetof(struct security_info, no_new_privileges),
831 },
832 {
833 .id = "CapabilityBoundingSet=~CAP_SYS_ADMIN",
834 .description_good = "Service has no administrator privileges",
835 .description_bad = "Service has administrator privileges",
836 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
837 .weight = 1500,
838 .range = 1,
839 .assess = assess_capability_bounding_set,
840 .parameter = UINT64_C(1) << CAP_SYS_ADMIN,
841 },
842 {
843 .id = "CapabilityBoundingSet=~CAP_SET(UID|GID|PCAP)",
844 .description_good = "Service cannot change UID/GID identities/capabilities",
845 .description_bad = "Service may change UID/GID identities/capabilities",
846 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
847 .weight = 1500,
848 .range = 1,
849 .assess = assess_capability_bounding_set,
850 .parameter = (UINT64_C(1) << CAP_SETUID)|
851 (UINT64_C(1) << CAP_SETGID)|
852 (UINT64_C(1) << CAP_SETPCAP),
853 },
854 {
855 .id = "CapabilityBoundingSet=~CAP_SYS_PTRACE",
856 .description_good = "Service has no ptrace() debugging abilities",
857 .description_bad = "Service has ptrace() debugging abilities",
858 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
859 .weight = 1500,
860 .range = 1,
861 .assess = assess_capability_bounding_set,
862 .parameter = (UINT64_C(1) << CAP_SYS_PTRACE),
863 },
864 {
865 .id = "CapabilityBoundingSet=~CAP_SYS_TIME",
866 .description_good = "Service processes cannot change the system clock",
867 .description_bad = "Service processes may change the system clock",
868 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
869 .weight = 1000,
870 .range = 1,
871 .assess = assess_capability_bounding_set,
872 .parameter = UINT64_C(1) << CAP_SYS_TIME,
873 },
874 {
875 .id = "CapabilityBoundingSet=~CAP_NET_ADMIN",
876 .description_good = "Service has no network configuration privileges",
877 .description_bad = "Service has network configuration privileges",
878 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
879 .weight = 1000,
880 .range = 1,
881 .assess = assess_capability_bounding_set,
882 .parameter = (UINT64_C(1) << CAP_NET_ADMIN),
883 },
884 {
885 .id = "CapabilityBoundingSet=~CAP_RAWIO",
886 .description_good = "Service has no raw I/O access",
887 .description_bad = "Service has raw I/O access",
888 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
889 .weight = 1000,
890 .range = 1,
891 .assess = assess_capability_bounding_set,
892 .parameter = (UINT64_C(1) << CAP_SYS_RAWIO),
893 },
894 {
895 .id = "CapabilityBoundingSet=~CAP_SYS_MODULE",
896 .description_good = "Service cannot load kernel modules",
897 .description_bad = "Service may load kernel modules",
898 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
899 .weight = 1000,
900 .range = 1,
901 .assess = assess_capability_bounding_set,
902 .parameter = (UINT64_C(1) << CAP_SYS_MODULE),
903 },
904 {
905 .id = "CapabilityBoundingSet=~CAP_AUDIT_*",
906 .description_good = "Service has no audit subsystem access",
907 .description_bad = "Service has audit subsystem access",
908 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
909 .weight = 500,
910 .range = 1,
911 .assess = assess_capability_bounding_set,
912 .parameter = (UINT64_C(1) << CAP_AUDIT_CONTROL) |
913 (UINT64_C(1) << CAP_AUDIT_READ) |
914 (UINT64_C(1) << CAP_AUDIT_WRITE),
915 },
916 {
917 .id = "CapabilityBoundingSet=~CAP_SYSLOG",
918 .description_good = "Service has no access to kernel logging",
919 .description_bad = "Service has access to kernel logging",
920 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
921 .weight = 500,
922 .range = 1,
923 .assess = assess_capability_bounding_set,
924 .parameter = (UINT64_C(1) << CAP_SYSLOG),
925 },
926 {
927 .id = "CapabilityBoundingSet=~CAP_SYS_(NICE|RESOURCE)",
928 .description_good = "Service has no privileges to change resource use parameters",
929 .description_bad = "Service has privileges to change resource use parameters",
930 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
931 .weight = 500,
932 .range = 1,
933 .assess = assess_capability_bounding_set,
934 .parameter = (UINT64_C(1) << CAP_SYS_NICE) |
935 (UINT64_C(1) << CAP_SYS_RESOURCE),
936 },
937 {
938 .id = "CapabilityBoundingSet=~CAP_MKNOD",
939 .description_good = "Service cannot create device nodes",
940 .description_bad = "Service may create device nodes",
941 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
942 .weight = 500,
943 .range = 1,
944 .assess = assess_capability_bounding_set,
945 .parameter = (UINT64_C(1) << CAP_MKNOD),
946 },
947 {
948 .id = "CapabilityBoundingSet=~CAP_(CHOWN|FSETID|SETFCAP)",
949 .description_good = "Service cannot change file ownership/access mode/capabilities",
950 .description_bad = "Service may change file ownership/access mode/capabilities unrestricted",
951 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
952 .weight = 1000,
953 .range = 1,
954 .assess = assess_capability_bounding_set,
955 .parameter = (UINT64_C(1) << CAP_CHOWN) |
956 (UINT64_C(1) << CAP_FSETID) |
957 (UINT64_C(1) << CAP_SETFCAP),
958 },
959 {
960 .id = "CapabilityBoundingSet=~CAP_(DAC_*|FOWNER|IPC_OWNER)",
961 .description_good = "Service cannot override UNIX file/IPC permission checks",
962 .description_bad = "Service may override UNIX file/IPC permission checks",
963 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
964 .weight = 1000,
965 .range = 1,
966 .assess = assess_capability_bounding_set,
967 .parameter = (UINT64_C(1) << CAP_DAC_OVERRIDE) |
968 (UINT64_C(1) << CAP_DAC_READ_SEARCH) |
969 (UINT64_C(1) << CAP_FOWNER) |
970 (UINT64_C(1) << CAP_IPC_OWNER),
971 },
972 {
973 .id = "CapabilityBoundingSet=~CAP_KILL",
974 .description_good = "Service cannot send UNIX signals to arbitrary processes",
975 .description_bad = "Service may send UNIX signals to arbitrary processes",
976 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
977 .weight = 500,
978 .range = 1,
979 .assess = assess_capability_bounding_set,
980 .parameter = (UINT64_C(1) << CAP_KILL),
981 },
982 {
983 .id = "CapabilityBoundingSet=~CAP_NET_(BIND_SERVICE|BROADCAST|RAW)",
984 .description_good = "Service has no elevated networking privileges",
985 .description_bad = "Service has elevated networking privileges",
986 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
987 .weight = 500,
988 .range = 1,
989 .assess = assess_capability_bounding_set,
990 .parameter = (UINT64_C(1) << CAP_NET_BIND_SERVICE) |
991 (UINT64_C(1) << CAP_NET_BROADCAST) |
992 (UINT64_C(1) << CAP_NET_RAW),
993 },
994 {
995 .id = "CapabilityBoundingSet=~CAP_SYS_BOOT",
996 .description_good = "Service cannot issue reboot()",
997 .description_bad = "Service may issue reboot()",
998 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
999 .weight = 100,
1000 .range = 1,
1001 .assess = assess_capability_bounding_set,
1002 .parameter = (UINT64_C(1) << CAP_SYS_BOOT),
1003 },
1004 {
1005 .id = "CapabilityBoundingSet=~CAP_MAC_*",
1006 .description_good = "Service cannot adjust SMACK MAC",
1007 .description_bad = "Service may adjust SMACK MAC",
1008 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
1009 .weight = 100,
1010 .range = 1,
1011 .assess = assess_capability_bounding_set,
1012 .parameter = (UINT64_C(1) << CAP_MAC_ADMIN)|
1013 (UINT64_C(1) << CAP_MAC_OVERRIDE),
1014 },
1015 {
1016 .id = "CapabilityBoundingSet=~CAP_LINUX_IMMUTABLE",
1017 .description_good = "Service cannot mark files immutable",
1018 .description_bad = "Service may mark files immutable",
1019 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
1020 .weight = 75,
1021 .range = 1,
1022 .assess = assess_capability_bounding_set,
1023 .parameter = (UINT64_C(1) << CAP_LINUX_IMMUTABLE),
1024 },
1025 {
1026 .id = "CapabilityBoundingSet=~CAP_IPC_LOCK",
1027 .description_good = "Service cannot lock memory into RAM",
1028 .description_bad = "Service may lock memory into RAM",
1029 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
1030 .weight = 50,
1031 .range = 1,
1032 .assess = assess_capability_bounding_set,
1033 .parameter = (UINT64_C(1) << CAP_IPC_LOCK),
1034 },
1035 {
1036 .id = "CapabilityBoundingSet=~CAP_SYS_CHROOT",
1037 .description_good = "Service cannot issue chroot()",
1038 .description_bad = "Service may issue chroot()",
1039 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
1040 .weight = 50,
1041 .range = 1,
1042 .assess = assess_capability_bounding_set,
1043 .parameter = (UINT64_C(1) << CAP_SYS_CHROOT),
1044 },
1045 {
1046 .id = "CapabilityBoundingSet=~CAP_BLOCK_SUSPEND",
1047 .description_good = "Service cannot establish wake locks",
1048 .description_bad = "Service may establish wake locks",
1049 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
1050 .weight = 25,
1051 .range = 1,
1052 .assess = assess_capability_bounding_set,
1053 .parameter = (UINT64_C(1) << CAP_BLOCK_SUSPEND),
1054 },
1055 {
1056 .id = "CapabilityBoundingSet=~CAP_WAKE_ALARM",
1057 .description_good = "Service cannot program timers that wake up the system",
1058 .description_bad = "Service may program timers that wake up the system",
1059 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
1060 .weight = 25,
1061 .range = 1,
1062 .assess = assess_capability_bounding_set,
1063 .parameter = (UINT64_C(1) << CAP_WAKE_ALARM),
1064 },
1065 {
1066 .id = "CapabilityBoundingSet=~CAP_LEASE",
1067 .description_good = "Service cannot create file leases",
1068 .description_bad = "Service may create file leases",
1069 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
1070 .weight = 25,
1071 .range = 1,
1072 .assess = assess_capability_bounding_set,
1073 .parameter = (UINT64_C(1) << CAP_LEASE),
1074 },
1075 {
1076 .id = "CapabilityBoundingSet=~CAP_SYS_TTY_CONFIG",
1077 .description_good = "Service cannot issue vhangup()",
1078 .description_bad = "Service may issue vhangup()",
1079 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
1080 .weight = 25,
1081 .range = 1,
1082 .assess = assess_capability_bounding_set,
1083 .parameter = (UINT64_C(1) << CAP_SYS_TTY_CONFIG),
1084 },
1085 {
1086 .id = "CapabilityBoundingSet=~CAP_SYS_PACCT",
1087 .description_good = "Service cannot use acct()",
1088 .description_bad = "Service may use acct()",
1089 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#CapabilityBoundingSet=",
1090 .weight = 25,
1091 .range = 1,
1092 .assess = assess_capability_bounding_set,
1093 .parameter = (UINT64_C(1) << CAP_SYS_PACCT),
1094 },
1095 {
1096 .id = "UMask=",
1097 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#UMask=",
1098 .weight = 100,
1099 .range = 10,
1100 .assess = assess_umask,
1101 },
1102 {
1103 .id = "KeyringMode=",
1104 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#KeyringMode=",
1105 .description_good = "Service doesn't share key material with other services",
1106 .description_bad = "Service shares key material with other service",
1107 .weight = 1000,
1108 .range = 1,
1109 .assess = assess_keyring_mode,
1110 },
1111 {
1112 .id = "NotifyAccess=",
1113 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#NotifyAccess=",
1114 .description_good = "Service child processes cannot alter service state",
1115 .description_bad = "Service child processes may alter service state",
1116 .weight = 1000,
1117 .range = 1,
1118 .assess = assess_notify_access,
1119 },
1120 {
1121 .id = "RemoveIPC=",
1122 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RemoveIPC=",
1123 .description_good = "Service user cannot leave SysV IPC objects around",
1124 .description_bad = "Service user may leave SysV IPC objects around",
1125 .description_na = "Service runs as root, option does not apply",
1126 .weight = 100,
1127 .range = 1,
1128 .assess = assess_remove_ipc,
1129 .offset = offsetof(struct security_info, remove_ipc),
1130 },
1131 {
1132 .id = "Delegate=",
1133 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#Delegate=",
1134 .description_good = "Service does not maintain its own delegated control group subtree",
1135 .description_bad = "Service maintains its own delegated control group subtree",
1136 .weight = 100,
1137 .range = 1,
1138 .assess = assess_bool,
1139 .offset = offsetof(struct security_info, delegate),
1140 .parameter = true, /* invert! */
1141 },
1142 {
1143 .id = "RestrictRealtime=",
1144 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictRealtime=",
1145 .description_good = "Service realtime scheduling access is restricted",
1146 .description_bad = "Service may acquire realtime scheduling",
1147 .weight = 500,
1148 .range = 1,
1149 .assess = assess_bool,
1150 .offset = offsetof(struct security_info, restrict_realtime),
1151 },
1152 {
1153 .id = "RestrictSUIDSGID=",
1154 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictSUIDSGID=",
1155 .description_good = "SUID/SGID file creation by service is restricted",
1156 .description_bad = "Service may create SUID/SGID files",
1157 .weight = 1000,
1158 .range = 1,
1159 .assess = assess_bool,
1160 .offset = offsetof(struct security_info, restrict_suid_sgid),
1161 },
1162 {
1163 .id = "RestrictNamespaces=~CLONE_NEWUSER",
1164 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
1165 .description_good = "Service cannot create user namespaces",
1166 .description_bad = "Service may create user namespaces",
1167 .weight = 1500,
1168 .range = 1,
1169 .assess = assess_restrict_namespaces,
1170 .parameter = CLONE_NEWUSER,
1171 },
1172 {
1173 .id = "RestrictNamespaces=~CLONE_NEWNS",
1174 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
1175 .description_good = "Service cannot create file system namespaces",
1176 .description_bad = "Service may create file system namespaces",
1177 .weight = 500,
1178 .range = 1,
1179 .assess = assess_restrict_namespaces,
1180 .parameter = CLONE_NEWNS,
1181 },
1182 {
1183 .id = "RestrictNamespaces=~CLONE_NEWIPC",
1184 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
1185 .description_good = "Service cannot create IPC namespaces",
1186 .description_bad = "Service may create IPC namespaces",
1187 .weight = 500,
1188 .range = 1,
1189 .assess = assess_restrict_namespaces,
1190 .parameter = CLONE_NEWIPC,
1191 },
1192 {
1193 .id = "RestrictNamespaces=~CLONE_NEWPID",
1194 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
1195 .description_good = "Service cannot create process namespaces",
1196 .description_bad = "Service may create process namespaces",
1197 .weight = 500,
1198 .range = 1,
1199 .assess = assess_restrict_namespaces,
1200 .parameter = CLONE_NEWPID,
1201 },
1202 {
1203 .id = "RestrictNamespaces=~CLONE_NEWCGROUP",
1204 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
1205 .description_good = "Service cannot create cgroup namespaces",
1206 .description_bad = "Service may create cgroup namespaces",
1207 .weight = 500,
1208 .range = 1,
1209 .assess = assess_restrict_namespaces,
1210 .parameter = CLONE_NEWCGROUP,
1211 },
1212 {
1213 .id = "RestrictNamespaces=~CLONE_NEWNET",
1214 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
1215 .description_good = "Service cannot create network namespaces",
1216 .description_bad = "Service may create network namespaces",
1217 .weight = 500,
1218 .range = 1,
1219 .assess = assess_restrict_namespaces,
1220 .parameter = CLONE_NEWNET,
1221 },
1222 {
1223 .id = "RestrictNamespaces=~CLONE_NEWUTS",
1224 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
1225 .description_good = "Service cannot create hostname namespaces",
1226 .description_bad = "Service may create hostname namespaces",
1227 .weight = 100,
1228 .range = 1,
1229 .assess = assess_restrict_namespaces,
1230 .parameter = CLONE_NEWUTS,
1231 },
1232 {
1233 .id = "RestrictAddressFamilies=~AF_(INET|INET6)",
1234 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictAddressFamilies=",
1235 .description_good = "Service cannot allocate Internet sockets",
1236 .description_bad = "Service may allocate Internet sockets",
1237 .weight = 1500,
1238 .range = 1,
1239 .assess = assess_bool,
1240 .offset = offsetof(struct security_info, restrict_address_family_inet),
1241 },
1242 {
1243 .id = "RestrictAddressFamilies=~AF_UNIX",
1244 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictAddressFamilies=",
1245 .description_good = "Service cannot allocate local sockets",
1246 .description_bad = "Service may allocate local sockets",
1247 .weight = 25,
1248 .range = 1,
1249 .assess = assess_bool,
1250 .offset = offsetof(struct security_info, restrict_address_family_unix),
1251 },
1252 {
1253 .id = "RestrictAddressFamilies=~AF_NETLINK",
1254 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictAddressFamilies=",
1255 .description_good = "Service cannot allocate netlink sockets",
1256 .description_bad = "Service may allocate netlink sockets",
1257 .weight = 200,
1258 .range = 1,
1259 .assess = assess_bool,
1260 .offset = offsetof(struct security_info, restrict_address_family_netlink),
1261 },
1262 {
1263 .id = "RestrictAddressFamilies=~AF_PACKET",
1264 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictAddressFamilies=",
1265 .description_good = "Service cannot allocate packet sockets",
1266 .description_bad = "Service may allocate packet sockets",
1267 .weight = 1000,
1268 .range = 1,
1269 .assess = assess_bool,
1270 .offset = offsetof(struct security_info, restrict_address_family_packet),
1271 },
1272 {
1273 .id = "RestrictAddressFamilies=~…",
1274 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictAddressFamilies=",
1275 .description_good = "Service cannot allocate exotic sockets",
1276 .description_bad = "Service may allocate exotic sockets",
1277 .weight = 1250,
1278 .range = 1,
1279 .assess = assess_bool,
1280 .offset = offsetof(struct security_info, restrict_address_family_other),
1281 },
1282 {
1283 .id = "SystemCallArchitectures=",
1284 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallArchitectures=",
1285 .weight = 1000,
1286 .range = 10,
1287 .assess = assess_system_call_architectures,
1288 },
1289 #if HAVE_SECCOMP
1290 {
1291 .id = "SystemCallFilter=~@swap",
1292 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
1293 .weight = 1000,
1294 .range = 10,
1295 .assess = assess_system_call_filter,
1296 .parameter = SYSCALL_FILTER_SET_SWAP,
1297 },
1298 {
1299 .id = "SystemCallFilter=~@obsolete",
1300 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
1301 .weight = 250,
1302 .range = 10,
1303 .assess = assess_system_call_filter,
1304 .parameter = SYSCALL_FILTER_SET_OBSOLETE,
1305 },
1306 {
1307 .id = "SystemCallFilter=~@clock",
1308 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
1309 .weight = 1000,
1310 .range = 10,
1311 .assess = assess_system_call_filter,
1312 .parameter = SYSCALL_FILTER_SET_CLOCK,
1313 },
1314 {
1315 .id = "SystemCallFilter=~@cpu-emulation",
1316 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
1317 .weight = 250,
1318 .range = 10,
1319 .assess = assess_system_call_filter,
1320 .parameter = SYSCALL_FILTER_SET_CPU_EMULATION,
1321 },
1322 {
1323 .id = "SystemCallFilter=~@debug",
1324 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
1325 .weight = 1000,
1326 .range = 10,
1327 .assess = assess_system_call_filter,
1328 .parameter = SYSCALL_FILTER_SET_DEBUG,
1329 },
1330 {
1331 .id = "SystemCallFilter=~@mount",
1332 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
1333 .weight = 1000,
1334 .range = 10,
1335 .assess = assess_system_call_filter,
1336 .parameter = SYSCALL_FILTER_SET_MOUNT,
1337 },
1338 {
1339 .id = "SystemCallFilter=~@module",
1340 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
1341 .weight = 1000,
1342 .range = 10,
1343 .assess = assess_system_call_filter,
1344 .parameter = SYSCALL_FILTER_SET_MODULE,
1345 },
1346 {
1347 .id = "SystemCallFilter=~@raw-io",
1348 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
1349 .weight = 1000,
1350 .range = 10,
1351 .assess = assess_system_call_filter,
1352 .parameter = SYSCALL_FILTER_SET_RAW_IO,
1353 },
1354 {
1355 .id = "SystemCallFilter=~@reboot",
1356 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
1357 .weight = 1000,
1358 .range = 10,
1359 .assess = assess_system_call_filter,
1360 .parameter = SYSCALL_FILTER_SET_REBOOT,
1361 },
1362 {
1363 .id = "SystemCallFilter=~@privileged",
1364 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
1365 .weight = 700,
1366 .range = 10,
1367 .assess = assess_system_call_filter,
1368 .parameter = SYSCALL_FILTER_SET_PRIVILEGED,
1369 },
1370 {
1371 .id = "SystemCallFilter=~@resources",
1372 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#SystemCallFilter=",
1373 .weight = 700,
1374 .range = 10,
1375 .assess = assess_system_call_filter,
1376 .parameter = SYSCALL_FILTER_SET_RESOURCES,
1377 },
1378 #endif
1379 {
1380 .id = "IPAddressDeny=",
1381 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#IPAddressDeny=",
1382 .weight = 1000,
1383 .range = 10,
1384 .assess = assess_ip_address_allow,
1385 },
1386 {
1387 .id = "DeviceAllow=",
1388 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#DeviceAllow=",
1389 .weight = 1000,
1390 .range = 10,
1391 .assess = assess_device_allow,
1392 },
1393 {
1394 .id = "AmbientCapabilities=",
1395 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#AmbientCapabilities=",
1396 .description_good = "Service process does not receive ambient capabilities",
1397 .description_bad = "Service process receives ambient capabilities",
1398 .weight = 500,
1399 .range = 1,
1400 .assess = assess_ambient_capabilities,
1401 },
1402 };
1403
1404 static int assess(const struct security_info *info, Table *overview_table, AnalyzeSecurityFlags flags) {
1405 static const struct {
1406 uint64_t exposure;
1407 const char *name;
1408 const char *color;
1409 SpecialGlyph smiley;
1410 } badness_table[] = {
1411 { 100, "DANGEROUS", ANSI_HIGHLIGHT_RED, SPECIAL_GLYPH_DEPRESSED_SMILEY },
1412 { 90, "UNSAFE", ANSI_HIGHLIGHT_RED, SPECIAL_GLYPH_UNHAPPY_SMILEY },
1413 { 75, "EXPOSED", ANSI_HIGHLIGHT_YELLOW, SPECIAL_GLYPH_SLIGHTLY_UNHAPPY_SMILEY },
1414 { 50, "MEDIUM", NULL, SPECIAL_GLYPH_NEUTRAL_SMILEY },
1415 { 10, "OK", ANSI_HIGHLIGHT_GREEN, SPECIAL_GLYPH_SLIGHTLY_HAPPY_SMILEY },
1416 { 1, "SAFE", ANSI_HIGHLIGHT_GREEN, SPECIAL_GLYPH_HAPPY_SMILEY },
1417 { 0, "PERFECT", ANSI_HIGHLIGHT_GREEN, SPECIAL_GLYPH_ECSTATIC_SMILEY },
1418 };
1419
1420 uint64_t badness_sum = 0, weight_sum = 0, exposure;
1421 _cleanup_(table_unrefp) Table *details_table = NULL;
1422 size_t i;
1423 int r;
1424
1425 if (!FLAGS_SET(flags, ANALYZE_SECURITY_SHORT)) {
1426 details_table = table_new(" ", "name", "description", "weight", "badness", "range", "exposure");
1427 if (!details_table)
1428 return log_oom();
1429
1430 (void) table_set_sort(details_table, 3, 1, (size_t) -1);
1431 (void) table_set_reverse(details_table, 3, true);
1432
1433 if (getenv_bool("SYSTEMD_ANALYZE_DEBUG") <= 0)
1434 (void) table_set_display(details_table, 0, 1, 2, 6, (size_t) -1);
1435 }
1436
1437 for (i = 0; i < ELEMENTSOF(security_assessor_table); i++) {
1438 const struct security_assessor *a = security_assessor_table + i;
1439 _cleanup_free_ char *d = NULL;
1440 uint64_t badness;
1441 void *data;
1442
1443 data = (uint8_t*) info + a->offset;
1444
1445 if (a->default_dependencies_only && !info->default_dependencies) {
1446 badness = UINT64_MAX;
1447 d = strdup("Service runs in special boot phase, option does not apply");
1448 if (!d)
1449 return log_oom();
1450 } else {
1451 r = a->assess(a, info, data, &badness, &d);
1452 if (r < 0)
1453 return r;
1454 }
1455
1456 assert(a->range > 0);
1457
1458 if (badness != UINT64_MAX) {
1459 assert(badness <= a->range);
1460
1461 badness_sum += DIV_ROUND_UP(badness * a->weight, a->range);
1462 weight_sum += a->weight;
1463 }
1464
1465 if (details_table) {
1466 const char *checkmark, *description, *color = NULL;
1467 TableCell *cell;
1468
1469 if (badness == UINT64_MAX) {
1470 checkmark = " ";
1471 description = a->description_na;
1472 color = NULL;
1473 } else if (badness == a->range) {
1474 checkmark = special_glyph(SPECIAL_GLYPH_CROSS_MARK);
1475 description = a->description_bad;
1476 color = ansi_highlight_red();
1477 } else if (badness == 0) {
1478 checkmark = special_glyph(SPECIAL_GLYPH_CHECK_MARK);
1479 description = a->description_good;
1480 color = ansi_highlight_green();
1481 } else {
1482 checkmark = special_glyph(SPECIAL_GLYPH_CROSS_MARK);
1483 description = NULL;
1484 color = ansi_highlight_red();
1485 }
1486
1487 if (d)
1488 description = d;
1489
1490 r = table_add_cell_full(details_table, &cell, TABLE_STRING, checkmark, 1, 1, 0, 0, 0);
1491 if (r < 0)
1492 return log_error_errno(r, "Failed to add cell to table: %m");
1493 if (color)
1494 (void) table_set_color(details_table, cell, color);
1495
1496 r = table_add_cell(details_table, &cell, TABLE_STRING, a->id);
1497 if (r < 0)
1498 return log_error_errno(r, "Failed to add cell to table: %m");
1499 if (a->url)
1500 (void) table_set_url(details_table, cell, a->url);
1501
1502 r = table_add_cell(details_table, NULL, TABLE_STRING, description);
1503 if (r < 0)
1504 return log_error_errno(r, "Failed to add cell to table: %m");
1505
1506 r = table_add_cell(details_table, &cell, TABLE_UINT64, &a->weight);
1507 if (r < 0)
1508 return log_error_errno(r, "Failed to add cell to table: %m");
1509 (void) table_set_align_percent(details_table, cell, 100);
1510
1511 r = table_add_cell(details_table, &cell, TABLE_UINT64, &badness);
1512 if (r < 0)
1513 return log_error_errno(r, "Failed to add cell to table: %m");
1514 (void) table_set_align_percent(details_table, cell, 100);
1515
1516 r = table_add_cell(details_table, &cell, TABLE_UINT64, &a->range);
1517 if (r < 0)
1518 return log_error_errno(r, "Failed to add cell to table: %m");
1519 (void) table_set_align_percent(details_table, cell, 100);
1520
1521 r = table_add_cell(details_table, &cell, TABLE_EMPTY, NULL);
1522 if (r < 0)
1523 return log_error_errno(r, "Failed to add cell to table: %m");
1524 (void) table_set_align_percent(details_table, cell, 100);
1525 }
1526 }
1527
1528 if (details_table) {
1529 size_t row;
1530
1531 for (row = 1; row < table_get_rows(details_table); row++) {
1532 char buf[DECIMAL_STR_MAX(uint64_t) + 1 + DECIMAL_STR_MAX(uint64_t) + 1];
1533 const uint64_t *weight, *badness, *range;
1534 TableCell *cell;
1535 uint64_t x;
1536
1537 assert_se(weight = table_get_at(details_table, row, 3));
1538 assert_se(badness = table_get_at(details_table, row, 4));
1539 assert_se(range = table_get_at(details_table, row, 5));
1540
1541 if (*badness == UINT64_MAX || *badness == 0)
1542 continue;
1543
1544 assert_se(cell = table_get_cell(details_table, row, 6));
1545
1546 x = DIV_ROUND_UP(DIV_ROUND_UP(*badness * *weight * 100U, *range), weight_sum);
1547 xsprintf(buf, "%" PRIu64 ".%" PRIu64, x / 10, x % 10);
1548
1549 r = table_update(details_table, cell, TABLE_STRING, buf);
1550 if (r < 0)
1551 return log_error_errno(r, "Failed to update cell in table: %m");
1552 }
1553
1554 r = table_print(details_table, stdout);
1555 if (r < 0)
1556 return log_error_errno(r, "Failed to output table: %m");
1557 }
1558
1559 assert(weight_sum > 0);
1560 exposure = DIV_ROUND_UP(badness_sum * 100U, weight_sum);
1561
1562 for (i = 0; i < ELEMENTSOF(badness_table); i++)
1563 if (exposure >= badness_table[i].exposure)
1564 break;
1565
1566 assert(i < ELEMENTSOF(badness_table));
1567
1568 if (details_table) {
1569 _cleanup_free_ char *clickable = NULL;
1570 const char *name;
1571
1572 /* If we shall output the details table, also print the brief summary underneath */
1573
1574 if (info->fragment_path) {
1575 r = terminal_urlify_path(info->fragment_path, info->id, &clickable);
1576 if (r < 0)
1577 return log_oom();
1578
1579 name = clickable;
1580 } else
1581 name = info->id;
1582
1583 printf("\n%s %sOverall exposure level for %s%s: %s%" PRIu64 ".%" PRIu64 " %s%s %s\n",
1584 special_glyph(SPECIAL_GLYPH_ARROW),
1585 ansi_highlight(),
1586 name,
1587 ansi_normal(),
1588 colors_enabled() ? strempty(badness_table[i].color) : "",
1589 exposure / 10, exposure % 10,
1590 badness_table[i].name,
1591 ansi_normal(),
1592 special_glyph(badness_table[i].smiley));
1593 }
1594
1595 fflush(stdout);
1596
1597 if (overview_table) {
1598 char buf[DECIMAL_STR_MAX(uint64_t) + 1 + DECIMAL_STR_MAX(uint64_t) + 1];
1599 TableCell *cell;
1600
1601 r = table_add_cell(overview_table, &cell, TABLE_STRING, info->id);
1602 if (r < 0)
1603 return log_error_errno(r, "Failed to add cell to table: %m");
1604 if (info->fragment_path) {
1605 _cleanup_free_ char *url = NULL;
1606
1607 r = file_url_from_path(info->fragment_path, &url);
1608 if (r < 0)
1609 return log_error_errno(r, "Failed to generate URL from path: %m");
1610
1611 (void) table_set_url(overview_table, cell, url);
1612 }
1613
1614 xsprintf(buf, "%" PRIu64 ".%" PRIu64, exposure / 10, exposure % 10);
1615 r = table_add_cell(overview_table, &cell, TABLE_STRING, buf);
1616 if (r < 0)
1617 return log_error_errno(r, "Failed to add cell to table: %m");
1618 (void) table_set_align_percent(overview_table, cell, 100);
1619
1620 r = table_add_cell(overview_table, &cell, TABLE_STRING, badness_table[i].name);
1621 if (r < 0)
1622 return log_error_errno(r, "Failed to add cell to table: %m");
1623 (void) table_set_color(overview_table, cell, strempty(badness_table[i].color));
1624
1625 r = table_add_cell(overview_table, NULL, TABLE_STRING, special_glyph(badness_table[i].smiley));
1626 if (r < 0)
1627 return log_error_errno(r, "Failed to add cell to table: %m");
1628 }
1629
1630 return 0;
1631 }
1632
1633 static int property_read_restrict_address_families(
1634 sd_bus *bus,
1635 const char *member,
1636 sd_bus_message *m,
1637 sd_bus_error *error,
1638 void *userdata) {
1639
1640 struct security_info *info = userdata;
1641 int whitelist, r;
1642
1643 assert(bus);
1644 assert(member);
1645 assert(m);
1646
1647 r = sd_bus_message_enter_container(m, 'r', "bas");
1648 if (r < 0)
1649 return r;
1650
1651 r = sd_bus_message_read(m, "b", &whitelist);
1652 if (r < 0)
1653 return r;
1654
1655 info->restrict_address_family_inet =
1656 info->restrict_address_family_unix =
1657 info->restrict_address_family_netlink =
1658 info->restrict_address_family_packet =
1659 info->restrict_address_family_other = whitelist;
1660
1661 r = sd_bus_message_enter_container(m, 'a', "s");
1662 if (r < 0)
1663 return r;
1664
1665 for (;;) {
1666 const char *name;
1667
1668 r = sd_bus_message_read(m, "s", &name);
1669 if (r < 0)
1670 return r;
1671 if (r == 0)
1672 break;
1673
1674 if (STR_IN_SET(name, "AF_INET", "AF_INET6"))
1675 info->restrict_address_family_inet = !whitelist;
1676 else if (streq(name, "AF_UNIX"))
1677 info->restrict_address_family_unix = !whitelist;
1678 else if (streq(name, "AF_NETLINK"))
1679 info->restrict_address_family_netlink = !whitelist;
1680 else if (streq(name, "AF_PACKET"))
1681 info->restrict_address_family_packet = !whitelist;
1682 else
1683 info->restrict_address_family_other = !whitelist;
1684 }
1685
1686 r = sd_bus_message_exit_container(m);
1687 if (r < 0)
1688 return r;
1689
1690 return sd_bus_message_exit_container(m);
1691 }
1692
1693 static int property_read_system_call_filter(
1694 sd_bus *bus,
1695 const char *member,
1696 sd_bus_message *m,
1697 sd_bus_error *error,
1698 void *userdata) {
1699
1700 struct security_info *info = userdata;
1701 int whitelist, r;
1702
1703 assert(bus);
1704 assert(member);
1705 assert(m);
1706
1707 r = sd_bus_message_enter_container(m, 'r', "bas");
1708 if (r < 0)
1709 return r;
1710
1711 r = sd_bus_message_read(m, "b", &whitelist);
1712 if (r < 0)
1713 return r;
1714
1715 info->system_call_filter_whitelist = whitelist;
1716
1717 r = sd_bus_message_enter_container(m, 'a', "s");
1718 if (r < 0)
1719 return r;
1720
1721 for (;;) {
1722 const char *name;
1723
1724 r = sd_bus_message_read(m, "s", &name);
1725 if (r < 0)
1726 return r;
1727 if (r == 0)
1728 break;
1729
1730 r = set_ensure_allocated(&info->system_call_filter, &string_hash_ops);
1731 if (r < 0)
1732 return r;
1733
1734 r = set_put_strdup(info->system_call_filter, name);
1735 if (r < 0)
1736 return r;
1737 }
1738
1739 r = sd_bus_message_exit_container(m);
1740 if (r < 0)
1741 return r;
1742
1743 return sd_bus_message_exit_container(m);
1744 }
1745
1746 static int property_read_ip_address_allow(
1747 sd_bus *bus,
1748 const char *member,
1749 sd_bus_message *m,
1750 sd_bus_error *error,
1751 void *userdata) {
1752
1753 struct security_info *info = userdata;
1754 bool deny_ipv4 = false, deny_ipv6 = false;
1755 int r;
1756
1757 assert(bus);
1758 assert(member);
1759 assert(m);
1760
1761 r = sd_bus_message_enter_container(m, 'a', "(iayu)");
1762 if (r < 0)
1763 return r;
1764
1765 for (;;) {
1766 const void *data;
1767 size_t size;
1768 int32_t family;
1769 uint32_t prefixlen;
1770
1771 r = sd_bus_message_enter_container(m, 'r', "iayu");
1772 if (r < 0)
1773 return r;
1774 if (r == 0)
1775 break;
1776
1777 r = sd_bus_message_read(m, "i", &family);
1778 if (r < 0)
1779 return r;
1780
1781 r = sd_bus_message_read_array(m, 'y', &data, &size);
1782 if (r < 0)
1783 return r;
1784
1785 r = sd_bus_message_read(m, "u", &prefixlen);
1786 if (r < 0)
1787 return r;
1788
1789 r = sd_bus_message_exit_container(m);
1790 if (r < 0)
1791 return r;
1792
1793 if (streq(member, "IPAddressAllow")) {
1794 union in_addr_union u;
1795
1796 if (family == AF_INET && size == 4 && prefixlen == 8)
1797 memcpy(&u.in, data, size);
1798 else if (family == AF_INET6 && size == 16 && prefixlen == 128)
1799 memcpy(&u.in6, data, size);
1800 else {
1801 info->ip_address_allow_other = true;
1802 continue;
1803 }
1804
1805 if (in_addr_is_localhost(family, &u))
1806 info->ip_address_allow_localhost = true;
1807 else
1808 info->ip_address_allow_other = true;
1809 } else {
1810 assert(streq(member, "IPAddressDeny"));
1811
1812 if (family == AF_INET && size == 4 && prefixlen == 0)
1813 deny_ipv4 = true;
1814 else if (family == AF_INET6 && size == 16 && prefixlen == 0)
1815 deny_ipv6 = true;
1816 }
1817 }
1818
1819 info->ip_address_deny_all = deny_ipv4 && deny_ipv6;
1820
1821 return sd_bus_message_exit_container(m);
1822 }
1823
1824 static int property_read_device_allow(
1825 sd_bus *bus,
1826 const char *member,
1827 sd_bus_message *m,
1828 sd_bus_error *error,
1829 void *userdata) {
1830
1831 struct security_info *info = userdata;
1832 size_t n = 0;
1833 int r;
1834
1835 assert(bus);
1836 assert(member);
1837 assert(m);
1838
1839 r = sd_bus_message_enter_container(m, 'a', "(ss)");
1840 if (r < 0)
1841 return r;
1842
1843 for (;;) {
1844 const char *name, *policy;
1845
1846 r = sd_bus_message_read(m, "(ss)", &name, &policy);
1847 if (r < 0)
1848 return r;
1849 if (r == 0)
1850 break;
1851
1852 n++;
1853 }
1854
1855 info->device_allow_non_empty = n > 0;
1856
1857 return sd_bus_message_exit_container(m);
1858 }
1859
1860 static int acquire_security_info(sd_bus *bus, const char *name, struct security_info *info, AnalyzeSecurityFlags flags) {
1861
1862 static const struct bus_properties_map security_map[] = {
1863 { "AmbientCapabilities", "t", NULL, offsetof(struct security_info, ambient_capabilities) },
1864 { "CapabilityBoundingSet", "t", NULL, offsetof(struct security_info, capability_bounding_set) },
1865 { "DefaultDependencies", "b", NULL, offsetof(struct security_info, default_dependencies) },
1866 { "Delegate", "b", NULL, offsetof(struct security_info, delegate) },
1867 { "DeviceAllow", "a(ss)", property_read_device_allow, 0 },
1868 { "DevicePolicy", "s", NULL, offsetof(struct security_info, device_policy) },
1869 { "DynamicUser", "b", NULL, offsetof(struct security_info, dynamic_user) },
1870 { "FragmentPath", "s", NULL, offsetof(struct security_info, fragment_path) },
1871 { "IPAddressAllow", "a(iayu)", property_read_ip_address_allow, 0 },
1872 { "IPAddressDeny", "a(iayu)", property_read_ip_address_allow, 0 },
1873 { "Id", "s", NULL, offsetof(struct security_info, id) },
1874 { "KeyringMode", "s", NULL, offsetof(struct security_info, keyring_mode) },
1875 { "LoadState", "s", NULL, offsetof(struct security_info, load_state) },
1876 { "LockPersonality", "b", NULL, offsetof(struct security_info, lock_personality) },
1877 { "MemoryDenyWriteExecute", "b", NULL, offsetof(struct security_info, memory_deny_write_execute) },
1878 { "NoNewPrivileges", "b", NULL, offsetof(struct security_info, no_new_privileges) },
1879 { "NotifyAccess", "s", NULL, offsetof(struct security_info, notify_access) },
1880 { "PrivateDevices", "b", NULL, offsetof(struct security_info, private_devices) },
1881 { "PrivateMounts", "b", NULL, offsetof(struct security_info, private_mounts) },
1882 { "PrivateNetwork", "b", NULL, offsetof(struct security_info, private_network) },
1883 { "PrivateTmp", "b", NULL, offsetof(struct security_info, private_tmp) },
1884 { "PrivateUsers", "b", NULL, offsetof(struct security_info, private_users) },
1885 { "ProtectControlGroups", "b", NULL, offsetof(struct security_info, protect_control_groups) },
1886 { "ProtectHome", "s", NULL, offsetof(struct security_info, protect_home) },
1887 { "ProtectHostname", "b", NULL, offsetof(struct security_info, protect_hostname) },
1888 { "ProtectKernelModules", "b", NULL, offsetof(struct security_info, protect_kernel_modules) },
1889 { "ProtectKernelTunables", "b", NULL, offsetof(struct security_info, protect_kernel_tunables) },
1890 { "ProtectSystem", "s", NULL, offsetof(struct security_info, protect_system) },
1891 { "RemoveIPC", "b", NULL, offsetof(struct security_info, remove_ipc) },
1892 { "RestrictAddressFamilies", "(bas)", property_read_restrict_address_families, 0 },
1893 { "RestrictNamespaces", "t", NULL, offsetof(struct security_info, restrict_namespaces) },
1894 { "RestrictRealtime", "b", NULL, offsetof(struct security_info, restrict_realtime) },
1895 { "RestrictSUIDSGID", "b", NULL, offsetof(struct security_info, restrict_suid_sgid) },
1896 { "RootDirectory", "s", NULL, offsetof(struct security_info, root_directory) },
1897 { "RootImage", "s", NULL, offsetof(struct security_info, root_image) },
1898 { "SupplementaryGroups", "as", NULL, offsetof(struct security_info, supplementary_groups) },
1899 { "SystemCallArchitectures", "as", NULL, offsetof(struct security_info, system_call_architectures) },
1900 { "SystemCallFilter", "(as)", property_read_system_call_filter, 0 },
1901 { "Type", "s", NULL, offsetof(struct security_info, type) },
1902 { "UMask", "u", NULL, offsetof(struct security_info, _umask) },
1903 { "User", "s", NULL, offsetof(struct security_info, user) },
1904 {}
1905 };
1906
1907 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1908 _cleanup_free_ char *path = NULL;
1909 int r;
1910
1911 /* Note: this mangles *info on failure! */
1912
1913 assert(bus);
1914 assert(name);
1915 assert(info);
1916
1917 path = unit_dbus_path_from_name(name);
1918 if (!path)
1919 return log_oom();
1920
1921 r = bus_map_all_properties(bus,
1922 "org.freedesktop.systemd1",
1923 path,
1924 security_map,
1925 BUS_MAP_STRDUP|BUS_MAP_BOOLEAN_AS_BOOL,
1926 &error,
1927 NULL,
1928 info);
1929 if (r < 0)
1930 return log_error_errno(r, "Failed to get unit properties: %s", bus_error_message(&error, r));
1931
1932 if (!streq_ptr(info->load_state, "loaded")) {
1933
1934 if (FLAGS_SET(flags, ANALYZE_SECURITY_ONLY_LOADED))
1935 return -EMEDIUMTYPE;
1936
1937 if (streq_ptr(info->load_state, "not-found"))
1938 log_error("Unit %s not found, cannot analyze.", name);
1939 else if (streq_ptr(info->load_state, "masked"))
1940 log_error("Unit %s is masked, cannot analyze.", name);
1941 else
1942 log_error("Unit %s not loaded properly, cannot analyze.", name);
1943
1944 return -EINVAL;
1945 }
1946
1947 if (FLAGS_SET(flags, ANALYZE_SECURITY_ONLY_LONG_RUNNING) && streq_ptr(info->type, "oneshot"))
1948 return -EMEDIUMTYPE;
1949
1950 if (info->private_devices ||
1951 info->private_tmp ||
1952 info->protect_control_groups ||
1953 info->protect_kernel_tunables ||
1954 info->protect_kernel_modules ||
1955 !streq_ptr(info->protect_home, "no") ||
1956 !streq_ptr(info->protect_system, "no") ||
1957 info->root_image)
1958 info->private_mounts = true;
1959
1960 if (info->protect_kernel_modules)
1961 info->capability_bounding_set &= ~(UINT64_C(1) << CAP_SYS_MODULE);
1962
1963 if (info->private_devices)
1964 info->capability_bounding_set &= ~((UINT64_C(1) << CAP_MKNOD) |
1965 (UINT64_C(1) << CAP_SYS_RAWIO));
1966
1967 return 0;
1968 }
1969
1970 static int analyze_security_one(sd_bus *bus, const char *name, Table* overview_table, AnalyzeSecurityFlags flags) {
1971 _cleanup_(security_info_free) struct security_info info = {
1972 .default_dependencies = true,
1973 .capability_bounding_set = UINT64_MAX,
1974 .restrict_namespaces = UINT64_MAX,
1975 ._umask = 0002,
1976 };
1977 int r;
1978
1979 assert(bus);
1980 assert(name);
1981
1982 r = acquire_security_info(bus, name, &info, flags);
1983 if (r == -EMEDIUMTYPE) /* Ignore this one because not loaded or Type is oneshot */
1984 return 0;
1985 if (r < 0)
1986 return r;
1987
1988 r = assess(&info, overview_table, flags);
1989 if (r < 0)
1990 return r;
1991
1992 return 0;
1993 }
1994
1995 int analyze_security(sd_bus *bus, char **units, AnalyzeSecurityFlags flags) {
1996 _cleanup_(table_unrefp) Table *overview_table = NULL;
1997 int ret = 0, r;
1998
1999 assert(bus);
2000
2001 if (strv_length(units) != 1) {
2002 overview_table = table_new("unit", "exposure", "predicate", "happy");
2003 if (!overview_table)
2004 return log_oom();
2005 }
2006
2007 if (strv_isempty(units)) {
2008 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2009 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
2010 _cleanup_strv_free_ char **list = NULL;
2011 size_t allocated = 0, n = 0;
2012 char **i;
2013
2014 r = sd_bus_call_method(
2015 bus,
2016 "org.freedesktop.systemd1",
2017 "/org/freedesktop/systemd1",
2018 "org.freedesktop.systemd1.Manager",
2019 "ListUnits",
2020 &error, &reply,
2021 NULL);
2022 if (r < 0)
2023 return log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
2024
2025 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)");
2026 if (r < 0)
2027 return bus_log_parse_error(r);
2028
2029 for (;;) {
2030 UnitInfo info;
2031 char *copy = NULL;
2032
2033 r = bus_parse_unit_info(reply, &info);
2034 if (r < 0)
2035 return bus_log_parse_error(r);
2036 if (r == 0)
2037 break;
2038
2039 if (!endswith(info.id, ".service"))
2040 continue;
2041
2042 if (!GREEDY_REALLOC(list, allocated, n+2))
2043 return log_oom();
2044
2045 copy = strdup(info.id);
2046 if (!copy)
2047 return log_oom();
2048
2049 list[n++] = copy;
2050 list[n] = NULL;
2051 }
2052
2053 strv_sort(list);
2054
2055 flags |= ANALYZE_SECURITY_SHORT|ANALYZE_SECURITY_ONLY_LOADED|ANALYZE_SECURITY_ONLY_LONG_RUNNING;
2056
2057 STRV_FOREACH(i, list) {
2058 r = analyze_security_one(bus, *i, overview_table, flags);
2059 if (r < 0 && ret >= 0)
2060 ret = r;
2061 }
2062
2063 } else {
2064 char **i;
2065
2066 STRV_FOREACH(i, units) {
2067 _cleanup_free_ char *mangled = NULL, *instance = NULL;
2068 const char *name;
2069
2070 if (!FLAGS_SET(flags, ANALYZE_SECURITY_SHORT) && i != units) {
2071 putc('\n', stdout);
2072 fflush(stdout);
2073 }
2074
2075 r = unit_name_mangle_with_suffix(*i, 0, ".service", &mangled);
2076 if (r < 0)
2077 return log_error_errno(r, "Failed to mangle unit name '%s': %m", *i);
2078
2079 if (!endswith(mangled, ".service")) {
2080 log_error("Unit %s is not a service unit, refusing.", *i);
2081 return -EINVAL;
2082 }
2083
2084 if (unit_name_is_valid(mangled, UNIT_NAME_TEMPLATE)) {
2085 r = unit_name_replace_instance(mangled, "test-instance", &instance);
2086 if (r < 0)
2087 return log_oom();
2088
2089 name = instance;
2090 } else
2091 name = mangled;
2092
2093 r = analyze_security_one(bus, name, overview_table, flags);
2094 if (r < 0 && ret >= 0)
2095 ret = r;
2096 }
2097 }
2098
2099 if (overview_table) {
2100 if (!FLAGS_SET(flags, ANALYZE_SECURITY_SHORT)) {
2101 putc('\n', stdout);
2102 fflush(stdout);
2103 }
2104
2105 r = table_print(overview_table, stdout);
2106 if (r < 0)
2107 return log_error_errno(r, "Failed to output table: %m");
2108 }
2109
2110 return ret;
2111 }