xref: /openbmc/linux/include/linux/rethook.h (revision 29b9ebc8)
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>
954ecbe6fSMasami Hiramatsu #include <linux/freelist.h>
1054ecbe6fSMasami Hiramatsu #include <linux/kallsyms.h>
1154ecbe6fSMasami Hiramatsu #include <linux/llist.h>
1254ecbe6fSMasami Hiramatsu #include <linux/rcupdate.h>
1354ecbe6fSMasami Hiramatsu #include <linux/refcount.h>
1454ecbe6fSMasami Hiramatsu 
1554ecbe6fSMasami Hiramatsu struct rethook_node;
1654ecbe6fSMasami Hiramatsu 
17cb16330dSMasami Hiramatsu (Google) typedef void (*rethook_handler_t) (struct rethook_node *, void *, unsigned long, struct pt_regs *);
1854ecbe6fSMasami Hiramatsu 
1954ecbe6fSMasami Hiramatsu /**
2054ecbe6fSMasami Hiramatsu  * struct rethook - The rethook management data structure.
2154ecbe6fSMasami Hiramatsu  * @data: The user-defined data storage.
2254ecbe6fSMasami Hiramatsu  * @handler: The user-defined return hook handler.
2354ecbe6fSMasami Hiramatsu  * @pool: The pool of struct rethook_node.
2454ecbe6fSMasami Hiramatsu  * @ref: The reference counter.
2554ecbe6fSMasami Hiramatsu  * @rcu: The rcu_head for deferred freeing.
2654ecbe6fSMasami Hiramatsu  *
2754ecbe6fSMasami Hiramatsu  * Don't embed to another data structure, because this is a self-destructive
2854ecbe6fSMasami Hiramatsu  * data structure when all rethook_node are freed.
2954ecbe6fSMasami Hiramatsu  */
3054ecbe6fSMasami Hiramatsu struct rethook {
3154ecbe6fSMasami Hiramatsu 	void			*data;
32*29b9ebc8SMasami Hiramatsu (Google) 	/*
33*29b9ebc8SMasami Hiramatsu (Google) 	 * To avoid sparse warnings, this uses a raw function pointer with
34*29b9ebc8SMasami Hiramatsu (Google) 	 * __rcu, instead of rethook_handler_t. But this must be same as
35*29b9ebc8SMasami Hiramatsu (Google) 	 * rethook_handler_t.
36*29b9ebc8SMasami Hiramatsu (Google) 	 */
37*29b9ebc8SMasami Hiramatsu (Google) 	void (__rcu *handler) (struct rethook_node *, void *, unsigned long, struct pt_regs *);
3854ecbe6fSMasami Hiramatsu 	struct freelist_head	pool;
3954ecbe6fSMasami Hiramatsu 	refcount_t		ref;
4054ecbe6fSMasami Hiramatsu 	struct rcu_head		rcu;
4154ecbe6fSMasami Hiramatsu };
4254ecbe6fSMasami Hiramatsu 
4354ecbe6fSMasami Hiramatsu /**
4454ecbe6fSMasami Hiramatsu  * struct rethook_node - The rethook shadow-stack entry node.
4554ecbe6fSMasami Hiramatsu  * @freelist: The freelist, linked to struct rethook::pool.
4654ecbe6fSMasami Hiramatsu  * @rcu: The rcu_head for deferred freeing.
4754ecbe6fSMasami Hiramatsu  * @llist: The llist, linked to a struct task_struct::rethooks.
4854ecbe6fSMasami Hiramatsu  * @rethook: The pointer to the struct rethook.
4954ecbe6fSMasami Hiramatsu  * @ret_addr: The storage for the real return address.
5054ecbe6fSMasami Hiramatsu  * @frame: The storage for the frame pointer.
5154ecbe6fSMasami Hiramatsu  *
5254ecbe6fSMasami Hiramatsu  * You can embed this to your extended data structure to store any data
5354ecbe6fSMasami Hiramatsu  * on each entry of the shadow stack.
5454ecbe6fSMasami Hiramatsu  */
5554ecbe6fSMasami Hiramatsu struct rethook_node {
5654ecbe6fSMasami Hiramatsu 	union {
5754ecbe6fSMasami Hiramatsu 		struct freelist_node freelist;
5854ecbe6fSMasami Hiramatsu 		struct rcu_head      rcu;
5954ecbe6fSMasami Hiramatsu 	};
6054ecbe6fSMasami Hiramatsu 	struct llist_node	llist;
6154ecbe6fSMasami Hiramatsu 	struct rethook		*rethook;
6254ecbe6fSMasami Hiramatsu 	unsigned long		ret_addr;
6354ecbe6fSMasami Hiramatsu 	unsigned long		frame;
6454ecbe6fSMasami Hiramatsu };
6554ecbe6fSMasami Hiramatsu 
6654ecbe6fSMasami Hiramatsu struct rethook *rethook_alloc(void *data, rethook_handler_t handler);
67195b9cb5SMasami Hiramatsu (Google) void rethook_stop(struct rethook *rh);
6854ecbe6fSMasami Hiramatsu void rethook_free(struct rethook *rh);
6954ecbe6fSMasami Hiramatsu void rethook_add_node(struct rethook *rh, struct rethook_node *node);
7054ecbe6fSMasami Hiramatsu struct rethook_node *rethook_try_get(struct rethook *rh);
7154ecbe6fSMasami Hiramatsu void rethook_recycle(struct rethook_node *node);
7254ecbe6fSMasami Hiramatsu void rethook_hook(struct rethook_node *node, struct pt_regs *regs, bool mcount);
7354ecbe6fSMasami Hiramatsu unsigned long rethook_find_ret_addr(struct task_struct *tsk, unsigned long frame,
7454ecbe6fSMasami Hiramatsu 				    struct llist_node **cur);
7554ecbe6fSMasami Hiramatsu 
7654ecbe6fSMasami Hiramatsu /* Arch dependent code must implement arch_* and trampoline code */
7754ecbe6fSMasami Hiramatsu void arch_rethook_prepare(struct rethook_node *node, struct pt_regs *regs, bool mcount);
7854ecbe6fSMasami Hiramatsu void arch_rethook_trampoline(void);
7954ecbe6fSMasami Hiramatsu 
8054ecbe6fSMasami Hiramatsu /**
8154ecbe6fSMasami Hiramatsu  * is_rethook_trampoline() - Check whether the address is rethook trampoline
8254ecbe6fSMasami Hiramatsu  * @addr: The address to be checked
8354ecbe6fSMasami Hiramatsu  *
8454ecbe6fSMasami Hiramatsu  * Return true if the @addr is the rethook trampoline address.
8554ecbe6fSMasami Hiramatsu  */
is_rethook_trampoline(unsigned long addr)8654ecbe6fSMasami Hiramatsu static inline bool is_rethook_trampoline(unsigned long addr)
8754ecbe6fSMasami Hiramatsu {
8854ecbe6fSMasami Hiramatsu 	return addr == (unsigned long)dereference_symbol_descriptor(arch_rethook_trampoline);
8954ecbe6fSMasami Hiramatsu }
9054ecbe6fSMasami Hiramatsu 
9154ecbe6fSMasami Hiramatsu /* If the architecture needs to fixup the return address, implement it. */
9254ecbe6fSMasami Hiramatsu void arch_rethook_fixup_return(struct pt_regs *regs,
9354ecbe6fSMasami Hiramatsu 			       unsigned long correct_ret_addr);
9454ecbe6fSMasami Hiramatsu 
9554ecbe6fSMasami Hiramatsu /* Generic trampoline handler, arch code must prepare asm stub */
9654ecbe6fSMasami Hiramatsu unsigned long rethook_trampoline_handler(struct pt_regs *regs,
9754ecbe6fSMasami Hiramatsu 					 unsigned long frame);
9854ecbe6fSMasami Hiramatsu 
9954ecbe6fSMasami Hiramatsu #ifdef CONFIG_RETHOOK
10054ecbe6fSMasami Hiramatsu void rethook_flush_task(struct task_struct *tk);
10154ecbe6fSMasami Hiramatsu #else
10254ecbe6fSMasami Hiramatsu #define rethook_flush_task(tsk)	do { } while (0)
10354ecbe6fSMasami Hiramatsu #endif
10454ecbe6fSMasami Hiramatsu 
10554ecbe6fSMasami Hiramatsu #endif
10654ecbe6fSMasami Hiramatsu 
107