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