xref: /linux-6.15/include/linux/rethook.h (revision a1461f1f)
154ecbe6fSMasami Hiramatsu /* SPDX-License-Identifier: GPL-2.0 */
254ecbe6fSMasami Hiramatsu /*
354ecbe6fSMasami Hiramatsu  * Return hooking with list-based shadow stack.
454ecbe6fSMasami Hiramatsu  */
554ecbe6fSMasami Hiramatsu #ifndef _LINUX_RETHOOK_H
654ecbe6fSMasami Hiramatsu #define _LINUX_RETHOOK_H
754ecbe6fSMasami Hiramatsu 
854ecbe6fSMasami Hiramatsu #include <linux/compiler.h>
94bbd9345Swuqiang.matt #include <linux/objpool.h>
1054ecbe6fSMasami Hiramatsu #include <linux/kallsyms.h>
1154ecbe6fSMasami Hiramatsu #include <linux/llist.h>
1254ecbe6fSMasami Hiramatsu #include <linux/rcupdate.h>
1354ecbe6fSMasami Hiramatsu 
1454ecbe6fSMasami Hiramatsu struct rethook_node;
1554ecbe6fSMasami Hiramatsu 
16cb16330dSMasami Hiramatsu (Google) typedef void (*rethook_handler_t) (struct rethook_node *, void *, unsigned long, struct pt_regs *);
1754ecbe6fSMasami Hiramatsu 
1854ecbe6fSMasami Hiramatsu /**
1954ecbe6fSMasami Hiramatsu  * struct rethook - The rethook management data structure.
2054ecbe6fSMasami Hiramatsu  * @data: The user-defined data storage.
2154ecbe6fSMasami Hiramatsu  * @handler: The user-defined return hook handler.
2254ecbe6fSMasami Hiramatsu  * @pool: The pool of struct rethook_node.
2354ecbe6fSMasami Hiramatsu  * @ref: The reference counter.
2454ecbe6fSMasami Hiramatsu  * @rcu: The rcu_head for deferred freeing.
2554ecbe6fSMasami Hiramatsu  *
2654ecbe6fSMasami Hiramatsu  * Don't embed to another data structure, because this is a self-destructive
2754ecbe6fSMasami Hiramatsu  * data structure when all rethook_node are freed.
2854ecbe6fSMasami Hiramatsu  */
2954ecbe6fSMasami Hiramatsu struct rethook {
3054ecbe6fSMasami Hiramatsu 	void			*data;
31*a1461f1fSMasami Hiramatsu (Google) 	/*
32*a1461f1fSMasami Hiramatsu (Google) 	 * To avoid sparse warnings, this uses a raw function pointer with
33*a1461f1fSMasami Hiramatsu (Google) 	 * __rcu, instead of rethook_handler_t. But this must be same as
34*a1461f1fSMasami Hiramatsu (Google) 	 * rethook_handler_t.
35*a1461f1fSMasami Hiramatsu (Google) 	 */
36*a1461f1fSMasami Hiramatsu (Google) 	void (__rcu *handler) (struct rethook_node *, void *, unsigned long, struct pt_regs *);
374bbd9345Swuqiang.matt 	struct objpool_head	pool;
3854ecbe6fSMasami Hiramatsu 	struct rcu_head		rcu;
3954ecbe6fSMasami Hiramatsu };
4054ecbe6fSMasami Hiramatsu 
4154ecbe6fSMasami Hiramatsu /**
4254ecbe6fSMasami Hiramatsu  * struct rethook_node - The rethook shadow-stack entry node.
4354ecbe6fSMasami Hiramatsu  * @rcu: The rcu_head for deferred freeing.
4454ecbe6fSMasami Hiramatsu  * @llist: The llist, linked to a struct task_struct::rethooks.
4554ecbe6fSMasami Hiramatsu  * @rethook: The pointer to the struct rethook.
4654ecbe6fSMasami Hiramatsu  * @ret_addr: The storage for the real return address.
4754ecbe6fSMasami Hiramatsu  * @frame: The storage for the frame pointer.
4854ecbe6fSMasami Hiramatsu  *
4954ecbe6fSMasami Hiramatsu  * You can embed this to your extended data structure to store any data
5054ecbe6fSMasami Hiramatsu  * on each entry of the shadow stack.
5154ecbe6fSMasami Hiramatsu  */
5254ecbe6fSMasami Hiramatsu struct rethook_node {
5354ecbe6fSMasami Hiramatsu 	struct rcu_head		rcu;
5454ecbe6fSMasami Hiramatsu 	struct llist_node	llist;
5554ecbe6fSMasami Hiramatsu 	struct rethook		*rethook;
5654ecbe6fSMasami Hiramatsu 	unsigned long		ret_addr;
5754ecbe6fSMasami Hiramatsu 	unsigned long		frame;
5854ecbe6fSMasami Hiramatsu };
5954ecbe6fSMasami Hiramatsu 
604bbd9345Swuqiang.matt struct rethook *rethook_alloc(void *data, rethook_handler_t handler, int size, int num);
61195b9cb5SMasami Hiramatsu (Google) void rethook_stop(struct rethook *rh);
6254ecbe6fSMasami Hiramatsu void rethook_free(struct rethook *rh);
6354ecbe6fSMasami Hiramatsu struct rethook_node *rethook_try_get(struct rethook *rh);
6454ecbe6fSMasami Hiramatsu void rethook_recycle(struct rethook_node *node);
6554ecbe6fSMasami Hiramatsu void rethook_hook(struct rethook_node *node, struct pt_regs *regs, bool mcount);
6654ecbe6fSMasami Hiramatsu unsigned long rethook_find_ret_addr(struct task_struct *tsk, unsigned long frame,
6754ecbe6fSMasami Hiramatsu 				    struct llist_node **cur);
6854ecbe6fSMasami Hiramatsu 
6954ecbe6fSMasami Hiramatsu /* Arch dependent code must implement arch_* and trampoline code */
7054ecbe6fSMasami Hiramatsu void arch_rethook_prepare(struct rethook_node *node, struct pt_regs *regs, bool mcount);
7154ecbe6fSMasami Hiramatsu void arch_rethook_trampoline(void);
7254ecbe6fSMasami Hiramatsu 
7354ecbe6fSMasami Hiramatsu /**
7454ecbe6fSMasami Hiramatsu  * is_rethook_trampoline() - Check whether the address is rethook trampoline
7554ecbe6fSMasami Hiramatsu  * @addr: The address to be checked
7654ecbe6fSMasami Hiramatsu  *
7754ecbe6fSMasami Hiramatsu  * Return true if the @addr is the rethook trampoline address.
7854ecbe6fSMasami Hiramatsu  */
is_rethook_trampoline(unsigned long addr)7954ecbe6fSMasami Hiramatsu static inline bool is_rethook_trampoline(unsigned long addr)
8054ecbe6fSMasami Hiramatsu {
8154ecbe6fSMasami Hiramatsu 	return addr == (unsigned long)dereference_symbol_descriptor(arch_rethook_trampoline);
8254ecbe6fSMasami Hiramatsu }
8354ecbe6fSMasami Hiramatsu 
8454ecbe6fSMasami Hiramatsu /* If the architecture needs to fixup the return address, implement it. */
8554ecbe6fSMasami Hiramatsu void arch_rethook_fixup_return(struct pt_regs *regs,
8654ecbe6fSMasami Hiramatsu 			       unsigned long correct_ret_addr);
8754ecbe6fSMasami Hiramatsu 
8854ecbe6fSMasami Hiramatsu /* Generic trampoline handler, arch code must prepare asm stub */
8954ecbe6fSMasami Hiramatsu unsigned long rethook_trampoline_handler(struct pt_regs *regs,
9054ecbe6fSMasami Hiramatsu 					 unsigned long frame);
9154ecbe6fSMasami Hiramatsu 
9254ecbe6fSMasami Hiramatsu #ifdef CONFIG_RETHOOK
9354ecbe6fSMasami Hiramatsu void rethook_flush_task(struct task_struct *tk);
9454ecbe6fSMasami Hiramatsu #else
9554ecbe6fSMasami Hiramatsu #define rethook_flush_task(tsk)	do { } while (0)
9654ecbe6fSMasami Hiramatsu #endif
9754ecbe6fSMasami Hiramatsu 
9854ecbe6fSMasami Hiramatsu #endif
99