summaryrefslogtreecommitdiff
path: root/src/analyze
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2018-11-14 19:40:45 +0100
committerLennart Poettering <lennart@poettering.net>2018-11-16 16:10:57 +0100
commitcdf6258c2ee414b38b4a6f63a635acbe709ac524 (patch)
tree4da908f04fb235397649810a785d0b0a84d8057c /src/analyze
parentf20db199541ea35c65edfeed9e5401cab6fe6bac (diff)
downloadsystemd-cdf6258c2ee414b38b4a6f63a635acbe709ac524.tar.gz
analyze: show list of syscalls the kernel supports but not included in any group in the output
This is quite useful for making sure our list is complete.
Diffstat (limited to 'src/analyze')
-rw-r--r--src/analyze/analyze.c81
1 files changed, 79 insertions, 2 deletions
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index 0c53a8e21f..89f0891b86 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -21,6 +21,7 @@
#include "conf-files.h"
#include "copy.h"
#include "fd-util.h"
+#include "fileio.h"
#include "glob-util.h"
#include "hashmap.h"
#include "locale-util.h"
@@ -1497,6 +1498,61 @@ static int dump_unit_paths(int argc, char *argv[], void *userdata) {
}
#if HAVE_SECCOMP
+
+static int load_kernel_syscalls(Set **ret) {
+ _cleanup_(set_free_freep) Set *syscalls = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ int r;
+
+ /* Let's read the available system calls from the list of available tracing events. Slightly dirty, but good
+ * enough for analysis purposes. */
+
+ f = fopen("/sys/kernel/debug/tracing/available_events", "re");
+ if (!f)
+ return log_full_errno(IN_SET(errno, EPERM, EACCES, ENOENT) ? LOG_DEBUG : LOG_WARNING, errno, "Can't read open /sys/kernel/debug/tracing/available_events: %m");
+
+ for (;;) {
+ _cleanup_free_ char *line = NULL;
+ const char *e;
+
+ r = read_line(f, LONG_LINE_MAX, &line);
+ if (r < 0)
+ return log_error_errno(r, "Failed to read system call list: %m");
+ if (r == 0)
+ break;
+
+ e = startswith(line, "syscalls:sys_enter_");
+ if (!e)
+ continue;
+
+ /* These are named differently inside the kernel than their external name for historical reasons. Let's hide them here. */
+ if (STR_IN_SET(e, "newuname", "newfstat", "newstat", "newlstat", "sysctl"))
+ continue;
+
+ r = set_ensure_allocated(&syscalls, &string_hash_ops);
+ if (r < 0)
+ return log_oom();
+
+ r = set_put_strdup(syscalls, e);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add system call to list: %m");
+ }
+
+ *ret = TAKE_PTR(syscalls);
+ return 0;
+}
+
+static void kernel_syscalls_remove(Set *s, const SyscallFilterSet *set) {
+ const char *syscall;
+
+ NULSTR_FOREACH(syscall, set->value) {
+ if (syscall[0] == '@')
+ continue;
+
+ (void) set_remove(s, syscall);
+ }
+}
+
static void dump_syscall_filter(const SyscallFilterSet *set) {
const char *syscall;
@@ -1512,14 +1568,35 @@ static int dump_syscall_filters(int argc, char *argv[], void *userdata) {
(void) pager_open(arg_pager_flags);
if (strv_isempty(strv_skip(argv, 1))) {
- int i;
+ _cleanup_(set_free_freep) Set *kernel = NULL;
+ int i, k;
+
+ k = load_kernel_syscalls(&kernel);
for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) {
+ const SyscallFilterSet *set = syscall_filter_sets + i;
if (!first)
puts("");
- dump_syscall_filter(syscall_filter_sets + i);
+
+ dump_syscall_filter(set);
+ kernel_syscalls_remove(kernel, set);
first = false;
}
+
+ if (k < 0) {
+ fputc('\n', stdout);
+ fflush(stdout);
+ log_notice_errno(k, "# Not showing unlisted system calls, couldn't retrieve kernel system call list: %m");
+ } else if (!set_isempty(kernel)) {
+ const char *syscall;
+ Iterator j;
+
+ printf("\n"
+ "# Unlisted System Calls (supported by the local kernel, but not included in any of the groups listed above):\n");
+
+ SET_FOREACH(syscall, kernel, j)
+ printf("# %s\n", syscall);
+ }
} else {
char **name;