Skip to content

Commit 0934ae9

Browse files
committed
tracing: Fix reading strings from synthetic events
The follow commands caused a crash: # cd /sys/kernel/tracing # echo 's:open char file[]' > dynamic_events # echo 'hist:keys=common_pid:file=filename:onchange($file).trace(open,$file)' > events/syscalls/sys_enter_openat/trigger' # echo 1 > events/synthetic/open/enable BOOM! The problem is that the synthetic event field "char file[]" will read the value given to it as a string without any memory checks to make sure the address is valid. The above example will pass in the user space address and the sythetic event code will happily call strlen() on it and then strscpy() where either one will cause an oops when accessing user space addresses. Use the helper functions from trace_kprobe and trace_eprobe that can read strings safely (and actually succeed when the address is from user space and the memory is mapped in). Now the above can show: packagekitd-1721 [000] ...2. 104.597170: open: file=/usr/lib/rpm/fileattrs/cmake.attr in:imjournal-978 [006] ...2. 104.599642: open: file=/var/lib/rsyslog/imjournal.state.tmp packagekitd-1721 [000] ...2. 104.626308: open: file=/usr/lib/rpm/fileattrs/debuginfo.attr Link: https://lkml.kernel.org/r/[email protected] Cc: [email protected] Cc: Andrew Morton <[email protected]> Cc: Tom Zanussi <[email protected]> Acked-by: Masami Hiramatsu (Google) <[email protected]> Reviewed-by: Tom Zanussi <[email protected]> Fixes: bd82631 ("tracing: Add support for dynamic strings to synthetic events") Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent 2e9906f commit 0934ae9

File tree

1 file changed

+17
-6
lines changed

1 file changed

+17
-6
lines changed

kernel/trace/trace_events_synth.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
/* for gfp flag names */
1818
#include <linux/trace_events.h>
1919
#include <trace/events/mmflags.h>
20+
#include "trace_probe.h"
21+
#include "trace_probe_kernel.h"
2022

2123
#include "trace_synth.h"
2224

@@ -409,6 +411,7 @@ static unsigned int trace_string(struct synth_trace_event *entry,
409411
{
410412
unsigned int len = 0;
411413
char *str_field;
414+
int ret;
412415

413416
if (is_dynamic) {
414417
u32 data_offset;
@@ -417,19 +420,27 @@ static unsigned int trace_string(struct synth_trace_event *entry,
417420
data_offset += event->n_u64 * sizeof(u64);
418421
data_offset += data_size;
419422

420-
str_field = (char *)entry + data_offset;
421-
422-
len = strlen(str_val) + 1;
423-
strscpy(str_field, str_val, len);
423+
len = kern_fetch_store_strlen((unsigned long)str_val);
424424

425425
data_offset |= len << 16;
426426
*(u32 *)&entry->fields[*n_u64] = data_offset;
427427

428+
ret = kern_fetch_store_string((unsigned long)str_val, &entry->fields[*n_u64], entry);
429+
428430
(*n_u64)++;
429431
} else {
430432
str_field = (char *)&entry->fields[*n_u64];
431433

432-
strscpy(str_field, str_val, STR_VAR_LEN_MAX);
434+
#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
435+
if ((unsigned long)str_val < TASK_SIZE)
436+
ret = strncpy_from_user_nofault(str_field, str_val, STR_VAR_LEN_MAX);
437+
else
438+
#endif
439+
ret = strncpy_from_kernel_nofault(str_field, str_val, STR_VAR_LEN_MAX);
440+
441+
if (ret < 0)
442+
strcpy(str_field, FAULT_STRING);
443+
433444
(*n_u64) += STR_VAR_LEN_MAX / sizeof(u64);
434445
}
435446

@@ -462,7 +473,7 @@ static notrace void trace_event_raw_event_synth(void *__data,
462473
val_idx = var_ref_idx[field_pos];
463474
str_val = (char *)(long)var_ref_vals[val_idx];
464475

465-
len = strlen(str_val) + 1;
476+
len = kern_fetch_store_strlen((unsigned long)str_val);
466477

467478
fields_size += len;
468479
}

0 commit comments

Comments
 (0)