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