Commit 9a3236ce authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'probes-fixes-v6.5-rc1' of...

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

Pull probes fixes from Masami Hiramatsu:

 - Fix fprobe's rethook release issues:

     - Release rethook after ftrace_ops is unregistered so that the
       rethook is not accessed after free.

     - Stop rethook before ftrace_ops is unregistered so that the
       rethook is NOT used after exiting unregister_fprobe()

 - Fix eprobe cleanup logic. If it attaches to multiple events and
   failes to enable one of them, rollback all enabled events correctly.

 - Fix fprobe to unlock ftrace recursion lock correctly when it missed
   by another running kprobe.

 - Cleanup kprobe to remove unnecessary NULL.

 - Cleanup kprobe to remove unnecessary 0 initializations.

* tag 'probes-fixes-v6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
  fprobe: Ensure running fprobe_exit_handler() finished before calling rethook_free()
  kernel: kprobes: Remove unnecessary ‘0’ values
  kprobes: Remove unnecessary ‘NULL’ values from correct_ret_addr
  fprobe: add unlock to match a succeeded ftrace_test_recursion_trylock
  kernel/trace: Fix cleanup logic of enable_trace_eprobe
  fprobe: Release rethook after the ftrace_ops is unregistered
parents 1d754604 195b9cb5
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ struct rethook_node {
};

struct rethook *rethook_alloc(void *data, rethook_handler_t handler);
void rethook_stop(struct rethook *rh);
void rethook_free(struct rethook *rh);
void rethook_add_node(struct rethook *rh, struct rethook_node *node);
struct rethook_node *rethook_try_get(struct rethook *rh);
+4 −4
Original line number Diff line number Diff line
@@ -1072,7 +1072,7 @@ static int kprobe_ftrace_enabled;
static int __arm_kprobe_ftrace(struct kprobe *p, struct ftrace_ops *ops,
			       int *cnt)
{
	int ret = 0;
	int ret;

	lockdep_assert_held(&kprobe_mutex);

@@ -1110,7 +1110,7 @@ static int arm_kprobe_ftrace(struct kprobe *p)
static int __disarm_kprobe_ftrace(struct kprobe *p, struct ftrace_ops *ops,
				  int *cnt)
{
	int ret = 0;
	int ret;

	lockdep_assert_held(&kprobe_mutex);

@@ -2007,9 +2007,9 @@ void __weak arch_kretprobe_fixup_return(struct pt_regs *regs,
unsigned long __kretprobe_trampoline_handler(struct pt_regs *regs,
					     void *frame_pointer)
{
	kprobe_opcode_t *correct_ret_addr = NULL;
	struct kretprobe_instance *ri = NULL;
	struct llist_node *first, *node = NULL;
	kprobe_opcode_t *correct_ret_addr;
	struct kretprobe *rp;

	/* Find correct address and all nodes for this frame. */
@@ -2693,7 +2693,7 @@ void kprobe_free_init_mem(void)

static int __init init_kprobes(void)
{
	int i, err = 0;
	int i, err;

	/* FIXME allocate the probe table, currently defined statically */
	/* initialize all list heads */
+7 −8
Original line number Diff line number Diff line
@@ -102,12 +102,14 @@ static void fprobe_kprobe_handler(unsigned long ip, unsigned long parent_ip,

	if (unlikely(kprobe_running())) {
		fp->nmissed++;
		return;
		goto recursion_unlock;
	}

	kprobe_busy_begin();
	__fprobe_handler(ip, parent_ip, ops, fregs);
	kprobe_busy_end();

recursion_unlock:
	ftrace_test_recursion_unlock(bit);
}

@@ -371,19 +373,16 @@ int unregister_fprobe(struct fprobe *fp)
	if (!fprobe_is_registered(fp))
		return -EINVAL;

	/*
	 * rethook_free() starts disabling the rethook, but the rethook handlers
	 * may be running on other processors at this point. To make sure that all
	 * current running handlers are finished, call unregister_ftrace_function()
	 * after this.
	 */
	if (fp->rethook)
		rethook_free(fp->rethook);
		rethook_stop(fp->rethook);

	ret = unregister_ftrace_function(&fp->ops);
	if (ret < 0)
		return ret;

	if (fp->rethook)
		rethook_free(fp->rethook);

	ftrace_free_filter(&fp->ops);

	return ret;
+13 −0
Original line number Diff line number Diff line
@@ -53,6 +53,19 @@ static void rethook_free_rcu(struct rcu_head *head)
		kfree(rh);
}

/**
 * rethook_stop() - Stop using a rethook.
 * @rh: the struct rethook to stop.
 *
 * Stop using a rethook to prepare for freeing it. If you want to wait for
 * all running rethook handler before calling rethook_free(), you need to
 * call this first and wait RCU, and call rethook_free().
 */
void rethook_stop(struct rethook *rh)
{
	WRITE_ONCE(rh->handler, NULL);
}

/**
 * rethook_free() - Free struct rethook.
 * @rh: the struct rethook to be freed.
+16 −2
Original line number Diff line number Diff line
@@ -644,6 +644,7 @@ static int enable_trace_eprobe(struct trace_event_call *call,
	struct trace_eprobe *ep;
	bool enabled;
	int ret = 0;
	int cnt = 0;

	tp = trace_probe_primary_from_call(call);
	if (WARN_ON_ONCE(!tp))
@@ -667,12 +668,25 @@ static int enable_trace_eprobe(struct trace_event_call *call,
		if (ret)
			break;
		enabled = true;
		cnt++;
	}

	if (ret) {
		/* Failed to enable one of them. Roll back all */
		if (enabled)
		if (enabled) {
			/*
			 * It's a bug if one failed for something other than memory
			 * not being available but another eprobe succeeded.
			 */
			WARN_ON_ONCE(ret != -ENOMEM);

			list_for_each_entry(pos, trace_probe_probe_list(tp), list) {
				ep = container_of(pos, struct trace_eprobe, tp);
				disable_eprobe(ep, file->tr);
				if (!--cnt)
					break;
			}
		}
		if (file)
			trace_probe_remove_file(tp, file);
		else