0001
0002
0003 #define pr_fmt(fmt) "rethook: " fmt
0004
0005 #include <linux/bug.h>
0006 #include <linux/kallsyms.h>
0007 #include <linux/kprobes.h>
0008 #include <linux/preempt.h>
0009 #include <linux/rethook.h>
0010 #include <linux/slab.h>
0011 #include <linux/sort.h>
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 void rethook_flush_task(struct task_struct *tk)
0022 {
0023 struct rethook_node *rhn;
0024 struct llist_node *node;
0025
0026 node = __llist_del_all(&tk->rethooks);
0027 while (node) {
0028 rhn = container_of(node, struct rethook_node, llist);
0029 node = node->next;
0030 preempt_disable();
0031 rethook_recycle(rhn);
0032 preempt_enable();
0033 }
0034 }
0035
0036 static void rethook_free_rcu(struct rcu_head *head)
0037 {
0038 struct rethook *rh = container_of(head, struct rethook, rcu);
0039 struct rethook_node *rhn;
0040 struct freelist_node *node;
0041 int count = 1;
0042
0043 node = rh->pool.head;
0044 while (node) {
0045 rhn = container_of(node, struct rethook_node, freelist);
0046 node = node->next;
0047 kfree(rhn);
0048 count++;
0049 }
0050
0051
0052 if (refcount_sub_and_test(count, &rh->ref))
0053 kfree(rh);
0054 }
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066 void rethook_free(struct rethook *rh)
0067 {
0068 WRITE_ONCE(rh->handler, NULL);
0069
0070 call_rcu(&rh->rcu, rethook_free_rcu);
0071 }
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082 struct rethook *rethook_alloc(void *data, rethook_handler_t handler)
0083 {
0084 struct rethook *rh = kzalloc(sizeof(struct rethook), GFP_KERNEL);
0085
0086 if (!rh || !handler)
0087 return NULL;
0088
0089 rh->data = data;
0090 rh->handler = handler;
0091 rh->pool.head = NULL;
0092 refcount_set(&rh->ref, 1);
0093
0094 return rh;
0095 }
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105 void rethook_add_node(struct rethook *rh, struct rethook_node *node)
0106 {
0107 node->rethook = rh;
0108 freelist_add(&node->freelist, &rh->pool);
0109 refcount_inc(&rh->ref);
0110 }
0111
0112 static void free_rethook_node_rcu(struct rcu_head *head)
0113 {
0114 struct rethook_node *node = container_of(head, struct rethook_node, rcu);
0115
0116 if (refcount_dec_and_test(&node->rethook->ref))
0117 kfree(node->rethook);
0118 kfree(node);
0119 }
0120
0121
0122
0123
0124
0125
0126
0127
0128 void rethook_recycle(struct rethook_node *node)
0129 {
0130 lockdep_assert_preemption_disabled();
0131
0132 if (likely(READ_ONCE(node->rethook->handler)))
0133 freelist_add(&node->freelist, &node->rethook->pool);
0134 else
0135 call_rcu(&node->rcu, free_rethook_node_rcu);
0136 }
0137 NOKPROBE_SYMBOL(rethook_recycle);
0138
0139
0140
0141
0142
0143
0144
0145
0146 struct rethook_node *rethook_try_get(struct rethook *rh)
0147 {
0148 rethook_handler_t handler = READ_ONCE(rh->handler);
0149 struct freelist_node *fn;
0150
0151 lockdep_assert_preemption_disabled();
0152
0153
0154 if (unlikely(!handler))
0155 return NULL;
0156
0157
0158
0159
0160
0161
0162
0163 if (unlikely(!rcu_is_watching()))
0164 return NULL;
0165
0166 fn = freelist_try_get(&rh->pool);
0167 if (!fn)
0168 return NULL;
0169
0170 return container_of(fn, struct rethook_node, freelist);
0171 }
0172 NOKPROBE_SYMBOL(rethook_try_get);
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187 void rethook_hook(struct rethook_node *node, struct pt_regs *regs, bool mcount)
0188 {
0189 arch_rethook_prepare(node, regs, mcount);
0190 __llist_add(&node->llist, ¤t->rethooks);
0191 }
0192 NOKPROBE_SYMBOL(rethook_hook);
0193
0194
0195 static unsigned long __rethook_find_ret_addr(struct task_struct *tsk,
0196 struct llist_node **cur)
0197 {
0198 struct rethook_node *rh = NULL;
0199 struct llist_node *node = *cur;
0200
0201 if (!node)
0202 node = tsk->rethooks.first;
0203 else
0204 node = node->next;
0205
0206 while (node) {
0207 rh = container_of(node, struct rethook_node, llist);
0208 if (rh->ret_addr != (unsigned long)arch_rethook_trampoline) {
0209 *cur = node;
0210 return rh->ret_addr;
0211 }
0212 node = node->next;
0213 }
0214 return 0;
0215 }
0216 NOKPROBE_SYMBOL(__rethook_find_ret_addr);
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234 unsigned long rethook_find_ret_addr(struct task_struct *tsk, unsigned long frame,
0235 struct llist_node **cur)
0236 {
0237 struct rethook_node *rhn = NULL;
0238 unsigned long ret;
0239
0240 if (WARN_ON_ONCE(!cur))
0241 return 0;
0242
0243 if (WARN_ON_ONCE(tsk != current && task_is_running(tsk)))
0244 return 0;
0245
0246 do {
0247 ret = __rethook_find_ret_addr(tsk, cur);
0248 if (!ret)
0249 break;
0250 rhn = container_of(*cur, struct rethook_node, llist);
0251 } while (rhn->frame != frame);
0252
0253 return ret;
0254 }
0255 NOKPROBE_SYMBOL(rethook_find_ret_addr);
0256
0257 void __weak arch_rethook_fixup_return(struct pt_regs *regs,
0258 unsigned long correct_ret_addr)
0259 {
0260
0261
0262
0263
0264
0265
0266 }
0267
0268
0269 unsigned long rethook_trampoline_handler(struct pt_regs *regs,
0270 unsigned long frame)
0271 {
0272 struct llist_node *first, *node = NULL;
0273 unsigned long correct_ret_addr;
0274 rethook_handler_t handler;
0275 struct rethook_node *rhn;
0276
0277 correct_ret_addr = __rethook_find_ret_addr(current, &node);
0278 if (!correct_ret_addr) {
0279 pr_err("rethook: Return address not found! Maybe there is a bug in the kernel\n");
0280 BUG_ON(1);
0281 }
0282
0283 instruction_pointer_set(regs, correct_ret_addr);
0284
0285
0286
0287
0288
0289 preempt_disable();
0290
0291
0292
0293
0294
0295 first = current->rethooks.first;
0296 while (first) {
0297 rhn = container_of(first, struct rethook_node, llist);
0298 if (WARN_ON_ONCE(rhn->frame != frame))
0299 break;
0300 handler = READ_ONCE(rhn->rethook->handler);
0301 if (handler)
0302 handler(rhn, rhn->rethook->data, regs);
0303
0304 if (first == node)
0305 break;
0306 first = first->next;
0307 }
0308
0309
0310 arch_rethook_fixup_return(regs, correct_ret_addr);
0311
0312
0313 first = current->rethooks.first;
0314 current->rethooks.first = node->next;
0315 node->next = NULL;
0316
0317 while (first) {
0318 rhn = container_of(first, struct rethook_node, llist);
0319 first = first->next;
0320 rethook_recycle(rhn);
0321 }
0322 preempt_enable();
0323
0324 return correct_ret_addr;
0325 }
0326 NOKPROBE_SYMBOL(rethook_trampoline_handler);