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