History

Merge tag 'probes-v7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

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

Linus Torvalds committed 4 months ago

Commit 18ecdd42 parents 4f7e890 69efd864 files · +159 −38Browse files

Showing the changes to kernel (3 of 4 files). Show all

Unified · Split

3 files
  1. kernel/trace/trace_probe.c +147 −34
  2. kernel/trace/trace_probe.h +5 −2
  3. kernel/trace/trace_uprobe.c +3 −2
kernel/trace/trace_probe.c+147−34
@@ -332,6 +332,23 @@ static int parse_trace_event_arg(char *arg, struct fetch_insn *code, · 331 unmodified lines
332 return -ENOENT;332 return -ENOENT;
333}333}
334 334
335static 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#ifdef CONFIG_PROBE_EVENTS_BTF_ARGS352#ifdef CONFIG_PROBE_EVENTS_BTF_ARGS
336 353
337static u32 btf_type_int(const struct btf_type *t)354static 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 && BTF_INT_BITS(intdata) == 8;393 && BTF_INT_BITS(intdata) == 8;
377}394}
378 395
396static struct btf *ctx_btf(struct traceprobe_parse_context *ctx)
397{
398 return ctx->struct_btf ? : ctx->btf;
399}
400
379static int check_prepare_btf_string_fetch(char *typename,401static int check_prepare_btf_string_fetch(char *typename,
380 struct fetch_insn **pcode,402 struct fetch_insn **pcode,
381 struct traceprobe_parse_context *ctx)403 struct traceprobe_parse_context *ctx)
382{404{
383 struct btf *btf = ctx->btf;405 struct btf *btf = ctx_btf(ctx);
384 406
385 if (!btf || !ctx->last_type)407 if (!btf || !ctx->last_type)
386 return 0;408 return 0;
@@ -506,6 +528,15 @@ static int query_btf_context(struct traceprobe_parse_context *ctx) · 119 unmodified lines
506 return 0;528 return 0;
507}529}
508 530
531static 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
509static void clear_btf_context(struct traceprobe_parse_context *ctx)540static void clear_btf_context(struct traceprobe_parse_context *ctx)
510{541{
511 if (ctx->btf) {542 if (ctx->btf) {
@@ -554,22 +585,29 @@ static int parse_btf_field(char *fieldname, const struct btf_type *type, · 42 unmodified lines
554 struct fetch_insn *code = *pcode;585 struct fetch_insn *code = *pcode;
555 const struct btf_member *field;586 const struct btf_member *field;
556 u32 bitoffs, anon_offs;587 u32 bitoffs, anon_offs;
588 bool is_struct = ctx->struct_btf != NULL;
589 struct btf *btf = ctx_btf(ctx);
557 char *next;590 char *next;
558 int is_ptr;591 int is_ptr;
559 s32 tid;592 s32 tid;
560 593
561 do {594 do {
562 /* Outer loop for solving arrow operator ('->') */595 if (!is_struct) {
563 if (BTF_INFO_KIND(type->info) != BTF_KIND_PTR) {596 /* Outer loop for solving arrow operator ('->') */
564 trace_probe_log_err(ctx->offset, NO_PTR_STRCT);597 if (BTF_INFO_KIND(type->info) != BTF_KIND_PTR) {
565 return -EINVAL;598 trace_probe_log_err(ctx->offset, NO_PTR_STRCT);
566 }599 return -EINVAL;
567 /* Convert a struct pointer type to a struct type */600 }
568 type = btf_type_skip_modifiers(ctx->btf, type->type, &tid);601
569 if (!type) {602 /* Convert a struct pointer type to a struct type */
570 trace_probe_log_err(ctx->offset, BAD_BTF_TID);603 type = btf_type_skip_modifiers(btf, type->type, &tid);
571 return -EINVAL;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 bitoffs = 0;612 bitoffs = 0;
575 do {613 do {
@@ -580,7 +618,7 @@ static int parse_btf_field(char *fieldname, const struct btf_type *type, · 4 unmodified lines
580 return is_ptr;618 return is_ptr;
581 619
582 anon_offs = 0;620 anon_offs = 0;
583 field = btf_find_struct_member(ctx->btf, type, fieldname,621 field = btf_find_struct_member(btf, type, fieldname,
584 &anon_offs);622 &anon_offs);
585 if (IS_ERR(field)) {623 if (IS_ERR(field)) {
586 trace_probe_log_err(ctx->offset, BAD_BTF_TID);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 ctx->last_bitsize = 0;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 if (!type) {644 if (!type) {
607 trace_probe_log_err(ctx->offset, BAD_BTF_TID);645 trace_probe_log_err(ctx->offset, BAD_BTF_TID);
608 return -EINVAL;646 return -EINVAL;
@@ -640,7 +678,7 @@ static int parse_btf_arg(char *varname, · 31 unmodified lines
640 int i, is_ptr, ret;678 int i, is_ptr, ret;
641 u32 tid;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 return -EINVAL;682 return -EINVAL;
645 683
646 is_ptr = split_next_field(varname, &field, ctx);684 is_ptr = split_next_field(varname, &field, ctx);
@@ -653,6 +691,19 @@ static int parse_btf_arg(char *varname, · 6 unmodified lines
653 return -EOPNOTSUPP;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 if (ctx->flags & TPARG_FL_RETURN && !strcmp(varname, "$retval")) {707 if (ctx->flags & TPARG_FL_RETURN && !strcmp(varname, "$retval")) {
657 code->op = FETCH_OP_RETVAL;708 code->op = FETCH_OP_RETVAL;
658 /* Check whether the function return type is not void */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
710found:761found:
711 type = btf_type_skip_modifiers(ctx->btf, tid, &tid);762 type = btf_type_skip_modifiers(ctx->btf, tid, &tid);
763found_type:
712 if (!type) {764 if (!type) {
713 trace_probe_log_err(ctx->offset, BAD_BTF_TID);765 trace_probe_log_err(ctx->offset, BAD_BTF_TID);
714 return -EINVAL;766 return -EINVAL;
@@ -727,7 +779,7 @@ found: · 12 unmodified lines
727static const struct fetch_type *find_fetch_type_from_btf_type(779static const struct fetch_type *find_fetch_type_from_btf_type(
728 struct traceprobe_parse_context *ctx)780 struct traceprobe_parse_context *ctx)
729{781{
730 struct btf *btf = ctx->btf;782 struct btf *btf = ctx_btf(ctx);
731 const char *typestr = NULL;783 const char *typestr = NULL;
732 784
733 if (btf && ctx->last_type)785 if (btf && ctx->last_type)
@@ -758,7 +810,67 @@ static int parse_btf_bitfield(struct fetch_insn **pcode, · 24 unmodified lines
758 return 0;810 return 0;
759}811}
760 812
761#else813static 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
832static 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
869static void clear_struct_btf(struct traceprobe_parse_context *ctx)
870{
871 ctx->struct_btf = NULL;
872}
873
762static void clear_btf_context(struct traceprobe_parse_context *ctx)874static void clear_btf_context(struct traceprobe_parse_context *ctx)
763{875{
764 ctx->btf = NULL;876 ctx->btf = NULL;
@@ -794,7 +906,15 @@ static int check_prepare_btf_string_fetch(char *typename, · 29 unmodified lines
794 return 0;906 return 0;
795}907}
796 908
797#endif909static 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#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API919#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 int i, offset, last_offset = 0;958 int i, offset, last_offset = 0;
839 959
840 if (!earg) {960 if (!earg) {
841 earg = kzalloc_obj(*tp->entry_arg);961 earg = kzalloc_flex(*earg, code, 2 * tp->nr_args + 1);
842 if (!earg)962 if (!earg)
843 return -ENOMEM;963 return -ENOMEM;
844 earg->size = 2 * tp->nr_args + 1;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 /* Fill the code buffer with 'end' to simplify it */965 /* Fill the code buffer with 'end' to simplify it */
851 for (i = 0; i < earg->size; i++)966 for (i = 0; i < earg->size; i++)
852 earg->code[i].op = FETCH_OP_END;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 int len;1068 int len;
954 1069
955 if (ctx->flags & TPARG_FL_TEVENT) {1070 if (ctx->flags & TPARG_FL_TEVENT) {
956 if (code->data)1071 if (parse_trace_event(arg, code, ctx) < 0)
957 return -EFAULT;1072 goto inval;
958 ret = parse_trace_event_arg(arg, code, ctx);1073 return 0;
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;
966 }1074 }
967 1075
968 if (str_has_prefix(arg, "retval")) {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 code->op = FETCH_OP_IMM;1337 code->op = FETCH_OP_IMM;
1230 }1338 }
1231 break;1339 break;
1340 case '(':
1341 ret = handle_typecast(arg, pcode, end, ctx);
1342 break;
1232 default:1343 default:
1233 if (isalpha(arg[0]) || arg[0] == '_') { /* BTF variable */1344 if (isalpha(arg[0]) || arg[0] == '_') { /* BTF variable */
1234 if (!tparg_is_function_entry(ctx->flags) &&1345 if (!tparg_is_function_entry(ctx->flags) &&
@@ -1561,6 +1672,9 @@ fail: · 326 unmodified lines
1561 }1672 }
1562 kfree(tmp);1673 kfree(tmp);
1563 1674
1675 /* struct_btf should not be passed to other arguments */
1676 clear_struct_btf(ctx);
1677
1564 return ret;1678 return ret;
1565}1679}
1566 1680
@@ -2049,7 +2163,6 @@ void trace_probe_cleanup(struct trace_probe *tp) · 482 unmodified lines
2049 traceprobe_free_probe_arg(&tp->args[i]);2163 traceprobe_free_probe_arg(&tp->args[i]);
2050 2164
2051 if (tp->entry_arg) {2165 if (tp->entry_arg) {
2052 kfree(tp->entry_arg->code);
2053 kfree(tp->entry_arg);2166 kfree(tp->entry_arg);
2054 tp->entry_arg = NULL;2167 tp->entry_arg = NULL;
2055 }2168 }
kernel/trace/trace_probe.h+5−2
@@ -238,8 +238,8 @@ struct probe_arg { · 237 unmodified lines
238};238};
239 239
240struct probe_entry_arg {240struct probe_entry_arg {
241 struct fetch_insn *code;
242 unsigned int size; /* The entry data size */241 unsigned int size; /* The entry data size */
242 struct fetch_insn code[] __counted_by(size);
243};243};
244 244
245struct trace_uprobe_filter {245struct trace_uprobe_filter {
@@ -422,7 +422,9 @@ struct traceprobe_parse_context { · 176 unmodified lines
422 const struct btf_param *params; /* Parameter of the function */422 const struct btf_param *params; /* Parameter of the function */
423 s32 nr_params; /* The number of the parameters */423 s32 nr_params; /* The number of the parameters */
424 struct btf *btf; /* The BTF to be used */424 struct btf *btf; /* The BTF to be used */
425 struct btf *struct_btf; /* The BTF to be used for structs */
425 const struct btf_type *last_type; /* Saved type */426 const struct btf_type *last_type; /* Saved type */
427 const struct btf_type *last_struct; /* Saved structure */
426 u32 last_bitoffs; /* Saved bitoffs */428 u32 last_bitoffs; /* Saved bitoffs */
427 u32 last_bitsize; /* Saved bitsize */429 u32 last_bitsize; /* Saved bitsize */
428 struct trace_probe *tp;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 C(NEED_STRING_TYPE, "$comm and immediate-string only accepts string type"),\565 C(NEED_STRING_TYPE, "$comm and immediate-string only accepts string type"),\
564 C(TOO_MANY_ARGS, "Too many arguments are specified"), \566 C(TOO_MANY_ARGS, "Too many arguments are specified"), \
565 C(TOO_MANY_EARGS, "Too many entry arguments specified"), \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#undef C571#undef C
569#define C(a, b) TP_ERR_##a572#define C(a, b) TP_ERR_##a
kernel/trace/trace_uprobe.c+3−2
@@ -912,7 +912,7 @@ static int uprobe_buffer_enable(void) · 911 unmodified lines
912{912{
913 int ret = 0;913 int ret = 0;
914 914
915 BUG_ON(!mutex_is_locked(&event_mutex));915 lockdep_assert_held(&event_mutex);
916 916
917 if (uprobe_buffer_refcnt++ == 0) {917 if (uprobe_buffer_refcnt++ == 0) {
918 ret = uprobe_buffer_init();918 ret = uprobe_buffer_init();
@@ -927,7 +927,7 @@ static void uprobe_buffer_disable(void) · 8 unmodified lines
927{927{
928 int cpu;928 int cpu;
929 929
930 BUG_ON(!mutex_is_locked(&event_mutex));930 lockdep_assert_held(&event_mutex);
931 931
932 if (--uprobe_buffer_refcnt == 0) {932 if (--uprobe_buffer_refcnt == 0) {
933 for_each_possible_cpu(cpu)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 ucb = uprobe_buffer_get();979 ucb = uprobe_buffer_get();
980 ucb->dsize = tu->tp.size + dsize;980 ucb->dsize = tu->tp.size + dsize;
981 981
982 BUILD_BUG_ON(MAX_UCB_BUFFER_SIZE < MAX_PROBE_EVENT_SIZE);
982 if (WARN_ON_ONCE(ucb->dsize > MAX_UCB_BUFFER_SIZE)) {983 if (WARN_ON_ONCE(ucb->dsize > MAX_UCB_BUFFER_SIZE)) {
983 ucb->dsize = MAX_UCB_BUFFER_SIZE;984 ucb->dsize = MAX_UCB_BUFFER_SIZE;
984 dsize = MAX_UCB_BUFFER_SIZE - tu->tp.size;985 dsize = MAX_UCB_BUFFER_SIZE - tu->tp.size;