To help debugging kernel, show real address for trace event arguments in tracefs/trace{,pipe} instead of hashed pointer value. Since ftrace human-readable format uses vsprintf(), all %p are translated to hash values instead of pointer address. However, when debugging the kernel, raw address value gives a hint when comparing with the memory mapping in the kernel. (Those are sometimes used with crash log, which is not hashed too) So converting %p with %px when calling trace_seq_printf(). Moreover, this is not improving the security because the tracefs can be used only by root user and the raw address values are readable from tracefs/percpu/cpu*/trace_pipe_raw file. Link: https://lkml.kernel.org/r/160277370703.29307.5134475491761971203.stgit@devnote2
Showing the changes to kernel/trace (3 of 5 files). Show all
Unified · Split
| @@ -3530,6 +3530,62 @@ __find_next_entry(struct trace_iterator *iter, int *ent_cpu, · 3529 unmodified lines | ||
| 3530 | 3530 | return next; |
| 3531 | 3531 | } |
| 3532 | 3532 | |
| 3533 | +#define STATIC_FMT_BUF_SIZE 128 | |
| 3534 | +static char static_fmt_buf[STATIC_FMT_BUF_SIZE]; | |
| 3535 | + | |
| 3536 | +static char *trace_iter_expand_format(struct trace_iterator *iter) | |
| 3537 | +{ | |
| 3538 | + char *tmp; | |
| 3539 | + | |
| 3540 | + if (iter->fmt == static_fmt_buf) | |
| 3541 | + return NULL; | |
| 3542 | + | |
| 3543 | + tmp = krealloc(iter->fmt, iter->fmt_size + STATIC_FMT_BUF_SIZE, | |
| 3544 | + GFP_KERNEL); | |
| 3545 | + if (tmp) { | |
| 3546 | + iter->fmt_size += STATIC_FMT_BUF_SIZE; | |
| 3547 | + iter->fmt = tmp; | |
| 3548 | + } | |
| 3549 | + | |
| 3550 | + return tmp; | |
| 3551 | +} | |
| 3552 | + | |
| 3553 | +const char *trace_event_format(struct trace_iterator *iter, const char *fmt) | |
| 3554 | +{ | |
| 3555 | + const char *p, *new_fmt; | |
| 3556 | + char *q; | |
| 3557 | + | |
| 3558 | + if (WARN_ON_ONCE(!fmt)) | |
| 3559 | + return fmt; | |
| 3560 | + | |
| 3561 | + p = fmt; | |
| 3562 | + new_fmt = q = iter->fmt; | |
| 3563 | + while (*p) { | |
| 3564 | + if (unlikely(q - new_fmt + 3 > iter->fmt_size)) { | |
| 3565 | + if (!trace_iter_expand_format(iter)) | |
| 3566 | + return fmt; | |
| 3567 | + | |
| 3568 | + q += iter->fmt - new_fmt; | |
| 3569 | + new_fmt = iter->fmt; | |
| 3570 | + } | |
| 3571 | + | |
| 3572 | + *q++ = *p++; | |
| 3573 | + | |
| 3574 | + /* Replace %p with %px */ | |
| 3575 | + if (p[-1] == '%') { | |
| 3576 | + if (p[0] == '%') { | |
| 3577 | + *q++ = *p++; | |
| 3578 | + } else if (p[0] == 'p' && !isalnum(p[1])) { | |
| 3579 | + *q++ = *p++; | |
| 3580 | + *q++ = 'x'; | |
| 3581 | + } | |
| 3582 | + } | |
| 3583 | + } | |
| 3584 | + *q = '\0'; | |
| 3585 | + | |
| 3586 | + return new_fmt; | |
| 3587 | +} | |
| 3588 | + | |
| 3533 | 3589 | #define STATIC_TEMP_BUF_SIZE 128 |
| 3534 | 3590 | static char static_temp_buf[STATIC_TEMP_BUF_SIZE] __aligned(4); |
| 3535 | 3591 | |
| @@ -4322,6 +4378,16 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot) · 786 unmodified lines | ||
| 4322 | 4378 | if (iter->temp) |
| 4323 | 4379 | iter->temp_size = 128; |
| 4324 | 4380 | |
| 4381 | + /* | |
| 4382 | + * trace_event_printf() may need to modify given format | |
| 4383 | + * string to replace %p with %px so that it shows real address | |
| 4384 | + * instead of hash value. However, that is only for the event | |
| 4385 | + * tracing, other tracer may not need. Defer the allocation | |
| 4386 | + * until it is needed. | |
| 4387 | + */ | |
| 4388 | + iter->fmt = NULL; | |
| 4389 | + iter->fmt_size = 0; | |
| 4390 | + | |
| 4325 | 4391 | /* |
| 4326 | 4392 | * We make a copy of the current tracer to avoid concurrent |
| 4327 | 4393 | * changes on it while we are reading. |
| @@ -4473,6 +4539,7 @@ static int tracing_release(struct inode *inode, struct file *file) · 145 unmodified lines | ||
| 4473 | 4539 | |
| 4474 | 4540 | mutex_destroy(&iter->mutex); |
| 4475 | 4541 | free_cpumask_var(iter->started); |
| 4542 | + kfree(iter->fmt); | |
| 4476 | 4543 | kfree(iter->temp); |
| 4477 | 4544 | kfree(iter->trace); |
| 4478 | 4545 | kfree(iter->buffer_iter); |
| @@ -9331,9 +9398,11 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) · 4852 unmodified lines | ||
| 9331 | 9398 | |
| 9332 | 9399 | /* Simulate the iterator */ |
| 9333 | 9400 | trace_init_global_iter(&iter); |
| 9334 | − /* Can not use kmalloc for iter.temp */ | |
| 9401 | + /* Can not use kmalloc for iter.temp and iter.fmt */ | |
| 9335 | 9402 | iter.temp = static_temp_buf; |
| 9336 | 9403 | iter.temp_size = STATIC_TEMP_BUF_SIZE; |
| 9404 | + iter.fmt = static_fmt_buf; | |
| 9405 | + iter.fmt_size = STATIC_FMT_BUF_SIZE; | |
| 9337 | 9406 | |
| 9338 | 9407 | for_each_tracing_cpu(cpu) { |
| 9339 | 9408 | atomic_inc(&per_cpu_ptr(iter.array_buffer->data, cpu)->disabled); |
| @@ -581,6 +581,8 @@ struct trace_entry *trace_find_next_entry(struct trace_iterator *iter, · 580 unmodified lines | ||
| 581 | 581 | void trace_buffer_unlock_commit_nostack(struct trace_buffer *buffer, |
| 582 | 582 | struct ring_buffer_event *event); |
| 583 | 583 | |
| 584 | +const char *trace_event_format(struct trace_iterator *iter, const char *fmt); | |
| 585 | + | |
| 584 | 586 | int trace_empty(struct trace_iterator *iter); |
| 585 | 587 | |
| 586 | 588 | void *trace_find_next_entry_inc(struct trace_iterator *iter); |
| @@ -312,13 +312,23 @@ int trace_raw_output_prep(struct trace_iterator *iter, · 311 unmodified lines | ||
| 312 | 312 | } |
| 313 | 313 | EXPORT_SYMBOL(trace_raw_output_prep); |
| 314 | 314 | |
| 315 | +void trace_event_printf(struct trace_iterator *iter, const char *fmt, ...) | |
| 316 | +{ | |
| 317 | + va_list ap; | |
| 318 | + | |
| 319 | + va_start(ap, fmt); | |
| 320 | + trace_seq_vprintf(&iter->seq, trace_event_format(iter, fmt), ap); | |
| 321 | + va_end(ap); | |
| 322 | +} | |
| 323 | +EXPORT_SYMBOL(trace_event_printf); | |
| 324 | + | |
| 315 | 325 | static int trace_output_raw(struct trace_iterator *iter, char *name, |
| 316 | 326 | char *fmt, va_list ap) |
| 317 | 327 | { |
| 318 | 328 | struct trace_seq *s = &iter->seq; |
| 319 | 329 | |
| 320 | 330 | trace_seq_printf(s, "%s: ", name); |
| 321 | − trace_seq_vprintf(s, fmt, ap); | |
| 331 | + trace_seq_vprintf(s, trace_event_format(iter, fmt), ap); | |
| 322 | 332 | |
| 323 | 333 | return trace_handle_return(s); |
| 324 | 334 | } |