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 | return next; | 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 | #define STATIC_TEMP_BUF_SIZE 128 | 3589 | #define STATIC_TEMP_BUF_SIZE 128 |
| 3534 | static char static_temp_buf[STATIC_TEMP_BUF_SIZE] __aligned(4); | 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 | if (iter->temp) | 4378 | if (iter->temp) |
| 4323 | iter->temp_size = 128; | 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 | * We make a copy of the current tracer to avoid concurrent | 4392 | * We make a copy of the current tracer to avoid concurrent |
| 4327 | * changes on it while we are reading. | 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 | mutex_destroy(&iter->mutex); | 4540 | mutex_destroy(&iter->mutex); |
| 4475 | free_cpumask_var(iter->started); | 4541 | free_cpumask_var(iter->started); |
| 4542 | kfree(iter->fmt); | ||
| 4476 | kfree(iter->temp); | 4543 | kfree(iter->temp); |
| 4477 | kfree(iter->trace); | 4544 | kfree(iter->trace); |
| 4478 | kfree(iter->buffer_iter); | 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 | /* Simulate the iterator */ | 9399 | /* Simulate the iterator */ |
| 9333 | trace_init_global_iter(&iter); | 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 | iter.temp = static_temp_buf; | 9402 | iter.temp = static_temp_buf; |
| 9336 | iter.temp_size = STATIC_TEMP_BUF_SIZE; | 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 | for_each_tracing_cpu(cpu) { | 9407 | for_each_tracing_cpu(cpu) { |
| 9339 | atomic_inc(&per_cpu_ptr(iter.array_buffer->data, cpu)->disabled); | 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 | void trace_buffer_unlock_commit_nostack(struct trace_buffer *buffer, | 581 | void trace_buffer_unlock_commit_nostack(struct trace_buffer *buffer, |
| 582 | struct ring_buffer_event *event); | 582 | struct ring_buffer_event *event); |
| 583 | 583 | ||
| 584 | const char *trace_event_format(struct trace_iterator *iter, const char *fmt); | ||
| 585 | |||
| 584 | int trace_empty(struct trace_iterator *iter); | 586 | int trace_empty(struct trace_iterator *iter); |
| 585 | 587 | ||
| 586 | void *trace_find_next_entry_inc(struct trace_iterator *iter); | 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 | EXPORT_SYMBOL(trace_raw_output_prep); | 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 | static int trace_output_raw(struct trace_iterator *iter, char *name, | 325 | static int trace_output_raw(struct trace_iterator *iter, char *name, |
| 316 | char *fmt, va_list ap) | 326 | char *fmt, va_list ap) |
| 317 | { | 327 | { |
| 318 | struct trace_seq *s = &iter->seq; | 328 | struct trace_seq *s = &iter->seq; |
| 319 | 329 | ||
| 320 | trace_seq_printf(s, "%s: ", name); | 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 | return trace_handle_return(s); | 333 | return trace_handle_return(s); |
| 324 | } | 334 | } |