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