]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/analyze/analyze-syscall-filter.c
Merge pull request #25333 from yuwata/find-esp-part-entry-scheme
[thirdparty/systemd.git] / src / analyze / analyze-syscall-filter.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "analyze-syscall-filter.h"
4 #include "analyze.h"
5 #include "fd-util.h"
6 #include "fileio.h"
7 #include "nulstr-util.h"
8 #include "seccomp-util.h"
9 #include "set.h"
10 #include "strv.h"
11 #include "terminal-util.h"
12
13 #if HAVE_SECCOMP
14
15 static int load_kernel_syscalls(Set **ret) {
16 _cleanup_set_free_ Set *syscalls = NULL;
17 _cleanup_fclose_ FILE *f = NULL;
18 int r;
19
20 /* Let's read the available system calls from the list of available tracing events. Slightly dirty,
21 * but good enough for analysis purposes. */
22
23 f = fopen("/sys/kernel/tracing/available_events", "re");
24 if (!f) {
25 /* We tried the non-debugfs mount point and that didn't work. If it wasn't mounted, maybe the
26 * old debugfs mount point works? */
27 f = fopen("/sys/kernel/debug/tracing/available_events", "re");
28 if (!f)
29 return log_full_errno(IN_SET(errno, EPERM, EACCES, ENOENT) ? LOG_DEBUG : LOG_WARNING, errno,
30 "Can't read open tracefs' available_events file: %m");
31 }
32
33 for (;;) {
34 _cleanup_free_ char *line = NULL;
35 const char *e;
36
37 r = read_line(f, LONG_LINE_MAX, &line);
38 if (r < 0)
39 return log_error_errno(r, "Failed to read system call list: %m");
40 if (r == 0)
41 break;
42
43 e = startswith(line, "syscalls:sys_enter_");
44 if (!e)
45 continue;
46
47 /* These are named differently inside the kernel than their external name for historical
48 * reasons. Let's hide them here. */
49 if (STR_IN_SET(e, "newuname", "newfstat", "newstat", "newlstat", "sysctl"))
50 continue;
51
52 r = set_put_strdup(&syscalls, e);
53 if (r < 0)
54 return log_error_errno(r, "Failed to add system call to list: %m");
55 }
56
57 *ret = TAKE_PTR(syscalls);
58 return 0;
59 }
60
61 static void syscall_set_remove(Set *s, const SyscallFilterSet *set) {
62 if (!set)
63 return;
64
65 NULSTR_FOREACH(syscall, set->value) {
66 if (syscall[0] == '@')
67 continue;
68
69 free(set_remove(s, syscall));
70 }
71 }
72
73 static void dump_syscall_filter(const SyscallFilterSet *set) {
74 printf("%s%s%s\n"
75 " # %s\n",
76 ansi_highlight(),
77 set->name,
78 ansi_normal(),
79 set->help);
80
81 NULSTR_FOREACH(syscall, set->value)
82 printf(" %s%s%s\n", syscall[0] == '@' ? ansi_underline() : "", syscall, ansi_normal());
83 }
84
85 int verb_syscall_filters(int argc, char *argv[], void *userdata) {
86 bool first = true;
87
88 pager_open(arg_pager_flags);
89
90 if (strv_isempty(strv_skip(argv, 1))) {
91 _cleanup_set_free_ Set *kernel = NULL, *known = NULL;
92 int k = 0; /* explicit initialization to appease gcc */
93
94 NULSTR_FOREACH(sys, syscall_filter_sets[SYSCALL_FILTER_SET_KNOWN].value)
95 if (set_put_strdup(&known, sys) < 0)
96 return log_oom();
97
98 if (!arg_quiet)
99 k = load_kernel_syscalls(&kernel);
100
101 for (int i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) {
102 const SyscallFilterSet *set = syscall_filter_sets + i;
103 if (!first)
104 puts("");
105
106 dump_syscall_filter(set);
107 syscall_set_remove(kernel, set);
108 if (i != SYSCALL_FILTER_SET_KNOWN)
109 syscall_set_remove(known, set);
110 first = false;
111 }
112
113 if (arg_quiet) /* Let's not show the extra stuff in quiet mode */
114 return 0;
115
116 if (!set_isempty(known)) {
117 _cleanup_free_ char **l = NULL;
118
119 printf("\n"
120 "# %sUngrouped System Calls%s (known but not included in any of the groups except @known):\n",
121 ansi_highlight(), ansi_normal());
122
123 l = set_get_strv(known);
124 if (!l)
125 return log_oom();
126
127 strv_sort(l);
128
129 STRV_FOREACH(syscall, l)
130 printf("# %s\n", *syscall);
131 }
132
133 if (k < 0) {
134 fputc('\n', stdout);
135 fflush(stdout);
136 if (!arg_quiet)
137 log_notice_errno(k, "# Not showing unlisted system calls, couldn't retrieve kernel system call list: %m");
138 } else if (!set_isempty(kernel)) {
139 _cleanup_free_ char **l = NULL;
140
141 printf("\n"
142 "# %sUnlisted System Calls%s (supported by the local kernel, but not included in any of the groups listed above):\n",
143 ansi_highlight(), ansi_normal());
144
145 l = set_get_strv(kernel);
146 if (!l)
147 return log_oom();
148
149 strv_sort(l);
150
151 STRV_FOREACH(syscall, l)
152 printf("# %s\n", *syscall);
153 }
154 } else
155 STRV_FOREACH(name, strv_skip(argv, 1)) {
156 const SyscallFilterSet *set;
157
158 if (!first)
159 puts("");
160
161 set = syscall_filter_set_find(*name);
162 if (!set) {
163 /* make sure the error appears below normal output */
164 fflush(stdout);
165
166 return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
167 "Filter set \"%s\" not found.", *name);
168 }
169
170 dump_syscall_filter(set);
171 first = false;
172 }
173
174 return EXIT_SUCCESS;
175 }
176
177 #else
178 int verb_syscall_filters(int argc, char *argv[], void *userdata) {
179 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Not compiled with syscall filters, sorry.");
180 }
181 #endif