History

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

Pull kprobes updates from Masami Hiramatsu: - Skip negative return code check for snprintf in eprobe - Add recursive call test cases for kprobe unit test - Add 'char' type to probe events to show it as the character instead of value - Update kselftest kprobe-event testcase to ignore '__pfx_' symbols - Fix kselftest to check filter on eprobe event correctly - Add filter on eprobe to the README file in tracefs - Fix optprobes to check whether there is 'under unoptimizing' optprobe when optimizing another kprobe correctly - Fix optprobe to check whether there is 'under unoptimizing' optprobe when fetching the original instruction correctly - Fix optprobe to free 'forcibly unoptimized' optprobe correctly * tag 'probes-v6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: tracing/eprobe: no need to check for negative ret value for snprintf test_kprobes: Add recursed kprobe test case tracing/probe: add a char type to show the character value of traced arguments selftests/ftrace: Fix probepoint testcase to ignore __pfx_* symbols selftests/ftrace: Fix eprobe syntax test case to check filter support tracing/eprobe: Fix to add filter on eprobe description in README file x86/kprobes: Fix arch_check_optimized_kprobe check within optimized_kprobe range x86/kprobes: Fix __recover_optprobed_insn check optimizing logic kprobes: Fix to handle forcibly unoptimized kprobes on freeing_list

Linus Torvalds committed 3 years ago

Commit 2b79eb72 parents 0df8218 c96abae12 files · +117 −33Browse files

Unified · Split

12 files
  1. Documentation/trace/kprobetrace.rst +3 −1
  2. arch/x86/kernel/kprobes/opt.c +3 −3
  3. include/linux/kprobes.h +2 −0
  4. kernel/kprobes.c +12 −15
  5. kernel/trace/trace.c +2 −2
  6. kernel/trace/trace_eprobe.c +4 −8
  7. kernel/trace/trace_probe.c +2 −0
  8. kernel/trace/trace_probe.h +1 −0
  9. lib/test_kprobes.c +37 −2
  10. tools/testing/selftests/ftrace/test.d/dynevent/eprobes_syntax_errors.tc +3 −1
  11. tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_char.tc +47 −0
  12. tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc +1 −1
Documentation/trace/kprobetrace.rst+3−1
@@ -58,7 +58,7 @@ Synopsis of kprobe_events · 57 unmodified lines
58 NAME=FETCHARG : Set NAME as the argument name of FETCHARG.58 NAME=FETCHARG : Set NAME as the argument name of FETCHARG.
59 FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types59 FETCHARG:TYPE : Set TYPE as the type of FETCHARG. Currently, basic types
60 (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types60 (u8/u16/u32/u64/s8/s16/s32/s64), hexadecimal types
61 (x8/x16/x32/x64), "string", "ustring", "symbol", "symstr"61 (x8/x16/x32/x64), "char", "string", "ustring", "symbol", "symstr"
62 and bitfield are supported.62 and bitfield are supported.
63 63
64 (\*1) only for the probe on function entry (offs == 0).64 (\*1) only for the probe on function entry (offs == 0).
@@ -82,6 +82,8 @@ Note that the array can be applied to memory type fetchargs, you can not · 17 unmodified lines
82apply it to registers/stack-entries etc. (for example, '$stack1:x8[8]' is82apply it to registers/stack-entries etc. (for example, '$stack1:x8[8]' is
83wrong, but '+8($stack):x8[8]' is OK.)83wrong, but '+8($stack):x8[8]' is OK.)
84 84
85Char type can be used to show the character value of traced arguments.
86
85String type is a special type, which fetches a "null-terminated" string from87String type is a special type, which fetches a "null-terminated" string from
86kernel space. This means it will fail and store NULL if the string container88kernel space. This means it will fail and store NULL if the string container
87has been paged out. "ustring" type is an alternative of string for user-space.89has been paged out. "ustring" type is an alternative of string for user-space.
arch/x86/kernel/kprobes/opt.c+3−3
@@ -46,8 +46,8 @@ unsigned long __recover_optprobed_insn(kprobe_opcode_t *buf, unsigned long addr) · 45 unmodified lines
46 /* This function only handles jump-optimized kprobe */46 /* This function only handles jump-optimized kprobe */
47 if (kp && kprobe_optimized(kp)) {47 if (kp && kprobe_optimized(kp)) {
48 op = container_of(kp, struct optimized_kprobe, kp);48 op = container_of(kp, struct optimized_kprobe, kp);
49 /* If op->list is not empty, op is under optimizing */49 /* If op is optimized or under unoptimizing */
50 if (list_empty(&op->list))50 if (list_empty(&op->list) || optprobe_queued_unopt(op))
51 goto found;51 goto found;
52 }52 }
53 }53 }
@@ -353,7 +353,7 @@ int arch_check_optimized_kprobe(struct optimized_kprobe *op) · 299 unmodified lines
353 353
354 for (i = 1; i < op->optinsn.size; i++) {354 for (i = 1; i < op->optinsn.size; i++) {
355 p = get_kprobe(op->kp.addr + i);355 p = get_kprobe(op->kp.addr + i);
356 if (p && !kprobe_disabled(p))356 if (p && !kprobe_disarmed(p))
357 return -EEXIST;357 return -EEXIST;
358 }358 }
359 359
include/linux/kprobes.h+2−0
@@ -378,6 +378,8 @@ extern void opt_pre_handler(struct kprobe *p, struct pt_regs *regs); · 377 unmodified lines
378DEFINE_INSN_CACHE_OPS(optinsn);378DEFINE_INSN_CACHE_OPS(optinsn);
379 379
380extern void wait_for_kprobe_optimizer(void);380extern void wait_for_kprobe_optimizer(void);
381bool optprobe_queued_unopt(struct optimized_kprobe *op);
382bool kprobe_disarmed(struct kprobe *p);
381#else /* !CONFIG_OPTPROBES */383#else /* !CONFIG_OPTPROBES */
382static inline void wait_for_kprobe_optimizer(void) { }384static inline void wait_for_kprobe_optimizer(void) { }
383#endif /* CONFIG_OPTPROBES */385#endif /* CONFIG_OPTPROBES */
kernel/kprobes.c+12−15
@@ -458,7 +458,7 @@ static inline int kprobe_optready(struct kprobe *p) · 457 unmodified lines
458}458}
459 459
460/* Return true if the kprobe is disarmed. Note: p must be on hash list */460/* Return true if the kprobe is disarmed. Note: p must be on hash list */
461static inline bool kprobe_disarmed(struct kprobe *p)461bool kprobe_disarmed(struct kprobe *p)
462{462{
463 struct optimized_kprobe *op;463 struct optimized_kprobe *op;
464 464
@@ -555,17 +555,15 @@ static void do_unoptimize_kprobes(void) · 90 unmodified lines
555 /* See comment in do_optimize_kprobes() */555 /* See comment in do_optimize_kprobes() */
556 lockdep_assert_cpus_held();556 lockdep_assert_cpus_held();
557 557
558 /* Unoptimization must be done anytime */558 if (!list_empty(&unoptimizing_list))
559 if (list_empty(&unoptimizing_list))559 arch_unoptimize_kprobes(&unoptimizing_list, &freeing_list);
560 return;
561 560
562 arch_unoptimize_kprobes(&unoptimizing_list, &freeing_list);561 /* Loop on 'freeing_list' for disarming and removing from kprobe hash list */
563 /* Loop on 'freeing_list' for disarming */
564 list_for_each_entry_safe(op, tmp, &freeing_list, list) {562 list_for_each_entry_safe(op, tmp, &freeing_list, list) {
565 /* Switching from detour code to origin */563 /* Switching from detour code to origin */
566 op->kp.flags &= ~KPROBE_FLAG_OPTIMIZED;564 op->kp.flags &= ~KPROBE_FLAG_OPTIMIZED;
567 /* Disarm probes if marked disabled */565 /* Disarm probes if marked disabled and not gone */
568 if (kprobe_disabled(&op->kp))566 if (kprobe_disabled(&op->kp) && !kprobe_gone(&op->kp))
569 arch_disarm_kprobe(&op->kp);567 arch_disarm_kprobe(&op->kp);
570 if (kprobe_unused(&op->kp)) {568 if (kprobe_unused(&op->kp)) {
571 /*569 /*
@@ -662,7 +660,7 @@ void wait_for_kprobe_optimizer(void) · 90 unmodified lines
662 mutex_unlock(&kprobe_mutex);660 mutex_unlock(&kprobe_mutex);
663}661}
664 662
665static bool optprobe_queued_unopt(struct optimized_kprobe *op)663bool optprobe_queued_unopt(struct optimized_kprobe *op)
666{664{
667 struct optimized_kprobe *_op;665 struct optimized_kprobe *_op;
668 666
@@ -797,14 +795,13 @@ static void kill_optimized_kprobe(struct kprobe *p) · 128 unmodified lines
797 op->kp.flags &= ~KPROBE_FLAG_OPTIMIZED;795 op->kp.flags &= ~KPROBE_FLAG_OPTIMIZED;
798 796
799 if (kprobe_unused(p)) {797 if (kprobe_unused(p)) {
800 /* Enqueue if it is unused */
801 list_add(&op->list, &freeing_list);
802 /*798 /*
803 * Remove unused probes from the hash list. After waiting799 * Unused kprobe is on unoptimizing or freeing list. We move it
804 * for synchronization, this probe is reclaimed.800 * to freeing_list and let the kprobe_optimizer() remove it from
805 * (reclaiming is done by do_free_cleaned_kprobes().)801 * the kprobe hash list and free it.
806 */802 */
807 hlist_del_rcu(&op->kp.hlist);803 if (optprobe_queued_unopt(op))
804 list_move(&op->list, &freeing_list);
808 }805 }
809 806
810 /* Don't touch the code, because it is already freed. */807 /* Don't touch the code, because it is already freed. */
kernel/trace/trace.c+2−2
@@ -5646,7 +5646,7 @@ static const char readme_msg[] = · 5645 unmodified lines
5646#ifdef CONFIG_HIST_TRIGGERS5646#ifdef CONFIG_HIST_TRIGGERS
5647 "\t s:[synthetic/]<event> <field> [<field>]\n"5647 "\t s:[synthetic/]<event> <field> [<field>]\n"
5648#endif5648#endif
5649 "\t e[:[<group>/][<event>]] <attached-group>.<attached-event> [<args>]\n"5649 "\t e[:[<group>/][<event>]] <attached-group>.<attached-event> [<args>] [if <filter>]\n"
5650 "\t -:[<group>/][<event>]\n"5650 "\t -:[<group>/][<event>]\n"
5651#ifdef CONFIG_KPROBE_EVENTS5651#ifdef CONFIG_KPROBE_EVENTS
5652 "\t place: [<module>:]<symbol>[+<offset>]|<memaddr>\n"5652 "\t place: [<module>:]<symbol>[+<offset>]|<memaddr>\n"
@@ -5663,7 +5663,7 @@ static const char readme_msg[] = · 10 unmodified lines
5663 "\t $stack<index>, $stack, $retval, $comm,\n"5663 "\t $stack<index>, $stack, $retval, $comm,\n"
5664#endif5664#endif
5665 "\t +|-[u]<offset>(<fetcharg>), \\imm-value, \\\"imm-string\"\n"5665 "\t +|-[u]<offset>(<fetcharg>), \\imm-value, \\\"imm-string\"\n"
5666 "\t type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n"5666 "\t type: s8/16/32/64, u8/16/32/64, x8/16/32/64, char, string, symbol,\n"
5667 "\t b<bit-width>@<bit-offset>/<container-size>, ustring,\n"5667 "\t b<bit-width>@<bit-offset>/<container-size>, ustring,\n"
5668 "\t symstr, <type>\\[<array-size>\\]\n"5668 "\t symstr, <type>\\[<array-size>\\]\n"
5669#ifdef CONFIG_HIST_TRIGGERS5669#ifdef CONFIG_HIST_TRIGGERS
kernel/trace/trace_eprobe.c+4−8
@@ -923,17 +923,13 @@ static int trace_eprobe_parse_filter(struct trace_eprobe *ep, int argc, const ch · 922 unmodified lines
923 923
924 p = ep->filter_str;924 p = ep->filter_str;
925 for (i = 0; i < argc; i++) {925 for (i = 0; i < argc; i++) {
926 ret = snprintf(p, len, "%s ", argv[i]);926 if (i)
927 if (ret < 0)927 ret = snprintf(p, len, " %s", argv[i]);
928 goto error;928 else
929 if (ret > len) {929 ret = snprintf(p, len, "%s", argv[i]);
930 ret = -E2BIG;
931 goto error;
932 }
933 p += ret;930 p += ret;
934 len -= ret;931 len -= ret;
935 }932 }
936 p[-1] = '\0';
937 933
938 /*934 /*
939 * Ensure the filter string can be parsed correctly. Note, this935 * Ensure the filter string can be parsed correctly. Note, this
kernel/trace/trace_probe.c+2−0
@@ -50,6 +50,7 @@ DEFINE_BASIC_PRINT_TYPE_FUNC(x8, u8, "0x%x") · 49 unmodified lines
50DEFINE_BASIC_PRINT_TYPE_FUNC(x16, u16, "0x%x")50DEFINE_BASIC_PRINT_TYPE_FUNC(x16, u16, "0x%x")
51DEFINE_BASIC_PRINT_TYPE_FUNC(x32, u32, "0x%x")51DEFINE_BASIC_PRINT_TYPE_FUNC(x32, u32, "0x%x")
52DEFINE_BASIC_PRINT_TYPE_FUNC(x64, u64, "0x%Lx")52DEFINE_BASIC_PRINT_TYPE_FUNC(x64, u64, "0x%Lx")
53DEFINE_BASIC_PRINT_TYPE_FUNC(char, u8, "'%c'")
53 54
54int PRINT_TYPE_FUNC_NAME(symbol)(struct trace_seq *s, void *data, void *ent)55int PRINT_TYPE_FUNC_NAME(symbol)(struct trace_seq *s, void *data, void *ent)
55{56{
@@ -95,6 +96,7 @@ static const struct fetch_type probe_fetch_types[] = { · 39 unmodified lines
95 ASSIGN_FETCH_TYPE_ALIAS(x16, u16, u16, 0),96 ASSIGN_FETCH_TYPE_ALIAS(x16, u16, u16, 0),
96 ASSIGN_FETCH_TYPE_ALIAS(x32, u32, u32, 0),97 ASSIGN_FETCH_TYPE_ALIAS(x32, u32, u32, 0),
97 ASSIGN_FETCH_TYPE_ALIAS(x64, u64, u64, 0),98 ASSIGN_FETCH_TYPE_ALIAS(x64, u64, u64, 0),
99 ASSIGN_FETCH_TYPE_ALIAS(char, u8, u8, 0),
98 ASSIGN_FETCH_TYPE_ALIAS(symbol, ADDR_FETCH_TYPE, ADDR_FETCH_TYPE, 0),100 ASSIGN_FETCH_TYPE_ALIAS(symbol, ADDR_FETCH_TYPE, ADDR_FETCH_TYPE, 0),
99 101
100 ASSIGN_FETCH_TYPE_END102 ASSIGN_FETCH_TYPE_END
kernel/trace/trace_probe.h+1−0
@@ -166,6 +166,7 @@ DECLARE_BASIC_PRINT_TYPE_FUNC(x16); · 165 unmodified lines
166DECLARE_BASIC_PRINT_TYPE_FUNC(x32);166DECLARE_BASIC_PRINT_TYPE_FUNC(x32);
167DECLARE_BASIC_PRINT_TYPE_FUNC(x64);167DECLARE_BASIC_PRINT_TYPE_FUNC(x64);
168 168
169DECLARE_BASIC_PRINT_TYPE_FUNC(char);
169DECLARE_BASIC_PRINT_TYPE_FUNC(string);170DECLARE_BASIC_PRINT_TYPE_FUNC(string);
170DECLARE_BASIC_PRINT_TYPE_FUNC(symbol);171DECLARE_BASIC_PRINT_TYPE_FUNC(symbol);
171 172
lib/test_kprobes.c+37−2
@@ -14,6 +14,7 @@ · 13 unmodified lines
14 14
15static u32 rand1, preh_val, posth_val;15static u32 rand1, preh_val, posth_val;
16static u32 (*target)(u32 value);16static u32 (*target)(u32 value);
17static u32 (*recursed_target)(u32 value);
17static u32 (*target2)(u32 value);18static u32 (*target2)(u32 value);
18static struct kunit *current_test;19static struct kunit *current_test;
19 20
@@ -27,18 +28,27 @@ static noinline u32 kprobe_target(u32 value) · 7 unmodified lines
27 return (value / div_factor);28 return (value / div_factor);
28}29}
29 30
31static noinline u32 kprobe_recursed_target(u32 value)
32{
33 return (value / div_factor);
34}
35
30static int kp_pre_handler(struct kprobe *p, struct pt_regs *regs)36static int kp_pre_handler(struct kprobe *p, struct pt_regs *regs)
31{37{
32 KUNIT_EXPECT_FALSE(current_test, preemptible());38 KUNIT_EXPECT_FALSE(current_test, preemptible());
33 preh_val = (rand1 / div_factor);39
40 preh_val = recursed_target(rand1);
34 return 0;41 return 0;
35}42}
36 43
37static void kp_post_handler(struct kprobe *p, struct pt_regs *regs,44static void kp_post_handler(struct kprobe *p, struct pt_regs *regs,
38 unsigned long flags)45 unsigned long flags)
39{46{
47 u32 expval = recursed_target(rand1);
48
40 KUNIT_EXPECT_FALSE(current_test, preemptible());49 KUNIT_EXPECT_FALSE(current_test, preemptible());
41 KUNIT_EXPECT_EQ(current_test, preh_val, (rand1 / div_factor));50 KUNIT_EXPECT_EQ(current_test, preh_val, expval);
51
42 posth_val = preh_val + div_factor;52 posth_val = preh_val + div_factor;
43}53}
44 54
@@ -136,6 +146,29 @@ static void test_kprobes(struct kunit *test) · 91 unmodified lines
136 unregister_kprobes(kps, 2);146 unregister_kprobes(kps, 2);
137}147}
138 148
149static struct kprobe kp_missed = {
150 .symbol_name = "kprobe_recursed_target",
151 .pre_handler = kp_pre_handler,
152 .post_handler = kp_post_handler,
153};
154
155static void test_kprobe_missed(struct kunit *test)
156{
157 current_test = test;
158 preh_val = 0;
159 posth_val = 0;
160
161 KUNIT_EXPECT_EQ(test, 0, register_kprobe(&kp_missed));
162
163 recursed_target(rand1);
164
165 KUNIT_EXPECT_EQ(test, 2, kp_missed.nmissed);
166 KUNIT_EXPECT_NE(test, 0, preh_val);
167 KUNIT_EXPECT_NE(test, 0, posth_val);
168
169 unregister_kprobe(&kp_missed);
170}
171
139#ifdef CONFIG_KRETPROBES172#ifdef CONFIG_KRETPROBES
140static u32 krph_val;173static u32 krph_val;
141 174
@@ -336,6 +369,7 @@ static int kprobes_test_init(struct kunit *test) · 194 unmodified lines
336{369{
337 target = kprobe_target;370 target = kprobe_target;
338 target2 = kprobe_target2;371 target2 = kprobe_target2;
372 recursed_target = kprobe_recursed_target;
339 stacktrace_target = kprobe_stacktrace_target;373 stacktrace_target = kprobe_stacktrace_target;
340 internal_target = kprobe_stacktrace_internal_target;374 internal_target = kprobe_stacktrace_internal_target;
341 stacktrace_driver = kprobe_stacktrace_driver;375 stacktrace_driver = kprobe_stacktrace_driver;
@@ -346,6 +380,7 @@ static int kprobes_test_init(struct kunit *test) · 4 unmodified lines
346static struct kunit_case kprobes_testcases[] = {380static struct kunit_case kprobes_testcases[] = {
347 KUNIT_CASE(test_kprobe),381 KUNIT_CASE(test_kprobe),
348 KUNIT_CASE(test_kprobes),382 KUNIT_CASE(test_kprobes),
383 KUNIT_CASE(test_kprobe_missed),
349#ifdef CONFIG_KRETPROBES384#ifdef CONFIG_KRETPROBES
350 KUNIT_CASE(test_kretprobe),385 KUNIT_CASE(test_kretprobe),
351 KUNIT_CASE(test_kretprobes),386 KUNIT_CASE(test_kretprobes),
tools/testing/selftests/ftrace/test.d/dynevent/eprobes_syntax_errors.tc+3−1
@@ -22,6 +22,8 @@ check_error 'e:foo/^bar.1 syscalls/sys_enter_openat' # BAD_EVENT_NAME · 21 unmodified lines
22check_error 'e:foo/bar syscalls/sys_enter_openat arg=^dfd' # BAD_FETCH_ARG22check_error 'e:foo/bar syscalls/sys_enter_openat arg=^dfd' # BAD_FETCH_ARG
23check_error 'e:foo/bar syscalls/sys_enter_openat ^arg=$foo' # BAD_ATTACH_ARG23check_error 'e:foo/bar syscalls/sys_enter_openat ^arg=$foo' # BAD_ATTACH_ARG
24 24
25check_error 'e:foo/bar syscalls/sys_enter_openat if ^' # NO_EP_FILTER25if grep -q '<attached-group>\.<attached-event>.*\[if <filter>\]' README; then
26 check_error 'e:foo/bar syscalls/sys_enter_openat if ^' # NO_EP_FILTER
27fi
26 28
27exit 029exit 0
tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_char.tc+47−0
@@ -0,0 +1,47 @@
1#!/bin/sh
2# SPDX-License-Identifier: GPL-2.0
3# description: Kprobe event char type argument
4# requires: kprobe_events
5
6case `uname -m` in
7x86_64)
8 ARG1=%di
9;;
10i[3456]86)
11 ARG1=%ax
12;;
13aarch64)
14 ARG1=%x0
15;;
16arm*)
17 ARG1=%r0
18;;
19ppc64*)
20 ARG1=%r3
21;;
22ppc*)
23 ARG1=%r3
24;;
25s390*)
26 ARG1=%r2
27;;
28mips*)
29 ARG1=%r4
30;;
31*)
32 echo "Please implement other architecture here"
33 exit_untested
34esac
35
36: "Test get argument (1)"
37echo "p:testprobe tracefs_create_dir arg1=+0(${ARG1}):char" > kprobe_events
38echo 1 > events/kprobes/testprobe/enable
39echo "p:test $FUNCTION_FORK" >> kprobe_events
40grep -qe "testprobe.* arg1='t'" trace
41
42echo 0 > events/kprobes/testprobe/enable
43: "Test get argument (2)"
44echo "p:testprobe tracefs_create_dir arg1=+0(${ARG1}):char arg2=+0(${ARG1}):char[4]" > kprobe_events
45echo 1 > events/kprobes/testprobe/enable
46echo "p:test $FUNCTION_FORK" >> kprobe_events
47grep -qe "testprobe.* arg1='t' arg2={'t','e','s','t'}" trace
tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc+1−1
@@ -21,7 +21,7 @@ set_offs() { # prev target next · 20 unmodified lines
21 21
22# We have to decode symbol addresses to get correct offsets.22# We have to decode symbol addresses to get correct offsets.
23# If the offset is not an instruction boundary, it cause -EILSEQ.23# If the offset is not an instruction boundary, it cause -EILSEQ.
24set_offs `grep -A1 -B1 ${TARGET_FUNC} /proc/kallsyms | cut -f 1 -d " " | xargs`24set_offs `grep -v __pfx_ /proc/kallsyms | grep -A1 -B1 ${TARGET_FUNC} | cut -f 1 -d " " | xargs`
25 25
26UINT_TEST=no26UINT_TEST=no
27# printf "%x" -1 returns (unsigned long)-1.27# printf "%x" -1 returns (unsigned long)-1.