xref: /openbmc/linux/kernel/trace/rethook.c (revision d0c44de2d8ffd2e4780d360b34ee6614aa4af080)
154ecbe6fSMasami Hiramatsu // SPDX-License-Identifier: GPL-2.0
254ecbe6fSMasami Hiramatsu 
354ecbe6fSMasami Hiramatsu #define pr_fmt(fmt) "rethook: " fmt
454ecbe6fSMasami Hiramatsu 
554ecbe6fSMasami Hiramatsu #include <linux/bug.h>
654ecbe6fSMasami Hiramatsu #include <linux/kallsyms.h>
754ecbe6fSMasami Hiramatsu #include <linux/kprobes.h>
854ecbe6fSMasami Hiramatsu #include <linux/preempt.h>
954ecbe6fSMasami Hiramatsu #include <linux/rethook.h>
1054ecbe6fSMasami Hiramatsu #include <linux/slab.h>
1154ecbe6fSMasami Hiramatsu #include <linux/sort.h>
1254ecbe6fSMasami Hiramatsu 
1354ecbe6fSMasami Hiramatsu /* Return hook list (shadow stack by list) */
1454ecbe6fSMasami Hiramatsu 
1554ecbe6fSMasami Hiramatsu /*
1654ecbe6fSMasami Hiramatsu  * This function is called from delayed_put_task_struct() when a task is
1754ecbe6fSMasami Hiramatsu  * dead and cleaned up to recycle any kretprobe instances associated with
1854ecbe6fSMasami Hiramatsu  * this task. These left over instances represent probed functions that
1954ecbe6fSMasami Hiramatsu  * have been called but will never return.
2054ecbe6fSMasami Hiramatsu  */
rethook_flush_task(struct task_struct * tk)2154ecbe6fSMasami Hiramatsu void rethook_flush_task(struct task_struct *tk)
2254ecbe6fSMasami Hiramatsu {
2354ecbe6fSMasami Hiramatsu 	struct rethook_node *rhn;
2454ecbe6fSMasami Hiramatsu 	struct llist_node *node;
2554ecbe6fSMasami Hiramatsu 
2654ecbe6fSMasami Hiramatsu 	node = __llist_del_all(&tk->rethooks);
2754ecbe6fSMasami Hiramatsu 	while (node) {
2854ecbe6fSMasami Hiramatsu 		rhn = container_of(node, struct rethook_node, llist);
2954ecbe6fSMasami Hiramatsu 		node = node->next;
3054ecbe6fSMasami Hiramatsu 		preempt_disable();
3154ecbe6fSMasami Hiramatsu 		rethook_recycle(rhn);
3254ecbe6fSMasami Hiramatsu 		preempt_enable();
3354ecbe6fSMasami Hiramatsu 	}
3454ecbe6fSMasami Hiramatsu }
3554ecbe6fSMasami Hiramatsu 
rethook_free_rcu(struct rcu_head * head)3654ecbe6fSMasami Hiramatsu static void rethook_free_rcu(struct rcu_head *head)
3754ecbe6fSMasami Hiramatsu {
3854ecbe6fSMasami Hiramatsu 	struct rethook *rh = container_of(head, struct rethook, rcu);
3954ecbe6fSMasami Hiramatsu 	struct rethook_node *rhn;
4054ecbe6fSMasami Hiramatsu 	struct freelist_node *node;
4154ecbe6fSMasami Hiramatsu 	int count = 1;
4254ecbe6fSMasami Hiramatsu 
4354ecbe6fSMasami Hiramatsu 	node = rh->pool.head;
4454ecbe6fSMasami Hiramatsu 	while (node) {
4554ecbe6fSMasami Hiramatsu 		rhn = container_of(node, struct rethook_node, freelist);
4654ecbe6fSMasami Hiramatsu 		node = node->next;
4754ecbe6fSMasami Hiramatsu 		kfree(rhn);
4854ecbe6fSMasami Hiramatsu 		count++;
4954ecbe6fSMasami Hiramatsu 	}
5054ecbe6fSMasami Hiramatsu 
5154ecbe6fSMasami Hiramatsu 	/* The rh->ref is the number of pooled node + 1 */
5254ecbe6fSMasami Hiramatsu 	if (refcount_sub_and_test(count, &rh->ref))
5354ecbe6fSMasami Hiramatsu 		kfree(rh);
5454ecbe6fSMasami Hiramatsu }
5554ecbe6fSMasami Hiramatsu 
5654ecbe6fSMasami Hiramatsu /**
57195b9cb5SMasami Hiramatsu (Google)  * rethook_stop() - Stop using a rethook.
58195b9cb5SMasami Hiramatsu (Google)  * @rh: the struct rethook to stop.
59195b9cb5SMasami Hiramatsu (Google)  *
60195b9cb5SMasami Hiramatsu (Google)  * Stop using a rethook to prepare for freeing it. If you want to wait for
61195b9cb5SMasami Hiramatsu (Google)  * all running rethook handler before calling rethook_free(), you need to
62195b9cb5SMasami Hiramatsu (Google)  * call this first and wait RCU, and call rethook_free().
63195b9cb5SMasami Hiramatsu (Google)  */
rethook_stop(struct rethook * rh)64195b9cb5SMasami Hiramatsu (Google) void rethook_stop(struct rethook *rh)
65195b9cb5SMasami Hiramatsu (Google) {
66*29b9ebc8SMasami Hiramatsu (Google) 	rcu_assign_pointer(rh->handler, NULL);
67195b9cb5SMasami Hiramatsu (Google) }
68195b9cb5SMasami Hiramatsu (Google) 
69195b9cb5SMasami Hiramatsu (Google) /**
7054ecbe6fSMasami Hiramatsu  * rethook_free() - Free struct rethook.
7154ecbe6fSMasami Hiramatsu  * @rh: the struct rethook to be freed.
7254ecbe6fSMasami Hiramatsu  *
7354ecbe6fSMasami Hiramatsu  * Free the rethook. Before calling this function, user must ensure the
7454ecbe6fSMasami Hiramatsu  * @rh::data is cleaned if needed (or, the handler can access it after
7554ecbe6fSMasami Hiramatsu  * calling this function.) This function will set the @rh to be freed
7654ecbe6fSMasami Hiramatsu  * after all rethook_node are freed (not soon). And the caller must
7754ecbe6fSMasami Hiramatsu  * not touch @rh after calling this.
7854ecbe6fSMasami Hiramatsu  */
rethook_free(struct rethook * rh)7954ecbe6fSMasami Hiramatsu void rethook_free(struct rethook *rh)
8054ecbe6fSMasami Hiramatsu {
81*29b9ebc8SMasami Hiramatsu (Google) 	rethook_stop(rh);
8254ecbe6fSMasami Hiramatsu 
8354ecbe6fSMasami Hiramatsu 	call_rcu(&rh->rcu, rethook_free_rcu);
8454ecbe6fSMasami Hiramatsu }
8554ecbe6fSMasami Hiramatsu 
rethook_get_handler(struct rethook * rh)86*29b9ebc8SMasami Hiramatsu (Google) static inline rethook_handler_t rethook_get_handler(struct rethook *rh)
87*29b9ebc8SMasami Hiramatsu (Google) {
88*29b9ebc8SMasami Hiramatsu (Google) 	return (rethook_handler_t)rcu_dereference_check(rh->handler,
89*29b9ebc8SMasami Hiramatsu (Google) 							rcu_read_lock_any_held());
90*29b9ebc8SMasami Hiramatsu (Google) }
91*29b9ebc8SMasami Hiramatsu (Google) 
9254ecbe6fSMasami Hiramatsu /**
9354ecbe6fSMasami Hiramatsu  * rethook_alloc() - Allocate struct rethook.
9454ecbe6fSMasami Hiramatsu  * @data: a data to pass the @handler when hooking the return.
9554ecbe6fSMasami Hiramatsu  * @handler: the return hook callback function.
9654ecbe6fSMasami Hiramatsu  *
9754ecbe6fSMasami Hiramatsu  * Allocate and initialize a new rethook with @data and @handler.
9854ecbe6fSMasami Hiramatsu  * Return NULL if memory allocation fails or @handler is NULL.
9954ecbe6fSMasami Hiramatsu  * Note that @handler == NULL means this rethook is going to be freed.
10054ecbe6fSMasami Hiramatsu  */
rethook_alloc(void * data,rethook_handler_t handler)10154ecbe6fSMasami Hiramatsu struct rethook *rethook_alloc(void *data, rethook_handler_t handler)
10254ecbe6fSMasami Hiramatsu {
10354ecbe6fSMasami Hiramatsu 	struct rethook *rh = kzalloc(sizeof(struct rethook), GFP_KERNEL);
10454ecbe6fSMasami Hiramatsu 
1050a1ebe35SYi Yang 	if (!rh || !handler) {
1060a1ebe35SYi Yang 		kfree(rh);
10754ecbe6fSMasami Hiramatsu 		return NULL;
1080a1ebe35SYi Yang 	}
10954ecbe6fSMasami Hiramatsu 
11054ecbe6fSMasami Hiramatsu 	rh->data = data;
111*29b9ebc8SMasami Hiramatsu (Google) 	rcu_assign_pointer(rh->handler, handler);
11254ecbe6fSMasami Hiramatsu 	rh->pool.head = NULL;
11354ecbe6fSMasami Hiramatsu 	refcount_set(&rh->ref, 1);
11454ecbe6fSMasami Hiramatsu 
11554ecbe6fSMasami Hiramatsu 	return rh;
11654ecbe6fSMasami Hiramatsu }
11754ecbe6fSMasami Hiramatsu 
11854ecbe6fSMasami Hiramatsu /**
11954ecbe6fSMasami Hiramatsu  * rethook_add_node() - Add a new node to the rethook.
12054ecbe6fSMasami Hiramatsu  * @rh: the struct rethook.
12154ecbe6fSMasami Hiramatsu  * @node: the struct rethook_node to be added.
12254ecbe6fSMasami Hiramatsu  *
12354ecbe6fSMasami Hiramatsu  * Add @node to @rh. User must allocate @node (as a part of user's
12454ecbe6fSMasami Hiramatsu  * data structure.) The @node fields are initialized in this function.
12554ecbe6fSMasami Hiramatsu  */
rethook_add_node(struct rethook * rh,struct rethook_node * node)12654ecbe6fSMasami Hiramatsu void rethook_add_node(struct rethook *rh, struct rethook_node *node)
12754ecbe6fSMasami Hiramatsu {
12854ecbe6fSMasami Hiramatsu 	node->rethook = rh;
12954ecbe6fSMasami Hiramatsu 	freelist_add(&node->freelist, &rh->pool);
13054ecbe6fSMasami Hiramatsu 	refcount_inc(&rh->ref);
13154ecbe6fSMasami Hiramatsu }
13254ecbe6fSMasami Hiramatsu 
free_rethook_node_rcu(struct rcu_head * head)13354ecbe6fSMasami Hiramatsu static void free_rethook_node_rcu(struct rcu_head *head)
13454ecbe6fSMasami Hiramatsu {
13554ecbe6fSMasami Hiramatsu 	struct rethook_node *node = container_of(head, struct rethook_node, rcu);
13654ecbe6fSMasami Hiramatsu 
13754ecbe6fSMasami Hiramatsu 	if (refcount_dec_and_test(&node->rethook->ref))
13854ecbe6fSMasami Hiramatsu 		kfree(node->rethook);
13954ecbe6fSMasami Hiramatsu 	kfree(node);
14054ecbe6fSMasami Hiramatsu }
14154ecbe6fSMasami Hiramatsu 
14254ecbe6fSMasami Hiramatsu /**
14354ecbe6fSMasami Hiramatsu  * rethook_recycle() - return the node to rethook.
14454ecbe6fSMasami Hiramatsu  * @node: The struct rethook_node to be returned.
14554ecbe6fSMasami Hiramatsu  *
14654ecbe6fSMasami Hiramatsu  * Return back the @node to @node::rethook. If the @node::rethook is already
14754ecbe6fSMasami Hiramatsu  * marked as freed, this will free the @node.
14854ecbe6fSMasami Hiramatsu  */
rethook_recycle(struct rethook_node * node)14954ecbe6fSMasami Hiramatsu void rethook_recycle(struct rethook_node *node)
15054ecbe6fSMasami Hiramatsu {
151*29b9ebc8SMasami Hiramatsu (Google) 	rethook_handler_t handler;
15254ecbe6fSMasami Hiramatsu 
153*29b9ebc8SMasami Hiramatsu (Google) 	handler = rethook_get_handler(node->rethook);
154*29b9ebc8SMasami Hiramatsu (Google) 	if (likely(handler))
15554ecbe6fSMasami Hiramatsu 		freelist_add(&node->freelist, &node->rethook->pool);
15654ecbe6fSMasami Hiramatsu 	else
15754ecbe6fSMasami Hiramatsu 		call_rcu(&node->rcu, free_rethook_node_rcu);
15854ecbe6fSMasami Hiramatsu }
15954ecbe6fSMasami Hiramatsu NOKPROBE_SYMBOL(rethook_recycle);
16054ecbe6fSMasami Hiramatsu 
16154ecbe6fSMasami Hiramatsu /**
16254ecbe6fSMasami Hiramatsu  * rethook_try_get() - get an unused rethook node.
16354ecbe6fSMasami Hiramatsu  * @rh: The struct rethook which pools the nodes.
16454ecbe6fSMasami Hiramatsu  *
16554ecbe6fSMasami Hiramatsu  * Get an unused rethook node from @rh. If the node pool is empty, this
16654ecbe6fSMasami Hiramatsu  * will return NULL. Caller must disable preemption.
16754ecbe6fSMasami Hiramatsu  */
rethook_try_get(struct rethook * rh)16854ecbe6fSMasami Hiramatsu struct rethook_node *rethook_try_get(struct rethook *rh)
16954ecbe6fSMasami Hiramatsu {
170*29b9ebc8SMasami Hiramatsu (Google) 	rethook_handler_t handler = rethook_get_handler(rh);
17154ecbe6fSMasami Hiramatsu 	struct freelist_node *fn;
17254ecbe6fSMasami Hiramatsu 
17354ecbe6fSMasami Hiramatsu 	/* Check whether @rh is going to be freed. */
17454ecbe6fSMasami Hiramatsu 	if (unlikely(!handler))
17554ecbe6fSMasami Hiramatsu 		return NULL;
17654ecbe6fSMasami Hiramatsu 
177c0f3bb40SMasami Hiramatsu (Google) 	/*
178c0f3bb40SMasami Hiramatsu (Google) 	 * This expects the caller will set up a rethook on a function entry.
179c0f3bb40SMasami Hiramatsu (Google) 	 * When the function returns, the rethook will eventually be reclaimed
180c0f3bb40SMasami Hiramatsu (Google) 	 * or released in the rethook_recycle() with call_rcu().
181c0f3bb40SMasami Hiramatsu (Google) 	 * This means the caller must be run in the RCU-availabe context.
182c0f3bb40SMasami Hiramatsu (Google) 	 */
183c0f3bb40SMasami Hiramatsu (Google) 	if (unlikely(!rcu_is_watching()))
184c0f3bb40SMasami Hiramatsu (Google) 		return NULL;
185c0f3bb40SMasami Hiramatsu (Google) 
18654ecbe6fSMasami Hiramatsu 	fn = freelist_try_get(&rh->pool);
18754ecbe6fSMasami Hiramatsu 	if (!fn)
18854ecbe6fSMasami Hiramatsu 		return NULL;
18954ecbe6fSMasami Hiramatsu 
19054ecbe6fSMasami Hiramatsu 	return container_of(fn, struct rethook_node, freelist);
19154ecbe6fSMasami Hiramatsu }
19254ecbe6fSMasami Hiramatsu NOKPROBE_SYMBOL(rethook_try_get);
19354ecbe6fSMasami Hiramatsu 
19454ecbe6fSMasami Hiramatsu /**
19554ecbe6fSMasami Hiramatsu  * rethook_hook() - Hook the current function return.
19654ecbe6fSMasami Hiramatsu  * @node: The struct rethook node to hook the function return.
19754ecbe6fSMasami Hiramatsu  * @regs: The struct pt_regs for the function entry.
19854ecbe6fSMasami Hiramatsu  * @mcount: True if this is called from mcount(ftrace) context.
19954ecbe6fSMasami Hiramatsu  *
20054ecbe6fSMasami Hiramatsu  * Hook the current running function return. This must be called when the
20154ecbe6fSMasami Hiramatsu  * function entry (or at least @regs must be the registers of the function
20254ecbe6fSMasami Hiramatsu  * entry.) @mcount is used for identifying the context. If this is called
20354ecbe6fSMasami Hiramatsu  * from ftrace (mcount) callback, @mcount must be set true. If this is called
20454ecbe6fSMasami Hiramatsu  * from the real function entry (e.g. kprobes) @mcount must be set false.
20554ecbe6fSMasami Hiramatsu  * This is because the way to hook the function return depends on the context.
20654ecbe6fSMasami Hiramatsu  */
rethook_hook(struct rethook_node * node,struct pt_regs * regs,bool mcount)20754ecbe6fSMasami Hiramatsu void rethook_hook(struct rethook_node *node, struct pt_regs *regs, bool mcount)
20854ecbe6fSMasami Hiramatsu {
20954ecbe6fSMasami Hiramatsu 	arch_rethook_prepare(node, regs, mcount);
21054ecbe6fSMasami Hiramatsu 	__llist_add(&node->llist, &current->rethooks);
21154ecbe6fSMasami Hiramatsu }
21254ecbe6fSMasami Hiramatsu NOKPROBE_SYMBOL(rethook_hook);
21354ecbe6fSMasami Hiramatsu 
21454ecbe6fSMasami Hiramatsu /* This assumes the 'tsk' is the current task or is not running. */
__rethook_find_ret_addr(struct task_struct * tsk,struct llist_node ** cur)21554ecbe6fSMasami Hiramatsu static unsigned long __rethook_find_ret_addr(struct task_struct *tsk,
21654ecbe6fSMasami Hiramatsu 					     struct llist_node **cur)
21754ecbe6fSMasami Hiramatsu {
21854ecbe6fSMasami Hiramatsu 	struct rethook_node *rh = NULL;
21954ecbe6fSMasami Hiramatsu 	struct llist_node *node = *cur;
22054ecbe6fSMasami Hiramatsu 
22154ecbe6fSMasami Hiramatsu 	if (!node)
22254ecbe6fSMasami Hiramatsu 		node = tsk->rethooks.first;
22354ecbe6fSMasami Hiramatsu 	else
22454ecbe6fSMasami Hiramatsu 		node = node->next;
22554ecbe6fSMasami Hiramatsu 
22654ecbe6fSMasami Hiramatsu 	while (node) {
22754ecbe6fSMasami Hiramatsu 		rh = container_of(node, struct rethook_node, llist);
22854ecbe6fSMasami Hiramatsu 		if (rh->ret_addr != (unsigned long)arch_rethook_trampoline) {
22954ecbe6fSMasami Hiramatsu 			*cur = node;
23054ecbe6fSMasami Hiramatsu 			return rh->ret_addr;
23154ecbe6fSMasami Hiramatsu 		}
23254ecbe6fSMasami Hiramatsu 		node = node->next;
23354ecbe6fSMasami Hiramatsu 	}
23454ecbe6fSMasami Hiramatsu 	return 0;
23554ecbe6fSMasami Hiramatsu }
23654ecbe6fSMasami Hiramatsu NOKPROBE_SYMBOL(__rethook_find_ret_addr);
23754ecbe6fSMasami Hiramatsu 
23854ecbe6fSMasami Hiramatsu /**
23954ecbe6fSMasami Hiramatsu  * rethook_find_ret_addr -- Find correct return address modified by rethook
24054ecbe6fSMasami Hiramatsu  * @tsk: Target task
24154ecbe6fSMasami Hiramatsu  * @frame: A frame pointer
24254ecbe6fSMasami Hiramatsu  * @cur: a storage of the loop cursor llist_node pointer for next call
24354ecbe6fSMasami Hiramatsu  *
24454ecbe6fSMasami Hiramatsu  * Find the correct return address modified by a rethook on @tsk in unsigned
24554ecbe6fSMasami Hiramatsu  * long type.
24654ecbe6fSMasami Hiramatsu  * The @tsk must be 'current' or a task which is not running. @frame is a hint
24754ecbe6fSMasami Hiramatsu  * to get the currect return address - which is compared with the
24854ecbe6fSMasami Hiramatsu  * rethook::frame field. The @cur is a loop cursor for searching the
24954ecbe6fSMasami Hiramatsu  * kretprobe return addresses on the @tsk. The '*@cur' should be NULL at the
25054ecbe6fSMasami Hiramatsu  * first call, but '@cur' itself must NOT NULL.
25154ecbe6fSMasami Hiramatsu  *
25254ecbe6fSMasami Hiramatsu  * Returns found address value or zero if not found.
25354ecbe6fSMasami Hiramatsu  */
rethook_find_ret_addr(struct task_struct * tsk,unsigned long frame,struct llist_node ** cur)25454ecbe6fSMasami Hiramatsu unsigned long rethook_find_ret_addr(struct task_struct *tsk, unsigned long frame,
25554ecbe6fSMasami Hiramatsu 				    struct llist_node **cur)
25654ecbe6fSMasami Hiramatsu {
25754ecbe6fSMasami Hiramatsu 	struct rethook_node *rhn = NULL;
25854ecbe6fSMasami Hiramatsu 	unsigned long ret;
25954ecbe6fSMasami Hiramatsu 
26054ecbe6fSMasami Hiramatsu 	if (WARN_ON_ONCE(!cur))
26154ecbe6fSMasami Hiramatsu 		return 0;
26254ecbe6fSMasami Hiramatsu 
26354ecbe6fSMasami Hiramatsu 	if (WARN_ON_ONCE(tsk != current && task_is_running(tsk)))
26454ecbe6fSMasami Hiramatsu 		return 0;
26554ecbe6fSMasami Hiramatsu 
26654ecbe6fSMasami Hiramatsu 	do {
26754ecbe6fSMasami Hiramatsu 		ret = __rethook_find_ret_addr(tsk, cur);
26854ecbe6fSMasami Hiramatsu 		if (!ret)
26954ecbe6fSMasami Hiramatsu 			break;
27054ecbe6fSMasami Hiramatsu 		rhn = container_of(*cur, struct rethook_node, llist);
27154ecbe6fSMasami Hiramatsu 	} while (rhn->frame != frame);
27254ecbe6fSMasami Hiramatsu 
27354ecbe6fSMasami Hiramatsu 	return ret;
27454ecbe6fSMasami Hiramatsu }
27554ecbe6fSMasami Hiramatsu NOKPROBE_SYMBOL(rethook_find_ret_addr);
27654ecbe6fSMasami Hiramatsu 
arch_rethook_fixup_return(struct pt_regs * regs,unsigned long correct_ret_addr)27754ecbe6fSMasami Hiramatsu void __weak arch_rethook_fixup_return(struct pt_regs *regs,
27854ecbe6fSMasami Hiramatsu 				      unsigned long correct_ret_addr)
27954ecbe6fSMasami Hiramatsu {
28054ecbe6fSMasami Hiramatsu 	/*
28154ecbe6fSMasami Hiramatsu 	 * Do nothing by default. If the architecture which uses a
28254ecbe6fSMasami Hiramatsu 	 * frame pointer to record real return address on the stack,
28354ecbe6fSMasami Hiramatsu 	 * it should fill this function to fixup the return address
28454ecbe6fSMasami Hiramatsu 	 * so that stacktrace works from the rethook handler.
28554ecbe6fSMasami Hiramatsu 	 */
28654ecbe6fSMasami Hiramatsu }
28754ecbe6fSMasami Hiramatsu 
28854ecbe6fSMasami Hiramatsu /* This function will be called from each arch-defined trampoline. */
rethook_trampoline_handler(struct pt_regs * regs,unsigned long frame)28954ecbe6fSMasami Hiramatsu unsigned long rethook_trampoline_handler(struct pt_regs *regs,
29054ecbe6fSMasami Hiramatsu 					 unsigned long frame)
29154ecbe6fSMasami Hiramatsu {
29254ecbe6fSMasami Hiramatsu 	struct llist_node *first, *node = NULL;
29354ecbe6fSMasami Hiramatsu 	unsigned long correct_ret_addr;
29454ecbe6fSMasami Hiramatsu 	rethook_handler_t handler;
29554ecbe6fSMasami Hiramatsu 	struct rethook_node *rhn;
29654ecbe6fSMasami Hiramatsu 
29754ecbe6fSMasami Hiramatsu 	correct_ret_addr = __rethook_find_ret_addr(current, &node);
29854ecbe6fSMasami Hiramatsu 	if (!correct_ret_addr) {
29954ecbe6fSMasami Hiramatsu 		pr_err("rethook: Return address not found! Maybe there is a bug in the kernel\n");
30054ecbe6fSMasami Hiramatsu 		BUG_ON(1);
30154ecbe6fSMasami Hiramatsu 	}
30254ecbe6fSMasami Hiramatsu 
30354ecbe6fSMasami Hiramatsu 	instruction_pointer_set(regs, correct_ret_addr);
30454ecbe6fSMasami Hiramatsu 
30554ecbe6fSMasami Hiramatsu 	/*
30654ecbe6fSMasami Hiramatsu 	 * These loops must be protected from rethook_free_rcu() because those
30754ecbe6fSMasami Hiramatsu 	 * are accessing 'rhn->rethook'.
30854ecbe6fSMasami Hiramatsu 	 */
309be243bacSZe Gao 	preempt_disable_notrace();
31054ecbe6fSMasami Hiramatsu 
31154ecbe6fSMasami Hiramatsu 	/*
31254ecbe6fSMasami Hiramatsu 	 * Run the handler on the shadow stack. Do not unlink the list here because
31354ecbe6fSMasami Hiramatsu 	 * stackdump inside the handlers needs to decode it.
31454ecbe6fSMasami Hiramatsu 	 */
31554ecbe6fSMasami Hiramatsu 	first = current->rethooks.first;
31654ecbe6fSMasami Hiramatsu 	while (first) {
31754ecbe6fSMasami Hiramatsu 		rhn = container_of(first, struct rethook_node, llist);
31854ecbe6fSMasami Hiramatsu 		if (WARN_ON_ONCE(rhn->frame != frame))
31954ecbe6fSMasami Hiramatsu 			break;
320*29b9ebc8SMasami Hiramatsu (Google) 		handler = rethook_get_handler(rhn->rethook);
32154ecbe6fSMasami Hiramatsu 		if (handler)
322cb16330dSMasami Hiramatsu (Google) 			handler(rhn, rhn->rethook->data,
323cb16330dSMasami Hiramatsu (Google) 				correct_ret_addr, regs);
32454ecbe6fSMasami Hiramatsu 
32554ecbe6fSMasami Hiramatsu 		if (first == node)
32654ecbe6fSMasami Hiramatsu 			break;
32754ecbe6fSMasami Hiramatsu 		first = first->next;
32854ecbe6fSMasami Hiramatsu 	}
32954ecbe6fSMasami Hiramatsu 
33054ecbe6fSMasami Hiramatsu 	/* Fixup registers for returning to correct address. */
33154ecbe6fSMasami Hiramatsu 	arch_rethook_fixup_return(regs, correct_ret_addr);
33254ecbe6fSMasami Hiramatsu 
33354ecbe6fSMasami Hiramatsu 	/* Unlink used shadow stack */
33454ecbe6fSMasami Hiramatsu 	first = current->rethooks.first;
33554ecbe6fSMasami Hiramatsu 	current->rethooks.first = node->next;
33654ecbe6fSMasami Hiramatsu 	node->next = NULL;
33754ecbe6fSMasami Hiramatsu 
33854ecbe6fSMasami Hiramatsu 	while (first) {
33954ecbe6fSMasami Hiramatsu 		rhn = container_of(first, struct rethook_node, llist);
34054ecbe6fSMasami Hiramatsu 		first = first->next;
34154ecbe6fSMasami Hiramatsu 		rethook_recycle(rhn);
34254ecbe6fSMasami Hiramatsu 	}
343be243bacSZe Gao 	preempt_enable_notrace();
34454ecbe6fSMasami Hiramatsu 
34554ecbe6fSMasami Hiramatsu 	return correct_ret_addr;
34654ecbe6fSMasami Hiramatsu }
34754ecbe6fSMasami Hiramatsu NOKPROBE_SYMBOL(rethook_trampoline_handler);
348