OSDN Git Service

fprobe: Ensure running fprobe_exit_handler() finished before calling rethook_free()
[tomoyo/tomoyo-test1.git] / kernel / trace / fprobe.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * fprobe - Simple ftrace probe wrapper for function entry.
4  */
5 #define pr_fmt(fmt) "fprobe: " fmt
6
7 #include <linux/err.h>
8 #include <linux/fprobe.h>
9 #include <linux/kallsyms.h>
10 #include <linux/kprobes.h>
11 #include <linux/rethook.h>
12 #include <linux/slab.h>
13 #include <linux/sort.h>
14
15 #include "trace.h"
16
17 struct fprobe_rethook_node {
18         struct rethook_node node;
19         unsigned long entry_ip;
20         unsigned long entry_parent_ip;
21         char data[];
22 };
23
24 static inline void __fprobe_handler(unsigned long ip, unsigned long parent_ip,
25                         struct ftrace_ops *ops, struct ftrace_regs *fregs)
26 {
27         struct fprobe_rethook_node *fpr;
28         struct rethook_node *rh = NULL;
29         struct fprobe *fp;
30         void *entry_data = NULL;
31         int ret = 0;
32
33         fp = container_of(ops, struct fprobe, ops);
34
35         if (fp->exit_handler) {
36                 rh = rethook_try_get(fp->rethook);
37                 if (!rh) {
38                         fp->nmissed++;
39                         return;
40                 }
41                 fpr = container_of(rh, struct fprobe_rethook_node, node);
42                 fpr->entry_ip = ip;
43                 fpr->entry_parent_ip = parent_ip;
44                 if (fp->entry_data_size)
45                         entry_data = fpr->data;
46         }
47
48         if (fp->entry_handler)
49                 ret = fp->entry_handler(fp, ip, ftrace_get_regs(fregs), entry_data);
50
51         /* If entry_handler returns !0, nmissed is not counted. */
52         if (rh) {
53                 if (ret)
54                         rethook_recycle(rh);
55                 else
56                         rethook_hook(rh, ftrace_get_regs(fregs), true);
57         }
58 }
59
60 static void fprobe_handler(unsigned long ip, unsigned long parent_ip,
61                 struct ftrace_ops *ops, struct ftrace_regs *fregs)
62 {
63         struct fprobe *fp;
64         int bit;
65
66         fp = container_of(ops, struct fprobe, ops);
67         if (fprobe_disabled(fp))
68                 return;
69
70         /* recursion detection has to go before any traceable function and
71          * all functions before this point should be marked as notrace
72          */
73         bit = ftrace_test_recursion_trylock(ip, parent_ip);
74         if (bit < 0) {
75                 fp->nmissed++;
76                 return;
77         }
78         __fprobe_handler(ip, parent_ip, ops, fregs);
79         ftrace_test_recursion_unlock(bit);
80
81 }
82 NOKPROBE_SYMBOL(fprobe_handler);
83
84 static void fprobe_kprobe_handler(unsigned long ip, unsigned long parent_ip,
85                                   struct ftrace_ops *ops, struct ftrace_regs *fregs)
86 {
87         struct fprobe *fp;
88         int bit;
89
90         fp = container_of(ops, struct fprobe, ops);
91         if (fprobe_disabled(fp))
92                 return;
93
94         /* recursion detection has to go before any traceable function and
95          * all functions called before this point should be marked as notrace
96          */
97         bit = ftrace_test_recursion_trylock(ip, parent_ip);
98         if (bit < 0) {
99                 fp->nmissed++;
100                 return;
101         }
102
103         if (unlikely(kprobe_running())) {
104                 fp->nmissed++;
105                 goto recursion_unlock;
106         }
107
108         kprobe_busy_begin();
109         __fprobe_handler(ip, parent_ip, ops, fregs);
110         kprobe_busy_end();
111
112 recursion_unlock:
113         ftrace_test_recursion_unlock(bit);
114 }
115
116 static void fprobe_exit_handler(struct rethook_node *rh, void *data,
117                                 struct pt_regs *regs)
118 {
119         struct fprobe *fp = (struct fprobe *)data;
120         struct fprobe_rethook_node *fpr;
121         int bit;
122
123         if (!fp || fprobe_disabled(fp))
124                 return;
125
126         fpr = container_of(rh, struct fprobe_rethook_node, node);
127
128         /*
129          * we need to assure no calls to traceable functions in-between the
130          * end of fprobe_handler and the beginning of fprobe_exit_handler.
131          */
132         bit = ftrace_test_recursion_trylock(fpr->entry_ip, fpr->entry_parent_ip);
133         if (bit < 0) {
134                 fp->nmissed++;
135                 return;
136         }
137
138         fp->exit_handler(fp, fpr->entry_ip, regs,
139                          fp->entry_data_size ? (void *)fpr->data : NULL);
140         ftrace_test_recursion_unlock(bit);
141 }
142 NOKPROBE_SYMBOL(fprobe_exit_handler);
143
144 static int symbols_cmp(const void *a, const void *b)
145 {
146         const char **str_a = (const char **) a;
147         const char **str_b = (const char **) b;
148
149         return strcmp(*str_a, *str_b);
150 }
151
152 /* Convert ftrace location address from symbols */
153 static unsigned long *get_ftrace_locations(const char **syms, int num)
154 {
155         unsigned long *addrs;
156
157         /* Convert symbols to symbol address */
158         addrs = kcalloc(num, sizeof(*addrs), GFP_KERNEL);
159         if (!addrs)
160                 return ERR_PTR(-ENOMEM);
161
162         /* ftrace_lookup_symbols expects sorted symbols */
163         sort(syms, num, sizeof(*syms), symbols_cmp, NULL);
164
165         if (!ftrace_lookup_symbols(syms, num, addrs))
166                 return addrs;
167
168         kfree(addrs);
169         return ERR_PTR(-ENOENT);
170 }
171
172 static void fprobe_init(struct fprobe *fp)
173 {
174         fp->nmissed = 0;
175         if (fprobe_shared_with_kprobes(fp))
176                 fp->ops.func = fprobe_kprobe_handler;
177         else
178                 fp->ops.func = fprobe_handler;
179         fp->ops.flags |= FTRACE_OPS_FL_SAVE_REGS;
180 }
181
182 static int fprobe_init_rethook(struct fprobe *fp, int num)
183 {
184         int i, size;
185
186         if (num < 0)
187                 return -EINVAL;
188
189         if (!fp->exit_handler) {
190                 fp->rethook = NULL;
191                 return 0;
192         }
193
194         /* Initialize rethook if needed */
195         if (fp->nr_maxactive)
196                 size = fp->nr_maxactive;
197         else
198                 size = num * num_possible_cpus() * 2;
199         if (size < 0)
200                 return -E2BIG;
201
202         fp->rethook = rethook_alloc((void *)fp, fprobe_exit_handler);
203         if (!fp->rethook)
204                 return -ENOMEM;
205         for (i = 0; i < size; i++) {
206                 struct fprobe_rethook_node *node;
207
208                 node = kzalloc(sizeof(*node) + fp->entry_data_size, GFP_KERNEL);
209                 if (!node) {
210                         rethook_free(fp->rethook);
211                         fp->rethook = NULL;
212                         return -ENOMEM;
213                 }
214                 rethook_add_node(fp->rethook, &node->node);
215         }
216         return 0;
217 }
218
219 static void fprobe_fail_cleanup(struct fprobe *fp)
220 {
221         if (fp->rethook) {
222                 /* Don't need to cleanup rethook->handler because this is not used. */
223                 rethook_free(fp->rethook);
224                 fp->rethook = NULL;
225         }
226         ftrace_free_filter(&fp->ops);
227 }
228
229 /**
230  * register_fprobe() - Register fprobe to ftrace by pattern.
231  * @fp: A fprobe data structure to be registered.
232  * @filter: A wildcard pattern of probed symbols.
233  * @notfilter: A wildcard pattern of NOT probed symbols.
234  *
235  * Register @fp to ftrace for enabling the probe on the symbols matched to @filter.
236  * If @notfilter is not NULL, the symbols matched the @notfilter are not probed.
237  *
238  * Return 0 if @fp is registered successfully, -errno if not.
239  */
240 int register_fprobe(struct fprobe *fp, const char *filter, const char *notfilter)
241 {
242         struct ftrace_hash *hash;
243         unsigned char *str;
244         int ret, len;
245
246         if (!fp || !filter)
247                 return -EINVAL;
248
249         fprobe_init(fp);
250
251         len = strlen(filter);
252         str = kstrdup(filter, GFP_KERNEL);
253         ret = ftrace_set_filter(&fp->ops, str, len, 0);
254         kfree(str);
255         if (ret)
256                 return ret;
257
258         if (notfilter) {
259                 len = strlen(notfilter);
260                 str = kstrdup(notfilter, GFP_KERNEL);
261                 ret = ftrace_set_notrace(&fp->ops, str, len, 0);
262                 kfree(str);
263                 if (ret)
264                         goto out;
265         }
266
267         /* TODO:
268          * correctly calculate the total number of filtered symbols
269          * from both filter and notfilter.
270          */
271         hash = rcu_access_pointer(fp->ops.local_hash.filter_hash);
272         if (WARN_ON_ONCE(!hash))
273                 goto out;
274
275         ret = fprobe_init_rethook(fp, (int)hash->count);
276         if (!ret)
277                 ret = register_ftrace_function(&fp->ops);
278
279 out:
280         if (ret)
281                 fprobe_fail_cleanup(fp);
282         return ret;
283 }
284 EXPORT_SYMBOL_GPL(register_fprobe);
285
286 /**
287  * register_fprobe_ips() - Register fprobe to ftrace by address.
288  * @fp: A fprobe data structure to be registered.
289  * @addrs: An array of target ftrace location addresses.
290  * @num: The number of entries of @addrs.
291  *
292  * Register @fp to ftrace for enabling the probe on the address given by @addrs.
293  * The @addrs must be the addresses of ftrace location address, which may be
294  * the symbol address + arch-dependent offset.
295  * If you unsure what this mean, please use other registration functions.
296  *
297  * Return 0 if @fp is registered successfully, -errno if not.
298  */
299 int register_fprobe_ips(struct fprobe *fp, unsigned long *addrs, int num)
300 {
301         int ret;
302
303         if (!fp || !addrs || num <= 0)
304                 return -EINVAL;
305
306         fprobe_init(fp);
307
308         ret = ftrace_set_filter_ips(&fp->ops, addrs, num, 0, 0);
309         if (ret)
310                 return ret;
311
312         ret = fprobe_init_rethook(fp, num);
313         if (!ret)
314                 ret = register_ftrace_function(&fp->ops);
315
316         if (ret)
317                 fprobe_fail_cleanup(fp);
318         return ret;
319 }
320 EXPORT_SYMBOL_GPL(register_fprobe_ips);
321
322 /**
323  * register_fprobe_syms() - Register fprobe to ftrace by symbols.
324  * @fp: A fprobe data structure to be registered.
325  * @syms: An array of target symbols.
326  * @num: The number of entries of @syms.
327  *
328  * Register @fp to the symbols given by @syms array. This will be useful if
329  * you are sure the symbols exist in the kernel.
330  *
331  * Return 0 if @fp is registered successfully, -errno if not.
332  */
333 int register_fprobe_syms(struct fprobe *fp, const char **syms, int num)
334 {
335         unsigned long *addrs;
336         int ret;
337
338         if (!fp || !syms || num <= 0)
339                 return -EINVAL;
340
341         addrs = get_ftrace_locations(syms, num);
342         if (IS_ERR(addrs))
343                 return PTR_ERR(addrs);
344
345         ret = register_fprobe_ips(fp, addrs, num);
346
347         kfree(addrs);
348
349         return ret;
350 }
351 EXPORT_SYMBOL_GPL(register_fprobe_syms);
352
353 /**
354  * unregister_fprobe() - Unregister fprobe from ftrace
355  * @fp: A fprobe data structure to be unregistered.
356  *
357  * Unregister fprobe (and remove ftrace hooks from the function entries).
358  *
359  * Return 0 if @fp is unregistered successfully, -errno if not.
360  */
361 int unregister_fprobe(struct fprobe *fp)
362 {
363         int ret;
364
365         if (!fp || (fp->ops.saved_func != fprobe_handler &&
366                     fp->ops.saved_func != fprobe_kprobe_handler))
367                 return -EINVAL;
368
369         if (fp->rethook)
370                 rethook_stop(fp->rethook);
371
372         ret = unregister_ftrace_function(&fp->ops);
373         if (ret < 0)
374                 return ret;
375
376         if (fp->rethook)
377                 rethook_free(fp->rethook);
378
379         ftrace_free_filter(&fp->ops);
380
381         return ret;
382 }
383 EXPORT_SYMBOL_GPL(unregister_fprobe);