Pull probes updates from Masami Hiramatsu: - BTF support for dereferencing pointers Add syntax to the parsing of eprobes to typecast structure pointer trace event fields, enabling BTF-based dereferencing instead of relying on manual offsets. - Improvements and robustness enhancements - Use flexible array for entry fetch code. Store probe entry fetch instructions in the probe_entry_arg allocation via a flexible array member to simplify memory allocation and lifetime management. - Replace BUG_ON with lockdep_assert_held in uprobe_buffer functions Replace BUG_ON() calls with lockdep_assert_held() in uprobe buffer enable/disable paths to prevent kernel crashes and better verify lock ownership. - Ensure the uprobe buffer size is bigger than event size. Add a BUILD_BUG_ON() assertion to guarantee that the per-CPU uprobe working buffer size is always larger than the maximum probe event size. * tag 'probes-v7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: tracing/eprobes: Allow use of BTF names to dereference pointers tracing: Replace BUG_ON with lockdep_assert_held in uprobe_buffer functions tracing: Use flexible array for entry fetch code tracing/probes: Ensure the uprobe buffer size is bigger than event size
Showing the changes to kernel (3 of 4 files). Show all
Unified · Split
| @@ -332,6 +332,23 @@ static int parse_trace_event_arg(char *arg, struct fetch_insn *code, · 331 unmodified lines | ||
| 332 | 332 | return -ENOENT; |
| 333 | 333 | } |
| 334 | 334 | |
| 335 | +static int parse_trace_event(char *arg, struct fetch_insn *code, | |
| 336 | + struct traceprobe_parse_context *ctx) | |
| 337 | +{ | |
| 338 | + int ret; | |
| 339 | + | |
| 340 | + if (code->data) | |
| 341 | + return -EFAULT; | |
| 342 | + ret = parse_trace_event_arg(arg, code, ctx); | |
| 343 | + if (!ret) | |
| 344 | + return 0; | |
| 345 | + if (strcmp(arg, "comm") == 0 || strcmp(arg, "COMM") == 0) { | |
| 346 | + code->op = FETCH_OP_COMM; | |
| 347 | + return 0; | |
| 348 | + } | |
| 349 | + return -EINVAL; | |
| 350 | +} | |
| 351 | + | |
| 335 | 352 | #ifdef CONFIG_PROBE_EVENTS_BTF_ARGS |
| 336 | 353 | |
| 337 | 354 | static u32 btf_type_int(const struct btf_type *t) |
| @@ -376,11 +393,16 @@ static bool btf_type_is_char_array(struct btf *btf, const struct btf_type *type) · 38 unmodified lines | ||
| 376 | 393 | && BTF_INT_BITS(intdata) == 8; |
| 377 | 394 | } |
| 378 | 395 | |
| 396 | +static struct btf *ctx_btf(struct traceprobe_parse_context *ctx) | |
| 397 | +{ | |
| 398 | + return ctx->struct_btf ? : ctx->btf; | |
| 399 | +} | |
| 400 | + | |
| 379 | 401 | static int check_prepare_btf_string_fetch(char *typename, |
| 380 | 402 | struct fetch_insn **pcode, |
| 381 | 403 | struct traceprobe_parse_context *ctx) |
| 382 | 404 | { |
| 383 | − struct btf *btf = ctx->btf; | |
| 405 | + struct btf *btf = ctx_btf(ctx); | |
| 384 | 406 | |
| 385 | 407 | if (!btf || !ctx->last_type) |
| 386 | 408 | return 0; |
| @@ -506,6 +528,15 @@ static int query_btf_context(struct traceprobe_parse_context *ctx) · 119 unmodified lines | ||
| 506 | 528 | return 0; |
| 507 | 529 | } |
| 508 | 530 | |
| 531 | +static void clear_struct_btf(struct traceprobe_parse_context *ctx) | |
| 532 | +{ | |
| 533 | + if (ctx->struct_btf) { | |
| 534 | + btf_put(ctx->struct_btf); | |
| 535 | + ctx->struct_btf = NULL; | |
| 536 | + ctx->last_struct = NULL; | |
| 537 | + } | |
| 538 | +} | |
| 539 | + | |
| 509 | 540 | static void clear_btf_context(struct traceprobe_parse_context *ctx) |
| 510 | 541 | { |
| 511 | 542 | if (ctx->btf) { |
| @@ -554,22 +585,29 @@ static int parse_btf_field(char *fieldname, const struct btf_type *type, · 42 unmodified lines | ||
| 554 | 585 | struct fetch_insn *code = *pcode; |
| 555 | 586 | const struct btf_member *field; |
| 556 | 587 | u32 bitoffs, anon_offs; |
| 588 | + bool is_struct = ctx->struct_btf != NULL; | |
| 589 | + struct btf *btf = ctx_btf(ctx); | |
| 557 | 590 | char *next; |
| 558 | 591 | int is_ptr; |
| 559 | 592 | s32 tid; |
| 560 | 593 | |
| 561 | 594 | do { |
| 562 | − /* Outer loop for solving arrow operator ('->') */ | |
| 563 | − if (BTF_INFO_KIND(type->info) != BTF_KIND_PTR) { | |
| 564 | − trace_probe_log_err(ctx->offset, NO_PTR_STRCT); | |
| 565 | − return -EINVAL; | |
| 566 | − } | |
| 567 | − /* Convert a struct pointer type to a struct type */ | |
| 568 | − type = btf_type_skip_modifiers(ctx->btf, type->type, &tid); | |
| 569 | − if (!type) { | |
| 570 | − trace_probe_log_err(ctx->offset, BAD_BTF_TID); | |
| 571 | − return -EINVAL; | |
| 595 | + if (!is_struct) { | |
| 596 | + /* Outer loop for solving arrow operator ('->') */ | |
| 597 | + if (BTF_INFO_KIND(type->info) != BTF_KIND_PTR) { | |
| 598 | + trace_probe_log_err(ctx->offset, NO_PTR_STRCT); | |
| 599 | + return -EINVAL; | |
| 600 | + } | |
| 601 | + | |
| 602 | + /* Convert a struct pointer type to a struct type */ | |
| 603 | + type = btf_type_skip_modifiers(btf, type->type, &tid); | |
| 604 | + if (!type) { | |
| 605 | + trace_probe_log_err(ctx->offset, BAD_BTF_TID); | |
| 606 | + return -EINVAL; | |
| 607 | + } | |
| 572 | 608 | } |
| 609 | + /* Only the first type can skip being a pointer */ | |
| 610 | + is_struct = false; | |
| 573 | 611 | |
| 574 | 612 | bitoffs = 0; |
| 575 | 613 | do { |
| @@ -580,7 +618,7 @@ static int parse_btf_field(char *fieldname, const struct btf_type *type, · 4 unmodified lines | ||
| 580 | 618 | return is_ptr; |
| 581 | 619 | |
| 582 | 620 | anon_offs = 0; |
| 583 | − field = btf_find_struct_member(ctx->btf, type, fieldname, | |
| 621 | + field = btf_find_struct_member(btf, type, fieldname, | |
| 584 | 622 | &anon_offs); |
| 585 | 623 | if (IS_ERR(field)) { |
| 586 | 624 | trace_probe_log_err(ctx->offset, BAD_BTF_TID); |
| @@ -602,7 +640,7 @@ static int parse_btf_field(char *fieldname, const struct btf_type *type, · 15 unmodified lines | ||
| 602 | 640 | ctx->last_bitsize = 0; |
| 603 | 641 | } |
| 604 | 642 | |
| 605 | − type = btf_type_skip_modifiers(ctx->btf, field->type, &tid); | |
| 643 | + type = btf_type_skip_modifiers(btf, field->type, &tid); | |
| 606 | 644 | if (!type) { |
| 607 | 645 | trace_probe_log_err(ctx->offset, BAD_BTF_TID); |
| 608 | 646 | return -EINVAL; |
| @@ -640,7 +678,7 @@ static int parse_btf_arg(char *varname, · 31 unmodified lines | ||
| 640 | 678 | int i, is_ptr, ret; |
| 641 | 679 | u32 tid; |
| 642 | 680 | |
| 643 | − if (WARN_ON_ONCE(!ctx->funcname)) | |
| 681 | + if (WARN_ON_ONCE(!ctx->funcname && !(ctx->flags & TPARG_FL_TEVENT))) | |
| 644 | 682 | return -EINVAL; |
| 645 | 683 | |
| 646 | 684 | is_ptr = split_next_field(varname, &field, ctx); |
| @@ -653,6 +691,19 @@ static int parse_btf_arg(char *varname, · 6 unmodified lines | ||
| 653 | 691 | return -EOPNOTSUPP; |
| 654 | 692 | } |
| 655 | 693 | |
| 694 | + if (ctx->flags & TPARG_FL_TEVENT) { | |
| 695 | + ret = parse_trace_event(varname, code, ctx); | |
| 696 | + if (ret < 0) { | |
| 697 | + trace_probe_log_err(ctx->offset, BAD_ATTACH_ARG); | |
| 698 | + return ret; | |
| 699 | + } | |
| 700 | + /* TEVENT is only here via a typecast */ | |
| 701 | + if (WARN_ON_ONCE(ctx->struct_btf == NULL)) | |
| 702 | + return -EINVAL; | |
| 703 | + type = ctx->last_struct; | |
| 704 | + goto found_type; | |
| 705 | + } | |
| 706 | + | |
| 656 | 707 | if (ctx->flags & TPARG_FL_RETURN && !strcmp(varname, "$retval")) { |
| 657 | 708 | code->op = FETCH_OP_RETVAL; |
| 658 | 709 | /* Check whether the function return type is not void */ |
| @@ -709,6 +760,7 @@ static int parse_btf_arg(char *varname, · 50 unmodified lines | ||
| 709 | 760 | |
| 710 | 761 | found: |
| 711 | 762 | type = btf_type_skip_modifiers(ctx->btf, tid, &tid); |
| 763 | +found_type: | |
| 712 | 764 | if (!type) { |
| 713 | 765 | trace_probe_log_err(ctx->offset, BAD_BTF_TID); |
| 714 | 766 | return -EINVAL; |
| @@ -727,7 +779,7 @@ found: · 12 unmodified lines | ||
| 727 | 779 | static const struct fetch_type *find_fetch_type_from_btf_type( |
| 728 | 780 | struct traceprobe_parse_context *ctx) |
| 729 | 781 | { |
| 730 | − struct btf *btf = ctx->btf; | |
| 782 | + struct btf *btf = ctx_btf(ctx); | |
| 731 | 783 | const char *typestr = NULL; |
| 732 | 784 | |
| 733 | 785 | if (btf && ctx->last_type) |
| @@ -758,7 +810,67 @@ static int parse_btf_bitfield(struct fetch_insn **pcode, · 24 unmodified lines | ||
| 758 | 810 | return 0; |
| 759 | 811 | } |
| 760 | 812 | |
| 761 | −#else | |
| 813 | +static int query_btf_struct(const char *sname, struct traceprobe_parse_context *ctx) | |
| 814 | +{ | |
| 815 | + struct btf *btf = NULL; | |
| 816 | + int id; | |
| 817 | + | |
| 818 | + /* A struct_btf should only be used by a single argument */ | |
| 819 | + if (WARN_ON_ONCE(ctx->struct_btf)) { | |
| 820 | + btf_put(ctx->struct_btf); | |
| 821 | + ctx->struct_btf = NULL; | |
| 822 | + } | |
| 823 | + | |
| 824 | + id = bpf_find_btf_id(sname, BTF_KIND_STRUCT, &btf); | |
| 825 | + if (id < 0) | |
| 826 | + return id; | |
| 827 | + ctx->struct_btf = btf; | |
| 828 | + ctx->last_struct = btf_type_by_id(ctx->struct_btf, id); | |
| 829 | + return 0; | |
| 830 | +} | |
| 831 | + | |
| 832 | +static int handle_typecast(char *arg, struct fetch_insn **pcode, | |
| 833 | + struct fetch_insn *end, | |
| 834 | + struct traceprobe_parse_context *ctx) | |
| 835 | +{ | |
| 836 | + char *tmp; | |
| 837 | + int ret; | |
| 838 | + | |
| 839 | + /* Currently this only works for eprobes */ | |
| 840 | + if (!(ctx->flags & TPARG_FL_TEVENT)) { | |
| 841 | + trace_probe_log_err(ctx->offset, TYPECAST_NOT_EVENT); | |
| 842 | + return -EINVAL; | |
| 843 | + } | |
| 844 | + | |
| 845 | + tmp = strchr(arg, ')'); | |
| 846 | + if (!tmp) { | |
| 847 | + trace_probe_log_err(ctx->offset + strlen(arg), | |
| 848 | + DEREF_OPEN_BRACE); | |
| 849 | + return -EINVAL; | |
| 850 | + } | |
| 851 | + *tmp = '\0'; | |
| 852 | + ret = query_btf_struct(arg + 1, ctx); | |
| 853 | + *tmp = ')'; | |
| 854 | + | |
| 855 | + if (ret < 0) { | |
| 856 | + trace_probe_log_err(ctx->offset + 1, NO_PTR_STRCT); | |
| 857 | + return -EINVAL; | |
| 858 | + } | |
| 859 | + | |
| 860 | + tmp++; | |
| 861 | + | |
| 862 | + ctx->offset += tmp - arg; | |
| 863 | + ret = parse_btf_arg(tmp, pcode, end, ctx); | |
| 864 | + return ret; | |
| 865 | +} | |
| 866 | + | |
| 867 | +#else /* !CONFIG_PROBE_EVENTS_BTF_ARGS */ | |
| 868 | + | |
| 869 | +static void clear_struct_btf(struct traceprobe_parse_context *ctx) | |
| 870 | +{ | |
| 871 | + ctx->struct_btf = NULL; | |
| 872 | +} | |
| 873 | + | |
| 762 | 874 | static void clear_btf_context(struct traceprobe_parse_context *ctx) |
| 763 | 875 | { |
| 764 | 876 | ctx->btf = NULL; |
| @@ -794,7 +906,15 @@ static int check_prepare_btf_string_fetch(char *typename, · 29 unmodified lines | ||
| 794 | 906 | return 0; |
| 795 | 907 | } |
| 796 | 908 | |
| 797 | −#endif | |
| 909 | +static int handle_typecast(char *arg, struct fetch_insn **pcode, | |
| 910 | + struct fetch_insn *end, | |
| 911 | + struct traceprobe_parse_context *ctx) | |
| 912 | +{ | |
| 913 | + trace_probe_log_err(ctx->offset, NOSUP_BTFARG); | |
| 914 | + return -EOPNOTSUPP; | |
| 915 | +} | |
| 916 | + | |
| 917 | +#endif /* CONFIG_PROBE_EVENTS_BTF_ARGS */ | |
| 798 | 918 | |
| 799 | 919 | #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API |
| 800 | 920 | |
| @@ -838,15 +958,10 @@ static int __store_entry_arg(struct trace_probe *tp, int argnum) · 37 unmodified lines | ||
| 838 | 958 | int i, offset, last_offset = 0; |
| 839 | 959 | |
| 840 | 960 | if (!earg) { |
| 841 | − earg = kzalloc_obj(*tp->entry_arg); | |
| 961 | + earg = kzalloc_flex(*earg, code, 2 * tp->nr_args + 1); | |
| 842 | 962 | if (!earg) |
| 843 | 963 | return -ENOMEM; |
| 844 | 964 | earg->size = 2 * tp->nr_args + 1; |
| 845 | − earg->code = kzalloc_objs(struct fetch_insn, earg->size); | |
| 846 | − if (!earg->code) { | |
| 847 | − kfree(earg); | |
| 848 | − return -ENOMEM; | |
| 849 | − } | |
| 850 | 965 | /* Fill the code buffer with 'end' to simplify it */ |
| 851 | 966 | for (i = 0; i < earg->size; i++) |
| 852 | 967 | earg->code[i].op = FETCH_OP_END; |
| @@ -953,16 +1068,9 @@ static int parse_probe_vars(char *orig_arg, const struct fetch_type *t, · 100 unmodified lines | ||
| 953 | 1068 | int len; |
| 954 | 1069 | |
| 955 | 1070 | if (ctx->flags & TPARG_FL_TEVENT) { |
| 956 | − if (code->data) | |
| 957 | − return -EFAULT; | |
| 958 | − ret = parse_trace_event_arg(arg, code, ctx); | |
| 959 | − if (!ret) | |
| 960 | − return 0; | |
| 961 | − if (strcmp(arg, "comm") == 0 || strcmp(arg, "COMM") == 0) { | |
| 962 | − code->op = FETCH_OP_COMM; | |
| 963 | − return 0; | |
| 964 | − } | |
| 965 | − goto inval; | |
| 1071 | + if (parse_trace_event(arg, code, ctx) < 0) | |
| 1072 | + goto inval; | |
| 1073 | + return 0; | |
| 966 | 1074 | } |
| 967 | 1075 | |
| 968 | 1076 | if (str_has_prefix(arg, "retval")) { |
| @@ -1229,6 +1337,9 @@ parse_probe_arg(char *arg, const struct fetch_type *type, · 260 unmodified lines | ||
| 1229 | 1337 | code->op = FETCH_OP_IMM; |
| 1230 | 1338 | } |
| 1231 | 1339 | break; |
| 1340 | + case '(': | |
| 1341 | + ret = handle_typecast(arg, pcode, end, ctx); | |
| 1342 | + break; | |
| 1232 | 1343 | default: |
| 1233 | 1344 | if (isalpha(arg[0]) || arg[0] == '_') { /* BTF variable */ |
| 1234 | 1345 | if (!tparg_is_function_entry(ctx->flags) && |
| @@ -1561,6 +1672,9 @@ fail: · 326 unmodified lines | ||
| 1561 | 1672 | } |
| 1562 | 1673 | kfree(tmp); |
| 1563 | 1674 | |
| 1675 | + /* struct_btf should not be passed to other arguments */ | |
| 1676 | + clear_struct_btf(ctx); | |
| 1677 | + | |
| 1564 | 1678 | return ret; |
| 1565 | 1679 | } |
| 1566 | 1680 | |
| @@ -2049,7 +2163,6 @@ void trace_probe_cleanup(struct trace_probe *tp) · 482 unmodified lines | ||
| 2049 | 2163 | traceprobe_free_probe_arg(&tp->args[i]); |
| 2050 | 2164 | |
| 2051 | 2165 | if (tp->entry_arg) { |
| 2052 | − kfree(tp->entry_arg->code); | |
| 2053 | 2166 | kfree(tp->entry_arg); |
| 2054 | 2167 | tp->entry_arg = NULL; |
| 2055 | 2168 | } |
| @@ -238,8 +238,8 @@ struct probe_arg { · 237 unmodified lines | ||
| 238 | 238 | }; |
| 239 | 239 | |
| 240 | 240 | struct probe_entry_arg { |
| 241 | − struct fetch_insn *code; | |
| 242 | 241 | unsigned int size; /* The entry data size */ |
| 242 | + struct fetch_insn code[] __counted_by(size); | |
| 243 | 243 | }; |
| 244 | 244 | |
| 245 | 245 | struct trace_uprobe_filter { |
| @@ -422,7 +422,9 @@ struct traceprobe_parse_context { · 176 unmodified lines | ||
| 422 | 422 | const struct btf_param *params; /* Parameter of the function */ |
| 423 | 423 | s32 nr_params; /* The number of the parameters */ |
| 424 | 424 | struct btf *btf; /* The BTF to be used */ |
| 425 | + struct btf *struct_btf; /* The BTF to be used for structs */ | |
| 425 | 426 | const struct btf_type *last_type; /* Saved type */ |
| 427 | + const struct btf_type *last_struct; /* Saved structure */ | |
| 426 | 428 | u32 last_bitoffs; /* Saved bitoffs */ |
| 427 | 429 | u32 last_bitsize; /* Saved bitsize */ |
| 428 | 430 | struct trace_probe *tp; |
| @@ -563,7 +565,8 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call, · 134 unmodified lines | ||
| 563 | 565 | C(NEED_STRING_TYPE, "$comm and immediate-string only accepts string type"),\ |
| 564 | 566 | C(TOO_MANY_ARGS, "Too many arguments are specified"), \ |
| 565 | 567 | C(TOO_MANY_EARGS, "Too many entry arguments specified"), \ |
| 566 | − C(EVENT_TOO_BIG, "Event too big (too many fields?)"), | |
| 568 | + C(EVENT_TOO_BIG, "Event too big (too many fields?)"), \ | |
| 569 | + C(TYPECAST_NOT_EVENT, "Typecasts are only for eprobe fields"), | |
| 567 | 570 | |
| 568 | 571 | #undef C |
| 569 | 572 | #define C(a, b) TP_ERR_##a |
| @@ -912,7 +912,7 @@ static int uprobe_buffer_enable(void) · 911 unmodified lines | ||
| 912 | 912 | { |
| 913 | 913 | int ret = 0; |
| 914 | 914 | |
| 915 | − BUG_ON(!mutex_is_locked(&event_mutex)); | |
| 915 | + lockdep_assert_held(&event_mutex); | |
| 916 | 916 | |
| 917 | 917 | if (uprobe_buffer_refcnt++ == 0) { |
| 918 | 918 | ret = uprobe_buffer_init(); |
| @@ -927,7 +927,7 @@ static void uprobe_buffer_disable(void) · 8 unmodified lines | ||
| 927 | 927 | { |
| 928 | 928 | int cpu; |
| 929 | 929 | |
| 930 | − BUG_ON(!mutex_is_locked(&event_mutex)); | |
| 930 | + lockdep_assert_held(&event_mutex); | |
| 931 | 931 | |
| 932 | 932 | if (--uprobe_buffer_refcnt == 0) { |
| 933 | 933 | for_each_possible_cpu(cpu) |
| @@ -979,6 +979,7 @@ static struct uprobe_cpu_buffer *prepare_uprobe_buffer(struct trace_uprobe *tu, · 45 unmodified lines | ||
| 979 | 979 | ucb = uprobe_buffer_get(); |
| 980 | 980 | ucb->dsize = tu->tp.size + dsize; |
| 981 | 981 | |
| 982 | + BUILD_BUG_ON(MAX_UCB_BUFFER_SIZE < MAX_PROBE_EVENT_SIZE); | |
| 982 | 983 | if (WARN_ON_ONCE(ucb->dsize > MAX_UCB_BUFFER_SIZE)) { |
| 983 | 984 | ucb->dsize = MAX_UCB_BUFFER_SIZE; |
| 984 | 985 | dsize = MAX_UCB_BUFFER_SIZE - tu->tp.size; |