]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
perf trace augmented_raw_syscalls: Add more checks to pass the verifier
authorHoward Chu <howardchu95@gmail.com>
Fri, 11 Oct 2024 02:14:02 +0000 (19:14 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 23 Oct 2024 14:34:56 +0000 (11:34 -0300)
Add some more checks to pass the verifier in more kernels.

Signed-off-by: Howard Chu <howardchu95@gmail.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alan Maguire <alan.maguire@oracle.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20241011021403.4089793-3-howardchu95@gmail.com
[ Reduced the patch removing things that can be done later ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c

index 31df5f0cb14bf3d25ec6239b91205d394e7cb1df..4a62ed593e84edf8cd002751d0b27541195f967a 100644 (file)
@@ -288,6 +288,10 @@ int sys_enter_rename(struct syscall_enter_args *args)
        augmented_args->arg.size = PERF_ALIGN(oldpath_len + 1, sizeof(u64));
        len += augmented_args->arg.size;
 
+       /* Every read from userspace is limited to value size */
+       if (augmented_args->arg.size > sizeof(augmented_args->arg.value))
+               return 1; /* Failure: don't filter */
+
        struct augmented_arg *arg2 = (void *)&augmented_args->arg.value + augmented_args->arg.size;
 
        newpath_len = augmented_arg__read_str(arg2, newpath_arg, sizeof(augmented_args->arg.value));
@@ -315,6 +319,10 @@ int sys_enter_renameat2(struct syscall_enter_args *args)
        augmented_args->arg.size = PERF_ALIGN(oldpath_len + 1, sizeof(u64));
        len += augmented_args->arg.size;
 
+       /* Every read from userspace is limited to value size */
+       if (augmented_args->arg.size > sizeof(augmented_args->arg.value))
+               return 1; /* Failure: don't filter */
+
        struct augmented_arg *arg2 = (void *)&augmented_args->arg.value + augmented_args->arg.size;
 
        newpath_len = augmented_arg__read_str(arg2, newpath_arg, sizeof(augmented_args->arg.value));
@@ -423,8 +431,9 @@ static bool pid_filter__has(struct pids_filtered *pids, pid_t pid)
 static int augment_sys_enter(void *ctx, struct syscall_enter_args *args)
 {
        bool augmented, do_output = false;
-       int zero = 0, size, aug_size, index, output = 0,
+       int zero = 0, size, aug_size, index,
            value_size = sizeof(struct augmented_arg) - offsetof(struct augmented_arg, value);
+       u64 output = 0; /* has to be u64, otherwise it won't pass the verifier */
        unsigned int nr, *beauty_map;
        struct beauty_payload_enter *payload;
        void *arg, *payload_offset;
@@ -490,10 +499,17 @@ static int augment_sys_enter(void *ctx, struct syscall_enter_args *args)
                        }
                }
 
+               /* Augmented data size is limited to sizeof(augmented_arg->unnamed union with value field) */
+               if (aug_size > value_size)
+                       aug_size = value_size;
+
                /* write data to payload */
                if (augmented) {
                        int written = offsetof(struct augmented_arg, value) + aug_size;
 
+                       if (written < 0 || written > sizeof(struct augmented_arg))
+                               return 1;
+
                        ((struct augmented_arg *)payload_offset)->size = aug_size;
                        output += written;
                        payload_offset += written;
@@ -501,7 +517,7 @@ static int augment_sys_enter(void *ctx, struct syscall_enter_args *args)
                }
        }
 
-       if (!do_output)
+       if (!do_output || (sizeof(struct syscall_enter_args) + output) > sizeof(struct beauty_payload_enter))
                return 1;
 
        return augmented__beauty_output(ctx, payload, sizeof(struct syscall_enter_args) + output);