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

Merge tag 'trace-fixes-v3.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace

Pull tracing fixes from Steven Rostedt:
"This includes two fixes.

1) is a bug fix that happens when root does the following:

echo function_graph > current_tracer
modprobe foo
echo nop > current_tracer

This causes the ftrace internal accounting to get screwed up and
crashes ftrace, preventing the user from using the function tracer
after that.

2) if a TRACE_EVENT has a string field, and NULL is given for it.

The internal trace event code does a strlen() and strcpy() on the
source of field. If it is NULL it causes the system to oops.

This bug has been there since 2.6.31, but no TRACE_EVENT ever passed
in a NULL to the string field, until now"

* tag 'trace-fixes-v3.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace:
ftrace: Fix function graph with loading of modules
tracing: Allow events to have NULL strings

+38 -31
+3 -2
include/trace/ftrace.h
··· 372 372 __data_size += (len) * sizeof(type); 373 373 374 374 #undef __string 375 - #define __string(item, src) __dynamic_array(char, item, strlen(src) + 1) 375 + #define __string(item, src) __dynamic_array(char, item, \ 376 + strlen((src) ? (const char *)(src) : "(null)") + 1) 376 377 377 378 #undef DECLARE_EVENT_CLASS 378 379 #define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \ ··· 502 501 503 502 #undef __assign_str 504 503 #define __assign_str(dst, src) \ 505 - strcpy(__get_str(dst), src); 504 + strcpy(__get_str(dst), (src) ? (const char *)(src) : "(null)"); 506 505 507 506 #undef TP_fast_assign 508 507 #define TP_fast_assign(args...) args
+35 -29
kernel/trace/ftrace.c
··· 367 367 368 368 static int __register_ftrace_function(struct ftrace_ops *ops) 369 369 { 370 - if (unlikely(ftrace_disabled)) 371 - return -ENODEV; 372 - 373 370 if (FTRACE_WARN_ON(ops == &global_ops)) 374 371 return -EINVAL; 375 372 ··· 424 427 static int __unregister_ftrace_function(struct ftrace_ops *ops) 425 428 { 426 429 int ret; 427 - 428 - if (ftrace_disabled) 429 - return -ENODEV; 430 430 431 431 if (WARN_ON(!(ops->flags & FTRACE_OPS_FL_ENABLED))) 432 432 return -EBUSY; ··· 2082 2088 static int ftrace_startup(struct ftrace_ops *ops, int command) 2083 2089 { 2084 2090 bool hash_enable = true; 2091 + int ret; 2085 2092 2086 2093 if (unlikely(ftrace_disabled)) 2087 2094 return -ENODEV; 2095 + 2096 + ret = __register_ftrace_function(ops); 2097 + if (ret) 2098 + return ret; 2088 2099 2089 2100 ftrace_start_up++; 2090 2101 command |= FTRACE_UPDATE_CALLS; ··· 2112 2113 return 0; 2113 2114 } 2114 2115 2115 - static void ftrace_shutdown(struct ftrace_ops *ops, int command) 2116 + static int ftrace_shutdown(struct ftrace_ops *ops, int command) 2116 2117 { 2117 2118 bool hash_disable = true; 2119 + int ret; 2118 2120 2119 2121 if (unlikely(ftrace_disabled)) 2120 - return; 2122 + return -ENODEV; 2123 + 2124 + ret = __unregister_ftrace_function(ops); 2125 + if (ret) 2126 + return ret; 2121 2127 2122 2128 ftrace_start_up--; 2123 2129 /* ··· 2157 2153 } 2158 2154 2159 2155 if (!command || !ftrace_enabled) 2160 - return; 2156 + return 0; 2161 2157 2162 2158 ftrace_run_update_code(command); 2159 + return 0; 2163 2160 } 2164 2161 2165 2162 static void ftrace_startup_sysctl(void) ··· 3065 3060 if (i == FTRACE_FUNC_HASHSIZE) 3066 3061 return; 3067 3062 3068 - ret = __register_ftrace_function(&trace_probe_ops); 3069 - if (!ret) 3070 - ret = ftrace_startup(&trace_probe_ops, 0); 3063 + ret = ftrace_startup(&trace_probe_ops, 0); 3071 3064 3072 3065 ftrace_probe_registered = 1; 3073 3066 } 3074 3067 3075 3068 static void __disable_ftrace_function_probe(void) 3076 3069 { 3077 - int ret; 3078 3070 int i; 3079 3071 3080 3072 if (!ftrace_probe_registered) ··· 3084 3082 } 3085 3083 3086 3084 /* no more funcs left */ 3087 - ret = __unregister_ftrace_function(&trace_probe_ops); 3088 - if (!ret) 3089 - ftrace_shutdown(&trace_probe_ops, 0); 3085 + ftrace_shutdown(&trace_probe_ops, 0); 3090 3086 3091 3087 ftrace_probe_registered = 0; 3092 3088 } ··· 4366 4366 static inline int ftrace_init_dyn_debugfs(struct dentry *d_tracer) { return 0; } 4367 4367 static inline void ftrace_startup_enable(int command) { } 4368 4368 /* Keep as macros so we do not need to define the commands */ 4369 - # define ftrace_startup(ops, command) \ 4370 - ({ \ 4371 - (ops)->flags |= FTRACE_OPS_FL_ENABLED; \ 4372 - 0; \ 4369 + # define ftrace_startup(ops, command) \ 4370 + ({ \ 4371 + int ___ret = __register_ftrace_function(ops); \ 4372 + if (!___ret) \ 4373 + (ops)->flags |= FTRACE_OPS_FL_ENABLED; \ 4374 + ___ret; \ 4373 4375 }) 4374 - # define ftrace_shutdown(ops, command) do { } while (0) 4376 + # define ftrace_shutdown(ops, command) __unregister_ftrace_function(ops) 4377 + 4375 4378 # define ftrace_startup_sysctl() do { } while (0) 4376 4379 # define ftrace_shutdown_sysctl() do { } while (0) 4377 4380 ··· 4783 4780 4784 4781 mutex_lock(&ftrace_lock); 4785 4782 4786 - ret = __register_ftrace_function(ops); 4787 - if (!ret) 4788 - ret = ftrace_startup(ops, 0); 4783 + ret = ftrace_startup(ops, 0); 4789 4784 4790 4785 mutex_unlock(&ftrace_lock); 4791 4786 ··· 4802 4801 int ret; 4803 4802 4804 4803 mutex_lock(&ftrace_lock); 4805 - ret = __unregister_ftrace_function(ops); 4806 - if (!ret) 4807 - ftrace_shutdown(ops, 0); 4804 + ret = ftrace_shutdown(ops, 0); 4808 4805 mutex_unlock(&ftrace_lock); 4809 4806 4810 4807 return ret; ··· 4996 4997 return NOTIFY_DONE; 4997 4998 } 4998 4999 5000 + /* Just a place holder for function graph */ 5001 + static struct ftrace_ops fgraph_ops __read_mostly = { 5002 + .func = ftrace_stub, 5003 + .flags = FTRACE_OPS_FL_STUB | FTRACE_OPS_FL_GLOBAL | 5004 + FTRACE_OPS_FL_RECURSION_SAFE, 5005 + }; 5006 + 4999 5007 int register_ftrace_graph(trace_func_graph_ret_t retfunc, 5000 5008 trace_func_graph_ent_t entryfunc) 5001 5009 { ··· 5029 5023 ftrace_graph_return = retfunc; 5030 5024 ftrace_graph_entry = entryfunc; 5031 5025 5032 - ret = ftrace_startup(&global_ops, FTRACE_START_FUNC_RET); 5026 + ret = ftrace_startup(&fgraph_ops, FTRACE_START_FUNC_RET); 5033 5027 5034 5028 out: 5035 5029 mutex_unlock(&ftrace_lock); ··· 5046 5040 ftrace_graph_active--; 5047 5041 ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub; 5048 5042 ftrace_graph_entry = ftrace_graph_entry_stub; 5049 - ftrace_shutdown(&global_ops, FTRACE_STOP_FUNC_RET); 5043 + ftrace_shutdown(&fgraph_ops, FTRACE_STOP_FUNC_RET); 5050 5044 unregister_pm_notifier(&ftrace_suspend_notifier); 5051 5045 unregister_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL); 5052 5046