History

tracing/probes: Fix MAX_TRACE_ARGS limit handling

When creating a trace_probe we would set nr_args prior to truncating the arguments to MAX_TRACE_ARGS. However, we would only initialize arguments up to the limit. This caused invalid memory access when attempting to set up probes with more than 128 fetchargs. BUG: kernel NULL pointer dereference, address: 0000000000000020 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page PGD 0 P4D 0 Oops: Oops: 0000 [#1] PREEMPT SMP PTI CPU: 0 UID: 0 PID: 1769 Comm: cat Not tainted 6.11.0-rc7+ #8 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-1.fc39 04/01/2014 RIP: 0010:__set_print_fmt+0x134/0x330 Resolve the issue by applying the MAX_TRACE_ARGS limit earlier. Return an error when there are too many arguments instead of silently truncating. Link: https://lore.kernel.org/all/20240930202656.292869-1-mikel@mikelr.com/

Mikel Rychliski committed 2 years ago

Commit 73f35081 parent aff18714 files · +19 −4Browse files

Showing the changes to kernel/trace (4 of 4 files). Show all

Unified · Split

4 files
  1. kernel/trace/trace_eprobe.c +6 −1
  2. kernel/trace/trace_fprobe.c +5 −1
  3. kernel/trace/trace_kprobe.c +5 −1
  4. kernel/trace/trace_uprobe.c +3 −1
kernel/trace/trace_eprobe.c+6−1
@@ -912,6 +912,11 @@ static int __trace_eprobe_create(int argc, const char *argv[]) · 911 unmodified lines
912912 }
913913 }
914914
915+ if (argc - 2 > MAX_TRACE_ARGS) {
916+ ret = -E2BIG;
917+ goto error;
918+ }
919+
915920 mutex_lock(&event_mutex);
916921 event_call = find_and_get_event(sys_name, sys_event);
917922 ep = alloc_event_probe(group, event, event_call, argc - 2);
@@ -937,7 +942,7 @@ static int __trace_eprobe_create(int argc, const char *argv[]) · 19 unmodified lines
937942
938943 argc -= 2; argv += 2;
939944 /* parse arguments */
940− for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
945+ for (i = 0; i < argc; i++) {
941946 trace_probe_log_set_index(i + 2);
942947 ret = trace_eprobe_tp_update_arg(ep, argv, i);
943948 if (ret)
kernel/trace/trace_fprobe.c+5−1
@@ -1187,6 +1187,10 @@ static int __trace_fprobe_create(int argc, const char *argv[]) · 1186 unmodified lines
11871187 argc = new_argc;
11881188 argv = new_argv;
11891189 }
1190+ if (argc > MAX_TRACE_ARGS) {
1191+ ret = -E2BIG;
1192+ goto out;
1193+ }
11901194
11911195 ret = traceprobe_expand_dentry_args(argc, argv, &dbuf);
11921196 if (ret)
@@ -1203,7 +1207,7 @@ static int __trace_fprobe_create(int argc, const char *argv[]) · 10 unmodified lines
12031207 }
12041208
12051209 /* parse arguments */
1206− for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
1210+ for (i = 0; i < argc; i++) {
12071211 trace_probe_log_set_index(i + 2);
12081212 ctx.offset = 0;
12091213 ret = traceprobe_parse_probe_arg(&tf->tp, i, argv[i], &ctx);
kernel/trace/trace_kprobe.c+5−1
@@ -1013,6 +1013,10 @@ static int __trace_kprobe_create(int argc, const char *argv[]) · 1012 unmodified lines
10131013 argc = new_argc;
10141014 argv = new_argv;
10151015 }
1016+ if (argc > MAX_TRACE_ARGS) {
1017+ ret = -E2BIG;
1018+ goto out;
1019+ }
10161020
10171021 ret = traceprobe_expand_dentry_args(argc, argv, &dbuf);
10181022 if (ret)
@@ -1029,7 +1033,7 @@ static int __trace_kprobe_create(int argc, const char *argv[]) · 10 unmodified lines
10291033 }
10301034
10311035 /* parse arguments */
1032− for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
1036+ for (i = 0; i < argc; i++) {
10331037 trace_probe_log_set_index(i + 2);
10341038 ctx.offset = 0;
10351039 ret = traceprobe_parse_probe_arg(&tk->tp, i, argv[i], &ctx);
kernel/trace/trace_uprobe.c+3−1
@@ -565,6 +565,8 @@ static int __trace_uprobe_create(int argc, const char **argv) · 564 unmodified lines
565565
566566 if (argc < 2)
567567 return -ECANCELED;
568+ if (argc - 2 > MAX_TRACE_ARGS)
569+ return -E2BIG;
568570
569571 if (argv[0][1] == ':')
570572 event = &argv[0][2];
@@ -690,7 +692,7 @@ static int __trace_uprobe_create(int argc, const char **argv) · 119 unmodified lines
690692 tu->filename = filename;
691693
692694 /* parse arguments */
693− for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
695+ for (i = 0; i < argc; i++) {
694696 struct traceprobe_parse_context ctx = {
695697 .flags = (is_return ? TPARG_FL_RETURN : 0) | TPARG_FL_USER,
696698 };