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 | ftrace_startup_enable(command); | 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 | ops->flags &= ~FTRACE_OPS_FL_ADDING; | 2987 | ops->flags &= ~FTRACE_OPS_FL_ADDING; |
| 2978 | 2988 | ||
| 2979 | return 0; | 2989 | return 0; |
| @@ -227,6 +227,7 @@ static int trace_eprobe_tp_arg_update(struct trace_eprobe *ep, int i) · 226 unmodified lines | |||
| 227 | struct probe_arg *parg = &ep->tp.args[i]; | 227 | struct probe_arg *parg = &ep->tp.args[i]; |
| 228 | struct ftrace_event_field *field; | 228 | struct ftrace_event_field *field; |
| 229 | struct list_head *head; | 229 | struct list_head *head; |
| 230 | int ret = -ENOENT; | ||
| 230 | 231 | ||
| 231 | head = trace_get_fields(ep->event); | 232 | head = trace_get_fields(ep->event); |
| 232 | list_for_each_entry(field, head, link) { | 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 | return 0; | 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 | kfree(parg->code->data); | 251 | kfree(parg->code->data); |
| 240 | parg->code->data = NULL; | 252 | parg->code->data = NULL; |
| 241 | return -ENOENT; | 253 | return ret; |
| 242 | } | 254 | } |
| 243 | 255 | ||
| 244 | static int eprobe_event_define_fields(struct trace_event_call *event_call) | 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 | addr = rec + field->offset; | 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 | switch (field->size) { | 347 | switch (field->size) { |
| 315 | case 1: | 348 | case 1: |
| 316 | if (field->is_signed) | 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 | static int get_eprobe_size(struct trace_probe *tp, void *rec) | 376 | static int get_eprobe_size(struct trace_probe *tp, void *rec) |
| 344 | { | 377 | { |
| 378 | struct fetch_insn *code; | ||
| 345 | struct probe_arg *arg; | 379 | struct probe_arg *arg; |
| 346 | int i, len, ret = 0; | 380 | int i, len, ret = 0; |
| 347 | 381 | ||
| 348 | for (i = 0; i < tp->nr_args; i++) { | 382 | for (i = 0; i < tp->nr_args; i++) { |
| 349 | arg = tp->args + i; | 383 | arg = tp->args + i; |
| 350 | if (unlikely(arg->dynamic)) { | 384 | if (arg->dynamic) { |
| 351 | unsigned long val; | 385 | unsigned long val; |
| 352 | 386 | ||
| 353 | val = get_event_field(arg->code, rec); | 387 | code = arg->code; |
| 354 | len = process_fetch_insn_bottom(arg->code + 1, val, NULL, NULL); | 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 | if (len > 0) | 410 | if (len > 0) |
| 356 | ret += len; | 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 | unsigned long val; | 425 | unsigned long val; |
| 371 | 426 | ||
| 372 | val = get_event_field(code, rec); | 427 | retry: |
| 373 | return process_fetch_insn_bottom(code + 1, val, dest, base); | 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 | NOKPROBE_SYMBOL(process_fetch_insn) | 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 | trace_probe_log_err(0, BAD_ATTACH_ARG); | 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 | return ret; | 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 | trace_probe_log_set_index(1); | 962 | trace_probe_log_set_index(1); |
| 884 | sys_event = argv[1]; | 963 | sys_event = argv[1]; |
| 885 | ret = traceprobe_parse_event_name(&sys_event, &sys_name, buf2, 0); | 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 | trace_probe_log_err(0, NO_EVENT_INFO); | 966 | trace_probe_log_err(0, NO_EVENT_INFO); |
| 888 | goto parse_error; | 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 | int i; | 157 | int i; |
| 158 | 158 | ||
| 159 | if (--tp_event->perf_refcount > 0) | 159 | if (--tp_event->perf_refcount > 0) |
| 160 | goto out; | 160 | return; |
| 161 | 161 | ||
| 162 | tp_event->class->reg(tp_event, TRACE_REG_PERF_UNREGISTER, NULL); | 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 | perf_trace_buf[i] = NULL; | 176 | perf_trace_buf[i] = NULL; |
| 177 | } | 177 | } |
| 178 | } | 178 | } |
| 179 | out: | ||
| 180 | trace_event_put_ref(tp_event); | ||
| 181 | } | 179 | } |
| 182 | 180 | ||
| 183 | static int perf_trace_event_open(struct perf_event *p_event) | 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 | mutex_lock(&event_mutex); | 239 | mutex_lock(&event_mutex); |
| 242 | perf_trace_event_close(p_event); | 240 | perf_trace_event_close(p_event); |
| 243 | perf_trace_event_unreg(p_event); | 241 | perf_trace_event_unreg(p_event); |
| 242 | trace_event_put_ref(p_event->tp_event); | ||
| 244 | mutex_unlock(&event_mutex); | 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 | mutex_lock(&event_mutex); | 291 | mutex_lock(&event_mutex); |
| 293 | perf_trace_event_close(p_event); | 292 | perf_trace_event_close(p_event); |
| 294 | perf_trace_event_unreg(p_event); | 293 | perf_trace_event_unreg(p_event); |
| 294 | trace_event_put_ref(p_event->tp_event); | ||
| 295 | mutex_unlock(&event_mutex); | 295 | mutex_unlock(&event_mutex); |
| 296 | 296 | ||
| 297 | destroy_local_trace_kprobe(p_event->tp_event); | 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 | mutex_lock(&event_mutex); | 347 | mutex_lock(&event_mutex); |
| 348 | perf_trace_event_close(p_event); | 348 | perf_trace_event_close(p_event); |
| 349 | perf_trace_event_unreg(p_event); | 349 | perf_trace_event_unreg(p_event); |
| 350 | trace_event_put_ref(p_event->tp_event); | ||
| 350 | mutex_unlock(&event_mutex); | 351 | mutex_unlock(&event_mutex); |
| 351 | destroy_local_trace_uprobe(p_event->tp_event); | 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 | __generic_field(int, CPU, FILTER_CPU); | 177 | __generic_field(int, CPU, FILTER_CPU); |
| 178 | __generic_field(int, cpu, FILTER_CPU); | 178 | __generic_field(int, cpu, FILTER_CPU); |
| 179 | __generic_field(int, common_cpu, FILTER_CPU); | ||
| 179 | __generic_field(char *, COMM, FILTER_COMM); | 180 | __generic_field(char *, COMM, FILTER_COMM); |
| 180 | __generic_field(char *, comm, FILTER_COMM); | 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 | int ret = 0; | 283 | int ret = 0; |
| 284 | int len; | 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 | if (flags & TPARG_FL_RETURN) { | 294 | if (flags & TPARG_FL_RETURN) { |
| 288 | code->op = FETCH_OP_RETVAL; | 295 | code->op = FETCH_OP_RETVAL; |
| 289 | } else { | 296 | } else { |
| @@ -307,7 +314,7 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t, · 17 unmodified lines | |||
| 307 | } | 314 | } |
| 308 | } else | 315 | } else |
| 309 | goto inval_var; | 316 | goto inval_var; |
| 310 | } else if (strcmp(arg, "comm") == 0) { | 317 | } else if (strcmp(arg, "comm") == 0 || strcmp(arg, "COMM") == 0) { |
| 311 | code->op = FETCH_OP_COMM; | 318 | code->op = FETCH_OP_COMM; |
| 312 | #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API | 319 | #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API |
| 313 | } else if (((flags & TPARG_FL_MASK) == | 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 | code->op = FETCH_OP_ARG; | 330 | code->op = FETCH_OP_ARG; |
| 324 | code->param = (unsigned int)param - 1; | 331 | code->param = (unsigned int)param - 1; |
| 325 | #endif | 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 | } else | 333 | } else |
| 334 | goto inval_var; | 334 | goto inval_var; |
| 335 | 335 | ||
| @@ -384,6 +384,11 @@ parse_probe_arg(char *arg, const struct fetch_type *type, · 48 unmodified lines | |||
| 384 | break; | 384 | break; |
| 385 | 385 | ||
| 386 | case '%': /* named register */ | 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 | ret = regs_query_register_offset(arg + 1); | 392 | ret = regs_query_register_offset(arg + 1); |
| 388 | if (ret >= 0) { | 393 | if (ret >= 0) { |
| 389 | code->op = FETCH_OP_REG; | 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 | * Since $comm and immediate string can not be dereferenced, | 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 | /* The type of $comm must be "string", and not an array. */ | 630 | /* The type of $comm must be "string", and not an array. */ |
| 624 | if (parg->count || (t && strcmp(t, "string"))) | 631 | if (parg->count || (t && strcmp(t, "string"))) |
| 625 | goto out; | 632 | goto out; |