Commit 1d5dcaa3 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'probes-fixes-v7.1-rc3' of...

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

Pull probes fixes from Masami Hiramatsu:

 - kprobes: skip non-symbol addresses in kprobe_add_ksym_blacklist()

   Since the ftrace adds its NOPs at .kprobes.text section (which stores
   an array), a wrong entry is added when loading a module which uses
   "__kprobes" attribute.

   To solve this, add "notrace" to __kprobes functions

 - test_kprobes: clear kprobes between test runs

   Clear all kprobes in the test program after running a test set,
   because Kunit test can run several times

 - fprobe: Fix unregister_fprobe() to wait for RCU grace period

   Since the fprobe data structure is removed with hlist_del_rcu(), it
   should wait for the RCU grace period. If the caller waits for RCU, we
   can use the async variant (e.g. eBPF)

* tag 'probes-fixes-v7.1-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
  fprobe: Fix unregister_fprobe() to wait for RCU grace period
  test_kprobes: clear kprobes between test runs
  kprobes: skip non-symbol addresses in kprobe_add_ksym_blacklist()
parents c21b90f7 657b594b
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@ static unsigned long __used \
	_kbl_addr_##fname = (unsigned long)fname;
# define NOKPROBE_SYMBOL(fname)	__NOKPROBE_SYMBOL(fname)
/* Use this to forbid a kprobes attach on very low level functions */
# define __kprobes	__section(".kprobes.text")
# define __kprobes	notrace __section(".kprobes.text")
# define nokprobe_inline	__always_inline
#else
# define NOKPROBE_SYMBOL(fname)
+5 −0
Original line number Diff line number Diff line
@@ -94,6 +94,7 @@ int register_fprobe(struct fprobe *fp, const char *filter, const char *notfilter
int register_fprobe_ips(struct fprobe *fp, unsigned long *addrs, int num);
int register_fprobe_syms(struct fprobe *fp, const char **syms, int num);
int unregister_fprobe(struct fprobe *fp);
int unregister_fprobe_async(struct fprobe *fp);
bool fprobe_is_registered(struct fprobe *fp);
int fprobe_count_ips_from_filter(const char *filter, const char *notfilter);
#else
@@ -113,6 +114,10 @@ static inline int unregister_fprobe(struct fprobe *fp)
{
	return -EOPNOTSUPP;
}
static inline int unregister_fprobe_async(struct fprobe *fp)
{
	return -EOPNOTSUPP;
}
static inline bool fprobe_is_registered(struct fprobe *fp)
{
	return false;
+2 −1
Original line number Diff line number Diff line
@@ -2384,7 +2384,8 @@ static void bpf_kprobe_multi_link_release(struct bpf_link *link)
	struct bpf_kprobe_multi_link *kmulti_link;

	kmulti_link = container_of(link, struct bpf_kprobe_multi_link, link);
	unregister_fprobe(&kmulti_link->fp);
	/* Don't wait for RCU GP here. */
	unregister_fprobe_async(&kmulti_link->fp);
	kprobe_multi_put_modules(kmulti_link->mods, kmulti_link->mods_cnt);
}

+21 −2
Original line number Diff line number Diff line
@@ -1093,14 +1093,15 @@ static int unregister_fprobe_nolock(struct fprobe *fp)
}

/**
 * unregister_fprobe() - Unregister fprobe.
 * unregister_fprobe_async() - Unregister fprobe without RCU GP wait
 * @fp: A fprobe data structure to be unregistered.
 *
 * Unregister fprobe (and remove ftrace hooks from the function entries).
 * This function will NOT wait until the fprobe is no longer used.
 *
 * Return 0 if @fp is unregistered successfully, -errno if not.
 */
int unregister_fprobe(struct fprobe *fp)
int unregister_fprobe_async(struct fprobe *fp)
{
	guard(mutex)(&fprobe_mutex);
	if (!fp || !fprobe_registered(fp))
@@ -1108,6 +1109,24 @@ int unregister_fprobe(struct fprobe *fp)

	return unregister_fprobe_nolock(fp);
}

/**
 * unregister_fprobe() - Unregister fprobe with RCU GP wait
 * @fp: A fprobe data structure to be unregistered.
 *
 * Unregister fprobe (and remove ftrace hooks from the function entries).
 * This function will block until the fprobe is no longer used.
 *
 * Return 0 if @fp is unregistered successfully, -errno if not.
 */
int unregister_fprobe(struct fprobe *fp)
{
	int ret = unregister_fprobe_async(fp);

	if (!ret)
		synchronize_rcu();
	return ret;
}
EXPORT_SYMBOL_GPL(unregister_fprobe);

static int __init fprobe_initcall(void)
+18 −11
Original line number Diff line number Diff line
@@ -12,6 +12,12 @@

#define div_factor 3

#define KP_CLEAR(_kp) \
do { \
	(_kp).addr = NULL; \
	(_kp).flags = 0; \
} while (0)

static u32 rand1, preh_val, posth_val;
static u32 (*target)(u32 value);
static u32 (*recursed_target)(u32 value);
@@ -125,10 +131,6 @@ static void test_kprobes(struct kunit *test)

	current_test = test;

	/* addr and flags should be cleard for reusing kprobe. */
	kp.addr = NULL;
	kp.flags = 0;

	KUNIT_EXPECT_EQ(test, 0, register_kprobes(kps, 2));
	preh_val = 0;
	posth_val = 0;
@@ -226,9 +228,6 @@ static void test_kretprobes(struct kunit *test)
	struct kretprobe *rps[2] = {&rp, &rp2};

	current_test = test;
	/* addr and flags should be cleard for reusing kprobe. */
	rp.kp.addr = NULL;
	rp.kp.flags = 0;
	KUNIT_EXPECT_EQ(test, 0, register_kretprobes(rps, 2));

	krph_val = 0;
@@ -290,8 +289,6 @@ static void test_stacktrace_on_kretprobe(struct kunit *test)
	unsigned long myretaddr = (unsigned long)__builtin_return_address(0);

	current_test = test;
	rp3.kp.addr = NULL;
	rp3.kp.flags = 0;

	/*
	 * Run the stacktrace_driver() to record correct return address in
@@ -352,8 +349,6 @@ static void test_stacktrace_on_nested_kretprobe(struct kunit *test)
	struct kretprobe *rps[2] = {&rp3, &rp4};

	current_test = test;
	rp3.kp.addr = NULL;
	rp3.kp.flags = 0;

	//KUNIT_ASSERT_NE(test, myretaddr, stacktrace_driver());

@@ -367,6 +362,18 @@ static void test_stacktrace_on_nested_kretprobe(struct kunit *test)

static int kprobes_test_init(struct kunit *test)
{
	KP_CLEAR(kp);
	KP_CLEAR(kp2);
	KP_CLEAR(kp_missed);
#ifdef CONFIG_KRETPROBES
	KP_CLEAR(rp.kp);
	KP_CLEAR(rp2.kp);
#ifdef CONFIG_ARCH_CORRECT_STACKTRACE_ON_KRETPROBE
	KP_CLEAR(rp3.kp);
	KP_CLEAR(rp4.kp);
#endif
#endif

	target = kprobe_target;
	target2 = kprobe_target2;
	recursed_target = kprobe_recursed_target;