Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'trace-fixes-v4.0-rc2-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace

Pull seq-buf/ftrace fixes from Steven Rostedt:
"This includes fixes for seq_buf_bprintf() truncation issue. It also
contains fixes to ftrace when /proc/sys/kernel/ftrace_enabled and
function tracing are started. Doing the following causes some issues:

# echo 0 > /proc/sys/kernel/ftrace_enabled
# echo function_graph > /sys/kernel/debug/tracing/current_tracer
# echo 1 > /proc/sys/kernel/ftrace_enabled
# echo nop > /sys/kernel/debug/tracing/current_tracer
# echo function_graph > /sys/kernel/debug/tracing/current_tracer

As well as with function tracing too. Pratyush Anand first reported
this issue to me and supplied a patch. When I tested this on my x86
test box, it caused thousands of backtraces and warnings to appear in
dmesg, which also caused a denial of service (a warning for every
function that was listed). I applied Pratyush's patch but it did not
fix the issue for me. I looked into it and found a slight problem
with trampoline accounting. I fixed it and sent Pratyush a patch, but
he said that it did not fix the issue for him.

I later learned tha Pratyush was using an ARM64 server, and when I
tested on my ARM board, I was able to reproduce the same issue as
Pratyush. After applying his patch, it fixed the problem. The above
test uncovered two different bugs, one in x86 and one in ARM and
ARM64. As this looked like it would affect PowerPC, I tested it on my
PPC64 box. It too broke, but neither the patch that fixed ARM or x86
fixed this box (the changes were all in generic code!). The above
test, uncovered two more bugs that affected PowerPC. Again, the
changes were only done to generic code. It's the way the arch code
expected things to be done that was different between the archs. Some
where more sensitive than others.

The rest of this series fixes the PPC bugs as well"

* tag 'trace-fixes-v4.0-rc2-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace:
ftrace: Fix ftrace enable ordering of sysctl ftrace_enabled
ftrace: Fix en(dis)able graph caller when en(dis)abling record via sysctl
ftrace: Clear REGS_EN and TRAMP_EN flags on disabling record via sysctl
seq_buf: Fix seq_buf_bprintf() truncation
seq_buf: Fix seq_buf_vprintf() truncation

+32 -12
+30 -10
kernel/trace/ftrace.c
··· 1059 1059 1060 1060 static struct pid * const ftrace_swapper_pid = &init_struct_pid; 1061 1061 1062 + #ifdef CONFIG_FUNCTION_GRAPH_TRACER 1063 + static int ftrace_graph_active; 1064 + #else 1065 + # define ftrace_graph_active 0 1066 + #endif 1067 + 1062 1068 #ifdef CONFIG_DYNAMIC_FTRACE 1063 1069 1064 1070 static struct ftrace_ops *removed_ops; ··· 2047 2041 if (!ftrace_rec_count(rec)) 2048 2042 rec->flags = 0; 2049 2043 else 2050 - /* Just disable the record (keep REGS state) */ 2051 - rec->flags &= ~FTRACE_FL_ENABLED; 2044 + /* 2045 + * Just disable the record, but keep the ops TRAMP 2046 + * and REGS states. The _EN flags must be disabled though. 2047 + */ 2048 + rec->flags &= ~(FTRACE_FL_ENABLED | FTRACE_FL_TRAMP_EN | 2049 + FTRACE_FL_REGS_EN); 2052 2050 } 2053 2051 2054 2052 return FTRACE_UPDATE_MAKE_NOP; ··· 2698 2688 2699 2689 static void ftrace_startup_sysctl(void) 2700 2690 { 2691 + int command; 2692 + 2701 2693 if (unlikely(ftrace_disabled)) 2702 2694 return; 2703 2695 2704 2696 /* Force update next time */ 2705 2697 saved_ftrace_func = NULL; 2706 2698 /* ftrace_start_up is true if we want ftrace running */ 2707 - if (ftrace_start_up) 2708 - ftrace_run_update_code(FTRACE_UPDATE_CALLS); 2699 + if (ftrace_start_up) { 2700 + command = FTRACE_UPDATE_CALLS; 2701 + if (ftrace_graph_active) 2702 + command |= FTRACE_START_FUNC_RET; 2703 + ftrace_startup_enable(command); 2704 + } 2709 2705 } 2710 2706 2711 2707 static void ftrace_shutdown_sysctl(void) 2712 2708 { 2709 + int command; 2710 + 2713 2711 if (unlikely(ftrace_disabled)) 2714 2712 return; 2715 2713 2716 2714 /* ftrace_start_up is true if ftrace is running */ 2717 - if (ftrace_start_up) 2718 - ftrace_run_update_code(FTRACE_DISABLE_CALLS); 2715 + if (ftrace_start_up) { 2716 + command = FTRACE_DISABLE_CALLS; 2717 + if (ftrace_graph_active) 2718 + command |= FTRACE_STOP_FUNC_RET; 2719 + ftrace_run_update_code(command); 2720 + } 2719 2721 } 2720 2722 2721 2723 static cycle_t ftrace_update_time; ··· 5580 5558 5581 5559 if (ftrace_enabled) { 5582 5560 5583 - ftrace_startup_sysctl(); 5584 - 5585 5561 /* we are starting ftrace again */ 5586 5562 if (ftrace_ops_list != &ftrace_list_end) 5587 5563 update_ftrace_function(); 5564 + 5565 + ftrace_startup_sysctl(); 5588 5566 5589 5567 } else { 5590 5568 /* stopping ftrace calls (just send to ftrace_stub) */ ··· 5611 5589 #endif 5612 5590 ASSIGN_OPS_HASH(graph_ops, &global_ops.local_hash) 5613 5591 }; 5614 - 5615 - static int ftrace_graph_active; 5616 5592 5617 5593 int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace) 5618 5594 {
+2 -2
lib/seq_buf.c
··· 61 61 62 62 if (s->len < s->size) { 63 63 len = vsnprintf(s->buffer + s->len, s->size - s->len, fmt, args); 64 - if (seq_buf_can_fit(s, len)) { 64 + if (s->len + len < s->size) { 65 65 s->len += len; 66 66 return 0; 67 67 } ··· 118 118 119 119 if (s->len < s->size) { 120 120 ret = bstr_printf(s->buffer + s->len, len, fmt, binary); 121 - if (seq_buf_can_fit(s, ret)) { 121 + if (s->len + ret < s->size) { 122 122 s->len += ret; 123 123 return 0; 124 124 }