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

Merge tag 'trace-v6.0-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace

Pull tracing fixes from Steven Rostedt:
"Various fixes for tracing:

- Fix a return value of traceprobe_parse_event_name()

- Fix NULL pointer dereference from failed ftrace enabling

- Fix NULL pointer dereference when asking for registers from eprobes

- Make eprobes consistent with kprobes/uprobes, filters and
histograms"

* tag 'trace-v6.0-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace:
tracing: Have filter accept "common_cpu" to be consistent
tracing/probes: Have kprobes and uprobes use $COMM too
tracing/eprobes: Have event probes be consistent with kprobes and uprobes
tracing/eprobes: Fix reading of string fields
tracing/eprobes: Do not hardcode $comm as a string
tracing/eprobes: Do not allow eprobes to use $stack, or % for regs
ftrace: Fix NULL pointer dereference in is_ftrace_trampoline when ftrace is dead
tracing/perf: Fix double put of trace event when init fails
tracing: React to error return from traceprobe_parse_event_name()

+119 -21
+10
kernel/trace/ftrace.c
··· 2974 2974 2975 2975 ftrace_startup_enable(command); 2976 2976 2977 + /* 2978 + * If ftrace is in an undefined state, we just remove ops from list 2979 + * to prevent the NULL pointer, instead of totally rolling it back and 2980 + * free trampoline, because those actions could cause further damage. 2981 + */ 2982 + if (unlikely(ftrace_disabled)) { 2983 + __unregister_ftrace_function(ops); 2984 + return -ENODEV; 2985 + } 2986 + 2977 2987 ops->flags &= ~FTRACE_OPS_FL_ADDING; 2978 2988 2979 2989 return 0;
+86 -7
kernel/trace/trace_eprobe.c
··· 227 227 struct probe_arg *parg = &ep->tp.args[i]; 228 228 struct ftrace_event_field *field; 229 229 struct list_head *head; 230 + int ret = -ENOENT; 230 231 231 232 head = trace_get_fields(ep->event); 232 233 list_for_each_entry(field, head, link) { ··· 237 236 return 0; 238 237 } 239 238 } 239 + 240 + /* 241 + * Argument not found on event. But allow for comm and COMM 242 + * to be used to get the current->comm. 243 + */ 244 + if (strcmp(parg->code->data, "COMM") == 0 || 245 + strcmp(parg->code->data, "comm") == 0) { 246 + parg->code->op = FETCH_OP_COMM; 247 + ret = 0; 248 + } 249 + 240 250 kfree(parg->code->data); 241 251 parg->code->data = NULL; 242 - return -ENOENT; 252 + return ret; 243 253 } 244 254 245 255 static int eprobe_event_define_fields(struct trace_event_call *event_call) ··· 323 311 324 312 addr = rec + field->offset; 325 313 314 + if (is_string_field(field)) { 315 + switch (field->filter_type) { 316 + case FILTER_DYN_STRING: 317 + val = (unsigned long)(rec + (*(unsigned int *)addr & 0xffff)); 318 + break; 319 + case FILTER_RDYN_STRING: 320 + val = (unsigned long)(addr + (*(unsigned int *)addr & 0xffff)); 321 + break; 322 + case FILTER_STATIC_STRING: 323 + val = (unsigned long)addr; 324 + break; 325 + case FILTER_PTR_STRING: 326 + val = (unsigned long)(*(char *)addr); 327 + break; 328 + default: 329 + WARN_ON_ONCE(1); 330 + return 0; 331 + } 332 + return val; 333 + } 334 + 326 335 switch (field->size) { 327 336 case 1: 328 337 if (field->is_signed) ··· 375 342 376 343 static int get_eprobe_size(struct trace_probe *tp, void *rec) 377 344 { 345 + struct fetch_insn *code; 378 346 struct probe_arg *arg; 379 347 int i, len, ret = 0; 380 348 381 349 for (i = 0; i < tp->nr_args; i++) { 382 350 arg = tp->args + i; 383 - if (unlikely(arg->dynamic)) { 351 + if (arg->dynamic) { 384 352 unsigned long val; 385 353 386 - val = get_event_field(arg->code, rec); 387 - len = process_fetch_insn_bottom(arg->code + 1, val, NULL, NULL); 354 + code = arg->code; 355 + retry: 356 + switch (code->op) { 357 + case FETCH_OP_TP_ARG: 358 + val = get_event_field(code, rec); 359 + break; 360 + case FETCH_OP_IMM: 361 + val = code->immediate; 362 + break; 363 + case FETCH_OP_COMM: 364 + val = (unsigned long)current->comm; 365 + break; 366 + case FETCH_OP_DATA: 367 + val = (unsigned long)code->data; 368 + break; 369 + case FETCH_NOP_SYMBOL: /* Ignore a place holder */ 370 + code++; 371 + goto retry; 372 + default: 373 + continue; 374 + } 375 + code++; 376 + len = process_fetch_insn_bottom(code, val, NULL, NULL); 388 377 if (len > 0) 389 378 ret += len; 390 379 } ··· 424 369 { 425 370 unsigned long val; 426 371 427 - val = get_event_field(code, rec); 428 - return process_fetch_insn_bottom(code + 1, val, dest, base); 372 + retry: 373 + switch (code->op) { 374 + case FETCH_OP_TP_ARG: 375 + val = get_event_field(code, rec); 376 + break; 377 + case FETCH_OP_IMM: 378 + val = code->immediate; 379 + break; 380 + case FETCH_OP_COMM: 381 + val = (unsigned long)current->comm; 382 + break; 383 + case FETCH_OP_DATA: 384 + val = (unsigned long)code->data; 385 + break; 386 + case FETCH_NOP_SYMBOL: /* Ignore a place holder */ 387 + code++; 388 + goto retry; 389 + default: 390 + return -EILSEQ; 391 + } 392 + code++; 393 + return process_fetch_insn_bottom(code, val, dest, base); 429 394 } 430 395 NOKPROBE_SYMBOL(process_fetch_insn) 431 396 ··· 920 845 trace_probe_log_err(0, BAD_ATTACH_ARG); 921 846 } 922 847 848 + /* Handle symbols "@" */ 849 + if (!ret) 850 + ret = traceprobe_update_arg(&ep->tp.args[i]); 851 + 923 852 return ret; 924 853 } 925 854 ··· 962 883 trace_probe_log_set_index(1); 963 884 sys_event = argv[1]; 964 885 ret = traceprobe_parse_event_name(&sys_event, &sys_name, buf2, 0); 965 - if (!sys_event || !sys_name) { 886 + if (ret || !sys_event || !sys_name) { 966 887 trace_probe_log_err(0, NO_EVENT_INFO); 967 888 goto parse_error; 968 889 }
+4 -3
kernel/trace/trace_event_perf.c
··· 157 157 int i; 158 158 159 159 if (--tp_event->perf_refcount > 0) 160 - goto out; 160 + return; 161 161 162 162 tp_event->class->reg(tp_event, TRACE_REG_PERF_UNREGISTER, NULL); 163 163 ··· 176 176 perf_trace_buf[i] = NULL; 177 177 } 178 178 } 179 - out: 180 - trace_event_put_ref(tp_event); 181 179 } 182 180 183 181 static int perf_trace_event_open(struct perf_event *p_event) ··· 239 241 mutex_lock(&event_mutex); 240 242 perf_trace_event_close(p_event); 241 243 perf_trace_event_unreg(p_event); 244 + trace_event_put_ref(p_event->tp_event); 242 245 mutex_unlock(&event_mutex); 243 246 } 244 247 ··· 291 292 mutex_lock(&event_mutex); 292 293 perf_trace_event_close(p_event); 293 294 perf_trace_event_unreg(p_event); 295 + trace_event_put_ref(p_event->tp_event); 294 296 mutex_unlock(&event_mutex); 295 297 296 298 destroy_local_trace_kprobe(p_event->tp_event); ··· 347 347 mutex_lock(&event_mutex); 348 348 perf_trace_event_close(p_event); 349 349 perf_trace_event_unreg(p_event); 350 + trace_event_put_ref(p_event->tp_event); 350 351 mutex_unlock(&event_mutex); 351 352 destroy_local_trace_uprobe(p_event->tp_event); 352 353 }
+1
kernel/trace/trace_events.c
··· 176 176 177 177 __generic_field(int, CPU, FILTER_CPU); 178 178 __generic_field(int, cpu, FILTER_CPU); 179 + __generic_field(int, common_cpu, FILTER_CPU); 179 180 __generic_field(char *, COMM, FILTER_COMM); 180 181 __generic_field(char *, comm, FILTER_COMM); 181 182
+18 -11
kernel/trace/trace_probe.c
··· 283 283 int ret = 0; 284 284 int len; 285 285 286 - if (strcmp(arg, "retval") == 0) { 286 + if (flags & TPARG_FL_TPOINT) { 287 + if (code->data) 288 + return -EFAULT; 289 + code->data = kstrdup(arg, GFP_KERNEL); 290 + if (!code->data) 291 + return -ENOMEM; 292 + code->op = FETCH_OP_TP_ARG; 293 + } else if (strcmp(arg, "retval") == 0) { 287 294 if (flags & TPARG_FL_RETURN) { 288 295 code->op = FETCH_OP_RETVAL; 289 296 } else { ··· 314 307 } 315 308 } else 316 309 goto inval_var; 317 - } else if (strcmp(arg, "comm") == 0) { 310 + } else if (strcmp(arg, "comm") == 0 || strcmp(arg, "COMM") == 0) { 318 311 code->op = FETCH_OP_COMM; 319 312 #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API 320 313 } else if (((flags & TPARG_FL_MASK) == ··· 330 323 code->op = FETCH_OP_ARG; 331 324 code->param = (unsigned int)param - 1; 332 325 #endif 333 - } else if (flags & TPARG_FL_TPOINT) { 334 - if (code->data) 335 - return -EFAULT; 336 - code->data = kstrdup(arg, GFP_KERNEL); 337 - if (!code->data) 338 - return -ENOMEM; 339 - code->op = FETCH_OP_TP_ARG; 340 326 } else 341 327 goto inval_var; 342 328 ··· 384 384 break; 385 385 386 386 case '%': /* named register */ 387 + if (flags & TPARG_FL_TPOINT) { 388 + /* eprobes do not handle registers */ 389 + trace_probe_log_err(offs, BAD_VAR); 390 + break; 391 + } 387 392 ret = regs_query_register_offset(arg + 1); 388 393 if (ret >= 0) { 389 394 code->op = FETCH_OP_REG; ··· 622 617 623 618 /* 624 619 * Since $comm and immediate string can not be dereferenced, 625 - * we can find those by strcmp. 620 + * we can find those by strcmp. But ignore for eprobes. 626 621 */ 627 - if (strcmp(arg, "$comm") == 0 || strncmp(arg, "\\\"", 2) == 0) { 622 + if (!(flags & TPARG_FL_TPOINT) && 623 + (strcmp(arg, "$comm") == 0 || strcmp(arg, "$COMM") == 0 || 624 + strncmp(arg, "\\\"", 2) == 0)) { 628 625 /* The type of $comm must be "string", and not an array. */ 629 626 if (parg->count || (t && strcmp(t, "string"))) 630 627 goto out;