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()
Unified · Split
| @@ -2974,6 +2974,16 @@ int ftrace_startup(struct ftrace_ops *ops, int command) · 2973 unmodified lines | ||
| 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; |
| @@ -227,6 +227,7 @@ static int trace_eprobe_tp_arg_update(struct trace_eprobe *ep, int i) · 226 unmodified lines | ||
| 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) { |
| @@ -236,9 +237,20 @@ static int trace_eprobe_tp_arg_update(struct trace_eprobe *ep, int i) · 3 unmodified lines | ||
| 236 | 237 | return 0; |
| 237 | 238 | } |
| 238 | 239 | } |
| 240 | + | |
| 241 | + /* | |
| 242 | + * Argument not found on event. But allow for comm and COMM | |
| 243 | + * to be used to get the current->comm. | |
| 244 | + */ | |
| 245 | + if (strcmp(parg->code->data, "COMM") == 0 || | |
| 246 | + strcmp(parg->code->data, "comm") == 0) { | |
| 247 | + parg->code->op = FETCH_OP_COMM; | |
| 248 | + ret = 0; | |
| 249 | + } | |
| 250 | + | |
| 239 | 251 | kfree(parg->code->data); |
| 240 | 252 | parg->code->data = NULL; |
| 241 | − return -ENOENT; | |
| 253 | + return ret; | |
| 242 | 254 | } |
| 243 | 255 | |
| 244 | 256 | static int eprobe_event_define_fields(struct trace_event_call *event_call) |
| @@ -311,6 +323,27 @@ static unsigned long get_event_field(struct fetch_insn *code, void *rec) · 66 unmodified lines | ||
| 311 | 323 | |
| 312 | 324 | addr = rec + field->offset; |
| 313 | 325 | |
| 326 | + if (is_string_field(field)) { | |
| 327 | + switch (field->filter_type) { | |
| 328 | + case FILTER_DYN_STRING: | |
| 329 | + val = (unsigned long)(rec + (*(unsigned int *)addr & 0xffff)); | |
| 330 | + break; | |
| 331 | + case FILTER_RDYN_STRING: | |
| 332 | + val = (unsigned long)(addr + (*(unsigned int *)addr & 0xffff)); | |
| 333 | + break; | |
| 334 | + case FILTER_STATIC_STRING: | |
| 335 | + val = (unsigned long)addr; | |
| 336 | + break; | |
| 337 | + case FILTER_PTR_STRING: | |
| 338 | + val = (unsigned long)(*(char *)addr); | |
| 339 | + break; | |
| 340 | + default: | |
| 341 | + WARN_ON_ONCE(1); | |
| 342 | + return 0; | |
| 343 | + } | |
| 344 | + return val; | |
| 345 | + } | |
| 346 | + | |
| 314 | 347 | switch (field->size) { |
| 315 | 348 | case 1: |
| 316 | 349 | if (field->is_signed) |
| @@ -342,16 +375,38 @@ static unsigned long get_event_field(struct fetch_insn *code, void *rec) · 25 unmodified lines | ||
| 342 | 375 | |
| 343 | 376 | static int get_eprobe_size(struct trace_probe *tp, void *rec) |
| 344 | 377 | { |
| 378 | + struct fetch_insn *code; | |
| 345 | 379 | struct probe_arg *arg; |
| 346 | 380 | int i, len, ret = 0; |
| 347 | 381 | |
| 348 | 382 | for (i = 0; i < tp->nr_args; i++) { |
| 349 | 383 | arg = tp->args + i; |
| 350 | − if (unlikely(arg->dynamic)) { | |
| 384 | + if (arg->dynamic) { | |
| 351 | 385 | unsigned long val; |
| 352 | 386 | |
| 353 | − val = get_event_field(arg->code, rec); | |
| 354 | − len = process_fetch_insn_bottom(arg->code + 1, val, NULL, NULL); | |
| 387 | + code = arg->code; | |
| 388 | + retry: | |
| 389 | + switch (code->op) { | |
| 390 | + case FETCH_OP_TP_ARG: | |
| 391 | + val = get_event_field(code, rec); | |
| 392 | + break; | |
| 393 | + case FETCH_OP_IMM: | |
| 394 | + val = code->immediate; | |
| 395 | + break; | |
| 396 | + case FETCH_OP_COMM: | |
| 397 | + val = (unsigned long)current->comm; | |
| 398 | + break; | |
| 399 | + case FETCH_OP_DATA: | |
| 400 | + val = (unsigned long)code->data; | |
| 401 | + break; | |
| 402 | + case FETCH_NOP_SYMBOL: /* Ignore a place holder */ | |
| 403 | + code++; | |
| 404 | + goto retry; | |
| 405 | + default: | |
| 406 | + continue; | |
| 407 | + } | |
| 408 | + code++; | |
| 409 | + len = process_fetch_insn_bottom(code, val, NULL, NULL); | |
| 355 | 410 | if (len > 0) |
| 356 | 411 | ret += len; |
| 357 | 412 | } |
| @@ -369,8 +424,28 @@ process_fetch_insn(struct fetch_insn *code, void *rec, void *dest, · 11 unmodified lines | ||
| 369 | 424 | { |
| 370 | 425 | unsigned long val; |
| 371 | 426 | |
| 372 | − val = get_event_field(code, rec); | |
| 373 | − return process_fetch_insn_bottom(code + 1, val, dest, base); | |
| 427 | + retry: | |
| 428 | + switch (code->op) { | |
| 429 | + case FETCH_OP_TP_ARG: | |
| 430 | + val = get_event_field(code, rec); | |
| 431 | + break; | |
| 432 | + case FETCH_OP_IMM: | |
| 433 | + val = code->immediate; | |
| 434 | + break; | |
| 435 | + case FETCH_OP_COMM: | |
| 436 | + val = (unsigned long)current->comm; | |
| 437 | + break; | |
| 438 | + case FETCH_OP_DATA: | |
| 439 | + val = (unsigned long)code->data; | |
| 440 | + break; | |
| 441 | + case FETCH_NOP_SYMBOL: /* Ignore a place holder */ | |
| 442 | + code++; | |
| 443 | + goto retry; | |
| 444 | + default: | |
| 445 | + return -EILSEQ; | |
| 446 | + } | |
| 447 | + code++; | |
| 448 | + return process_fetch_insn_bottom(code, val, dest, base); | |
| 374 | 449 | } |
| 375 | 450 | NOKPROBE_SYMBOL(process_fetch_insn) |
| 376 | 451 | |
| @@ -845,6 +920,10 @@ static int trace_eprobe_tp_update_arg(struct trace_eprobe *ep, const char *argv[ · 468 unmodified lines | ||
| 845 | 920 | trace_probe_log_err(0, BAD_ATTACH_ARG); |
| 846 | 921 | } |
| 847 | 922 | |
| 923 | + /* Handle symbols "@" */ | |
| 924 | + if (!ret) | |
| 925 | + ret = traceprobe_update_arg(&ep->tp.args[i]); | |
| 926 | + | |
| 848 | 927 | return ret; |
| 849 | 928 | } |
| 850 | 929 | |
| @@ -883,7 +962,7 @@ static int __trace_eprobe_create(int argc, const char *argv[]) · 32 unmodified lines | ||
| 883 | 962 | trace_probe_log_set_index(1); |
| 884 | 963 | sys_event = argv[1]; |
| 885 | 964 | ret = traceprobe_parse_event_name(&sys_event, &sys_name, buf2, 0); |
| 886 | − if (!sys_event || !sys_name) { | |
| 965 | + if (ret || !sys_event || !sys_name) { | |
| 887 | 966 | trace_probe_log_err(0, NO_EVENT_INFO); |
| 888 | 967 | goto parse_error; |
| 889 | 968 | } |
| @@ -157,7 +157,7 @@ static void perf_trace_event_unreg(struct perf_event *p_event) · 156 unmodified lines | ||
| 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,8 +176,6 @@ static void perf_trace_event_unreg(struct perf_event *p_event) · 12 unmodified lines | ||
| 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) |
| @@ -241,6 +239,7 @@ void perf_trace_destroy(struct perf_event *p_event) · 57 unmodified lines | ||
| 241 | 239 | mutex_lock(&event_mutex); |
| 242 | 240 | perf_trace_event_close(p_event); |
| 243 | 241 | perf_trace_event_unreg(p_event); |
| 242 | + trace_event_put_ref(p_event->tp_event); | |
| 244 | 243 | mutex_unlock(&event_mutex); |
| 245 | 244 | } |
| 246 | 245 | |
| @@ -292,6 +291,7 @@ void perf_kprobe_destroy(struct perf_event *p_event) · 45 unmodified lines | ||
| 292 | 291 | mutex_lock(&event_mutex); |
| 293 | 292 | perf_trace_event_close(p_event); |
| 294 | 293 | perf_trace_event_unreg(p_event); |
| 294 | + trace_event_put_ref(p_event->tp_event); | |
| 295 | 295 | mutex_unlock(&event_mutex); |
| 296 | 296 | |
| 297 | 297 | destroy_local_trace_kprobe(p_event->tp_event); |
| @@ -347,6 +347,7 @@ void perf_uprobe_destroy(struct perf_event *p_event) · 49 unmodified lines | ||
| 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 | } |
| @@ -176,6 +176,7 @@ static int trace_define_generic_fields(void) · 175 unmodified lines | ||
| 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 | |
| @@ -283,7 +283,14 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t, · 282 unmodified lines | ||
| 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 { |
| @@ -307,7 +314,7 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t, · 17 unmodified lines | ||
| 307 | 314 | } |
| 308 | 315 | } else |
| 309 | 316 | goto inval_var; |
| 310 | − } else if (strcmp(arg, "comm") == 0) { | |
| 317 | + } else if (strcmp(arg, "comm") == 0 || strcmp(arg, "COMM") == 0) { | |
| 311 | 318 | code->op = FETCH_OP_COMM; |
| 312 | 319 | #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API |
| 313 | 320 | } else if (((flags & TPARG_FL_MASK) == |
| @@ -323,13 +330,6 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t, · 9 unmodified lines | ||
| 323 | 330 | code->op = FETCH_OP_ARG; |
| 324 | 331 | code->param = (unsigned int)param - 1; |
| 325 | 332 | #endif |
| 326 | − } else if (flags & TPARG_FL_TPOINT) { | |
| 327 | − if (code->data) | |
| 328 | − return -EFAULT; | |
| 329 | − code->data = kstrdup(arg, GFP_KERNEL); | |
| 330 | − if (!code->data) | |
| 331 | − return -ENOMEM; | |
| 332 | − code->op = FETCH_OP_TP_ARG; | |
| 333 | 333 | } else |
| 334 | 334 | goto inval_var; |
| 335 | 335 | |
| @@ -384,6 +384,11 @@ parse_probe_arg(char *arg, const struct fetch_type *type, · 48 unmodified lines | ||
| 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; |
| @@ -617,9 +622,11 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size, · 227 unmodified lines | ||
| 617 | 622 | |
| 618 | 623 | /* |
| 619 | 624 | * Since $comm and immediate string can not be dereferenced, |
| 620 | − * we can find those by strcmp. | |
| 625 | + * we can find those by strcmp. But ignore for eprobes. | |
| 621 | 626 | */ |
| 622 | − if (strcmp(arg, "$comm") == 0 || strncmp(arg, "\\\"", 2) == 0) { | |
| 627 | + if (!(flags & TPARG_FL_TPOINT) && | |
| 628 | + (strcmp(arg, "$comm") == 0 || strcmp(arg, "$COMM") == 0 || | |
| 629 | + strncmp(arg, "\\\"", 2) == 0)) { | |
| 623 | 630 | /* The type of $comm must be "string", and not an array. */ |
| 624 | 631 | if (parg->count || (t && strcmp(t, "string"))) |
| 625 | 632 | goto out; |