Syscall filtering: apply to syscall exit
[lttng-modules.git] / lttng-syscalls.c
1 /*
2 * lttng-syscalls.c
3 *
4 * LTTng syscall probes.
5 *
6 * Copyright (C) 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; only
11 * version 2.1 of the License.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include <linux/module.h>
24 #include <linux/slab.h>
25 #include <linux/compat.h>
26 #include <linux/err.h>
27 #include <linux/bitmap.h>
28 #include <asm/ptrace.h>
29 #include <asm/syscall.h>
30
31 #include "wrapper/tracepoint.h"
32 #include "lttng-events.h"
33
34 #ifndef CONFIG_COMPAT
35 # ifndef is_compat_task
36 # define is_compat_task() (0)
37 # endif
38 #endif
39
40 enum sc_type {
41 SC_TYPE_ENTRY,
42 SC_TYPE_EXIT,
43 SC_TYPE_COMPAT_ENTRY,
44 SC_TYPE_COMPAT_EXIT,
45 };
46
47 #define SYSCALL_ENTRY_STR "syscall_entry_"
48 #define COMPAT_SYSCALL_ENTRY_STR "compat_syscall_entry_"
49 #define SYSCALL_EXIT_STR "syscall_exit_"
50 #define COMPAT_SYSCALL_EXIT_STR "compat_syscall_exit_"
51
52 static
53 void syscall_entry_probe(void *__data, struct pt_regs *regs, long id);
54 static
55 void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret);
56
57 /*
58 * Forward declarations for old kernels.
59 */
60 struct mmsghdr;
61 struct rlimit64;
62 struct oldold_utsname;
63 struct old_utsname;
64 struct sel_arg_struct;
65 struct mmap_arg_struct;
66
67 #ifdef IA32_NR_syscalls
68 #define NR_compat_syscalls IA32_NR_syscalls
69 #else
70 #define NR_compat_syscalls NR_syscalls
71 #endif
72
73 /*
74 * Take care of NOARGS not supported by mainline.
75 */
76 #define DECLARE_EVENT_CLASS_NOARGS(name, tstruct, assign, print)
77 #define DEFINE_EVENT_NOARGS(template, name)
78 #define TRACE_EVENT_NOARGS(name, struct, assign, print)
79
80 /*
81 * Create LTTng tracepoint probes.
82 */
83 #define LTTNG_PACKAGE_BUILD
84 #define CREATE_TRACE_POINTS
85 #define TP_MODULE_NOINIT
86 #define TRACE_INCLUDE_PATH ../instrumentation/syscalls/headers
87
88 #define PARAMS(args...) args
89
90 /* Handle unknown syscalls */
91 #define TRACE_SYSTEM syscalls_unknown
92 #include "instrumentation/syscalls/headers/syscalls_unknown.h"
93 #undef TRACE_SYSTEM
94
95
96 /* Hijack probe callback for system call enter */
97 #undef TP_PROBE_CB
98 #define TP_PROBE_CB(_template) &syscall_entry_probe
99 #define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
100 TRACE_EVENT(syscall_enter_##_name, PARAMS(_proto), PARAMS(_args),\
101 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
102 #define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
103 DECLARE_EVENT_CLASS_NOARGS(syscall_enter_##_name, PARAMS(_struct), PARAMS(_assign),\
104 PARAMS(_printk))
105 #define SC_DEFINE_EVENT_NOARGS(_template, _name) \
106 DEFINE_EVENT_NOARGS(syscall_enter_##_template, syscall_enter_##_name)
107 #undef TRACE_SYSTEM
108 #define TRACE_SYSTEM syscall_enter_integers
109 #define TRACE_INCLUDE_FILE syscalls_integers
110 #include "instrumentation/syscalls/headers/syscalls_integers.h"
111 #undef TRACE_INCLUDE_FILE
112 #undef TRACE_SYSTEM
113 #define TRACE_SYSTEM syscall_enter_pointers
114 #define TRACE_INCLUDE_FILE syscalls_pointers
115 #include "instrumentation/syscalls/headers/syscalls_pointers.h"
116 #undef TRACE_INCLUDE_FILE
117 #undef TRACE_SYSTEM
118 #undef SC_TRACE_EVENT
119 #undef SC_DECLARE_EVENT_CLASS_NOARGS
120 #undef SC_DEFINE_EVENT_NOARGS
121 #undef TP_PROBE_CB
122 #undef _TRACE_SYSCALLS_integers_H
123 #undef _TRACE_SYSCALLS_pointers_H
124
125
126 /* Hijack probe callback for compat system call enter */
127 #define TP_PROBE_CB(_template) &syscall_entry_probe
128 #define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
129 TRACE_EVENT(compat_syscall_enter_##_name, PARAMS(_proto), PARAMS(_args), \
130 PARAMS(_struct), PARAMS(_assign), \
131 PARAMS(_printk))
132 #define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
133 DECLARE_EVENT_CLASS_NOARGS(compat_syscall_enter_##_name, PARAMS(_struct), \
134 PARAMS(_assign), PARAMS(_printk))
135 #define SC_DEFINE_EVENT_NOARGS(_template, _name) \
136 DEFINE_EVENT_NOARGS(compat_syscall_enter_##_template, \
137 compat_syscall_enter_##_name)
138 #define TRACE_SYSTEM compat_syscall_enter_integers
139 #define TRACE_INCLUDE_FILE compat_syscalls_integers
140 #include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
141 #undef TRACE_INCLUDE_FILE
142 #undef TRACE_SYSTEM
143 #define TRACE_SYSTEM compat_syscall_enter_pointers
144 #define TRACE_INCLUDE_FILE compat_syscalls_pointers
145 #include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
146 #undef TRACE_INCLUDE_FILE
147 #undef TRACE_SYSTEM
148 #undef SC_TRACE_EVENT
149 #undef SC_DECLARE_EVENT_CLASS_NOARGS
150 #undef SC_DEFINE_EVENT_NOARGS
151 #undef TP_PROBE_CB
152 #undef _TRACE_SYSCALLS_integers_H
153 #undef _TRACE_SYSCALLS_pointers_H
154
155
156 /* Hijack probe callback for system call exit */
157 #define TP_PROBE_CB(_template) &syscall_exit_probe
158 #define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
159 TRACE_EVENT(syscall_exit_##_name, PARAMS(_proto), PARAMS(_args),\
160 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
161 #define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
162 DECLARE_EVENT_CLASS_NOARGS(syscall_exit_##_name, PARAMS(_struct), \
163 PARAMS(_assign), PARAMS(_printk))
164 #define SC_DEFINE_EVENT_NOARGS(_template, _name) \
165 DEFINE_EVENT_NOARGS(syscall_exit_##_template, \
166 syscall_exit_##_name)
167 #define TRACE_SYSTEM syscall_exit_integers
168 #define TRACE_INCLUDE_FILE syscalls_integers
169 #include "instrumentation/syscalls/headers/syscalls_integers.h"
170 #undef TRACE_INCLUDE_FILE
171 #undef TRACE_SYSTEM
172 #define TRACE_SYSTEM syscall_exit_pointers
173 #define TRACE_INCLUDE_FILE syscalls_pointers
174 #include "instrumentation/syscalls/headers/syscalls_pointers.h"
175 #undef TRACE_INCLUDE_FILE
176 #undef TRACE_SYSTEM
177 #undef SC_TRACE_EVENT
178 #undef SC_DECLARE_EVENT_CLASS_NOARGS
179 #undef SC_DEFINE_EVENT_NOARGS
180 #undef TP_PROBE_CB
181 #undef _TRACE_SYSCALLS_integers_H
182 #undef _TRACE_SYSCALLS_pointers_H
183
184
185 /* Hijack probe callback for compat system call exit */
186 #define TP_PROBE_CB(_template) &syscall_exit_probe
187 #define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
188 TRACE_EVENT(compat_syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \
189 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
190 #define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
191 DECLARE_EVENT_CLASS_NOARGS(compat_syscall_exit_##_name, PARAMS(_struct), \
192 PARAMS(_assign), PARAMS(_printk))
193 #define SC_DEFINE_EVENT_NOARGS(_template, _name) \
194 DEFINE_EVENT_NOARGS(compat_syscall_exit_##_template, \
195 compat_syscall_exit_##_name)
196 #define TRACE_SYSTEM compat_syscall_exit_integers
197 #define TRACE_INCLUDE_FILE compat_syscalls_integers
198 #include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
199 #undef TRACE_INCLUDE_FILE
200 #undef TRACE_SYSTEM
201 #define TRACE_SYSTEM compat_syscall_exit_pointers
202 #define TRACE_INCLUDE_FILE compat_syscalls_pointers
203 #include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
204 #undef TRACE_INCLUDE_FILE
205 #undef TRACE_SYSTEM
206 #undef SC_TRACE_EVENT
207 #undef SC_DECLARE_EVENT_CLASS_NOARGS
208 #undef SC_DEFINE_EVENT_NOARGS
209 #undef TP_PROBE_CB
210 #undef _TRACE_SYSCALLS_integers_H
211 #undef _TRACE_SYSCALLS_pointers_H
212
213
214 #undef TP_MODULE_NOINIT
215 #undef LTTNG_PACKAGE_BUILD
216 #undef CREATE_TRACE_POINTS
217
218 struct trace_syscall_entry {
219 void *func;
220 const struct lttng_event_desc *desc;
221 const struct lttng_event_field *fields;
222 unsigned int nrargs;
223 };
224
225 #define CREATE_SYSCALL_TABLE
226
227 #undef TRACE_SYSCALL_TABLE
228 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
229 [ _nr ] = { \
230 .func = __event_probe__syscall_enter_##_template, \
231 .nrargs = (_nrargs), \
232 .fields = __event_fields___syscall_enter_##_template, \
233 .desc = &__event_desc___syscall_enter_##_name, \
234 },
235
236 /* Syscall enter tracing table */
237 static const struct trace_syscall_entry sc_table[] = {
238 #include "instrumentation/syscalls/headers/syscalls_integers.h"
239 #include "instrumentation/syscalls/headers/syscalls_pointers.h"
240 };
241
242 #undef TRACE_SYSCALL_TABLE
243 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
244 [ _nr ] = { \
245 .func = __event_probe__compat_syscall_enter_##_template, \
246 .nrargs = (_nrargs), \
247 .fields = __event_fields___compat_syscall_enter_##_template, \
248 .desc = &__event_desc___compat_syscall_enter_##_name, \
249 },
250
251 /* Compat syscall enter table */
252 const struct trace_syscall_entry compat_sc_table[] = {
253 #include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
254 #include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
255 };
256
257 #undef TRACE_SYSCALL_TABLE
258 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
259 [ _nr ] = { \
260 .func = __event_probe__syscall_exit_##_template, \
261 .nrargs = (_nrargs), \
262 .fields = __event_fields___syscall_exit_##_template, \
263 .desc = &__event_desc___syscall_exit_##_name, \
264 },
265
266 /* Syscall exit table */
267 static const struct trace_syscall_entry sc_exit_table[] = {
268 #include "instrumentation/syscalls/headers/syscalls_integers.h"
269 #include "instrumentation/syscalls/headers/syscalls_pointers.h"
270 };
271
272 #undef TRACE_SYSCALL_TABLE
273 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
274 [ _nr ] = { \
275 .func = __event_probe__compat_syscall_exit_##_template, \
276 .nrargs = (_nrargs), \
277 .fields = __event_fields___compat_syscall_exit_##_template, \
278 .desc = &__event_desc___compat_syscall_exit_##_name, \
279 },
280
281 /* Compat syscall exit table */
282 const struct trace_syscall_entry compat_sc_exit_table[] = {
283 #include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
284 #include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
285 };
286
287 #undef CREATE_SYSCALL_TABLE
288
289 struct lttng_syscall_filter {
290 DECLARE_BITMAP(sc, NR_syscalls);
291 DECLARE_BITMAP(sc_compat, NR_compat_syscalls);
292 };
293
294 static void syscall_entry_unknown(struct lttng_event *event,
295 struct pt_regs *regs, unsigned int id)
296 {
297 unsigned long args[UNKNOWN_SYSCALL_NRARGS];
298
299 syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args);
300 if (unlikely(is_compat_task()))
301 __event_probe__compat_syscall_enter_unknown(event, id, args);
302 else
303 __event_probe__syscall_enter_unknown(event, id, args);
304 }
305
306 void syscall_entry_probe(void *__data, struct pt_regs *regs, long id)
307 {
308 struct lttng_channel *chan = __data;
309 struct lttng_event *event, *unknown_event;
310 const struct trace_syscall_entry *table, *entry;
311 size_t table_len;
312
313 if (unlikely(is_compat_task())) {
314 struct lttng_syscall_filter *filter;
315
316 filter = rcu_dereference(chan->sc_filter);
317 if (filter) {
318 if (id >= NR_compat_syscalls
319 || !test_bit(id, filter->sc_compat)) {
320 /* System call filtered out. */
321 return;
322 }
323 }
324 table = compat_sc_table;
325 table_len = ARRAY_SIZE(compat_sc_table);
326 unknown_event = chan->sc_compat_unknown;
327 } else {
328 struct lttng_syscall_filter *filter;
329
330 filter = rcu_dereference(chan->sc_filter);
331 if (filter) {
332 if (id >= NR_syscalls
333 || !test_bit(id, filter->sc)) {
334 /* System call filtered out. */
335 return;
336 }
337 }
338 table = sc_table;
339 table_len = ARRAY_SIZE(sc_table);
340 unknown_event = chan->sc_unknown;
341 }
342 if (unlikely(id >= table_len)) {
343 syscall_entry_unknown(unknown_event, regs, id);
344 return;
345 }
346 if (unlikely(is_compat_task()))
347 event = chan->compat_sc_table[id];
348 else
349 event = chan->sc_table[id];
350 if (unlikely(!event)) {
351 syscall_entry_unknown(unknown_event, regs, id);
352 return;
353 }
354 entry = &table[id];
355 WARN_ON_ONCE(!entry);
356
357 switch (entry->nrargs) {
358 case 0:
359 {
360 void (*fptr)(void *__data) = entry->func;
361
362 fptr(event);
363 break;
364 }
365 case 1:
366 {
367 void (*fptr)(void *__data, unsigned long arg0) = entry->func;
368 unsigned long args[1];
369
370 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
371 fptr(event, args[0]);
372 break;
373 }
374 case 2:
375 {
376 void (*fptr)(void *__data,
377 unsigned long arg0,
378 unsigned long arg1) = entry->func;
379 unsigned long args[2];
380
381 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
382 fptr(event, args[0], args[1]);
383 break;
384 }
385 case 3:
386 {
387 void (*fptr)(void *__data,
388 unsigned long arg0,
389 unsigned long arg1,
390 unsigned long arg2) = entry->func;
391 unsigned long args[3];
392
393 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
394 fptr(event, args[0], args[1], args[2]);
395 break;
396 }
397 case 4:
398 {
399 void (*fptr)(void *__data,
400 unsigned long arg0,
401 unsigned long arg1,
402 unsigned long arg2,
403 unsigned long arg3) = entry->func;
404 unsigned long args[4];
405
406 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
407 fptr(event, args[0], args[1], args[2], args[3]);
408 break;
409 }
410 case 5:
411 {
412 void (*fptr)(void *__data,
413 unsigned long arg0,
414 unsigned long arg1,
415 unsigned long arg2,
416 unsigned long arg3,
417 unsigned long arg4) = entry->func;
418 unsigned long args[5];
419
420 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
421 fptr(event, args[0], args[1], args[2], args[3], args[4]);
422 break;
423 }
424 case 6:
425 {
426 void (*fptr)(void *__data,
427 unsigned long arg0,
428 unsigned long arg1,
429 unsigned long arg2,
430 unsigned long arg3,
431 unsigned long arg4,
432 unsigned long arg5) = entry->func;
433 unsigned long args[6];
434
435 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
436 fptr(event, args[0], args[1], args[2],
437 args[3], args[4], args[5]);
438 break;
439 }
440 default:
441 break;
442 }
443 }
444
445 static void syscall_exit_unknown(struct lttng_event *event,
446 struct pt_regs *regs, unsigned int id, long ret)
447 {
448 unsigned long args[UNKNOWN_SYSCALL_NRARGS];
449
450 syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args);
451 if (unlikely(is_compat_task()))
452 __event_probe__compat_syscall_exit_unknown(event, id, ret,
453 args);
454 else
455 __event_probe__syscall_exit_unknown(event, id, ret, args);
456 }
457
458 void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret)
459 {
460 struct lttng_channel *chan = __data;
461 struct lttng_event *event, *unknown_event;
462 const struct trace_syscall_entry *table, *entry;
463 size_t table_len;
464 long id;
465
466 id = syscall_get_nr(current, regs);
467 if (unlikely(is_compat_task())) {
468 struct lttng_syscall_filter *filter;
469
470 filter = rcu_dereference(chan->sc_filter);
471 if (filter) {
472 if (id >= NR_compat_syscalls
473 || !test_bit(id, filter->sc_compat)) {
474 /* System call filtered out. */
475 return;
476 }
477 }
478 table = compat_sc_exit_table;
479 table_len = ARRAY_SIZE(compat_sc_exit_table);
480 unknown_event = chan->compat_sc_exit_unknown;
481 } else {
482 struct lttng_syscall_filter *filter;
483
484 filter = rcu_dereference(chan->sc_filter);
485 if (filter) {
486 if (id >= NR_syscalls
487 || !test_bit(id, filter->sc)) {
488 /* System call filtered out. */
489 return;
490 }
491 }
492 table = sc_exit_table;
493 table_len = ARRAY_SIZE(sc_exit_table);
494 unknown_event = chan->sc_exit_unknown;
495 }
496 if (unlikely(id >= table_len)) {
497 syscall_exit_unknown(unknown_event, regs, id, ret);
498 return;
499 }
500 if (unlikely(is_compat_task()))
501 event = chan->compat_sc_exit_table[id];
502 else
503 event = chan->sc_exit_table[id];
504 if (unlikely(!event)) {
505 syscall_exit_unknown(unknown_event, regs, id, ret);
506 return;
507 }
508 entry = &table[id];
509 WARN_ON_ONCE(!entry);
510
511 switch (entry->nrargs) {
512 case 0:
513 {
514 void (*fptr)(void *__data) = entry->func;
515
516 fptr(event);
517 break;
518 }
519 case 1:
520 {
521 void (*fptr)(void *__data,
522 unsigned long arg0) = entry->func;
523 unsigned long args[1];
524
525 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
526 fptr(event, args[0]);
527 break;
528 }
529 case 2:
530 {
531 void (*fptr)(void *__data,
532 unsigned long arg0,
533 unsigned long arg1) = entry->func;
534 unsigned long args[2];
535
536 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
537 fptr(event, args[0], args[1]);
538 break;
539 }
540 case 3:
541 {
542 void (*fptr)(void *__data,
543 unsigned long arg0,
544 unsigned long arg1,
545 unsigned long arg2) = entry->func;
546 unsigned long args[3];
547
548 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
549 fptr(event, args[0], args[1], args[2]);
550 break;
551 }
552 case 4:
553 {
554 void (*fptr)(void *__data,
555 unsigned long arg0,
556 unsigned long arg1,
557 unsigned long arg2,
558 unsigned long arg3) = entry->func;
559 unsigned long args[4];
560
561 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
562 fptr(event, args[0], args[1], args[2], args[3]);
563 break;
564 }
565 case 5:
566 {
567 void (*fptr)(void *__data,
568 unsigned long arg0,
569 unsigned long arg1,
570 unsigned long arg2,
571 unsigned long arg3,
572 unsigned long arg4) = entry->func;
573 unsigned long args[5];
574
575 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
576 fptr(event, args[0], args[1], args[2], args[3], args[4]);
577 break;
578 }
579 case 6:
580 {
581 void (*fptr)(void *__data,
582 unsigned long arg0,
583 unsigned long arg1,
584 unsigned long arg2,
585 unsigned long arg3,
586 unsigned long arg4,
587 unsigned long arg5) = entry->func;
588 unsigned long args[6];
589
590 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
591 fptr(event, args[0], args[1], args[2],
592 args[3], args[4], args[5]);
593 break;
594 }
595 default:
596 break;
597 }
598 }
599
600 /* noinline to diminish caller stack size */
601 static
602 int fill_table(const struct trace_syscall_entry *table, size_t table_len,
603 struct lttng_event **chan_table, struct lttng_channel *chan,
604 void *filter, enum sc_type type)
605 {
606 const struct lttng_event_desc *desc;
607 unsigned int i;
608
609 /* Allocate events for each syscall, insert into table */
610 for (i = 0; i < table_len; i++) {
611 struct lttng_kernel_event ev;
612 desc = table[i].desc;
613
614 if (!desc) {
615 /* Unknown syscall */
616 continue;
617 }
618 /*
619 * Skip those already populated by previous failed
620 * register for this channel.
621 */
622 if (chan_table[i])
623 continue;
624 memset(&ev, 0, sizeof(ev));
625 switch (type) {
626 case SC_TYPE_ENTRY:
627 strncpy(ev.name, SYSCALL_ENTRY_STR,
628 LTTNG_KERNEL_SYM_NAME_LEN);
629 break;
630 case SC_TYPE_EXIT:
631 strncpy(ev.name, SYSCALL_EXIT_STR,
632 LTTNG_KERNEL_SYM_NAME_LEN);
633 break;
634 case SC_TYPE_COMPAT_ENTRY:
635 strncpy(ev.name, COMPAT_SYSCALL_ENTRY_STR,
636 LTTNG_KERNEL_SYM_NAME_LEN);
637 break;
638 case SC_TYPE_COMPAT_EXIT:
639 strncpy(ev.name, COMPAT_SYSCALL_EXIT_STR,
640 LTTNG_KERNEL_SYM_NAME_LEN);
641 break;
642 default:
643 BUG_ON(1);
644 break;
645 }
646 strncat(ev.name, desc->name,
647 LTTNG_KERNEL_SYM_NAME_LEN - strlen(ev.name) - 1);
648 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
649 ev.instrumentation = LTTNG_KERNEL_NOOP;
650 chan_table[i] = lttng_event_create(chan, &ev, filter,
651 desc);
652 WARN_ON_ONCE(!chan_table[i]);
653 if (IS_ERR(chan_table[i])) {
654 /*
655 * If something goes wrong in event registration
656 * after the first one, we have no choice but to
657 * leave the previous events in there, until
658 * deleted by session teardown.
659 */
660 return PTR_ERR(chan_table[i]);
661 }
662 }
663 return 0;
664 }
665
666 int lttng_syscalls_register(struct lttng_channel *chan, void *filter)
667 {
668 struct lttng_kernel_event ev;
669 int ret;
670
671 wrapper_vmalloc_sync_all();
672
673 if (!chan->sc_table) {
674 /* create syscall table mapping syscall to events */
675 chan->sc_table = kzalloc(sizeof(struct lttng_event *)
676 * ARRAY_SIZE(sc_table), GFP_KERNEL);
677 if (!chan->sc_table)
678 return -ENOMEM;
679 }
680 if (!chan->sc_exit_table) {
681 /* create syscall table mapping syscall to events */
682 chan->sc_exit_table = kzalloc(sizeof(struct lttng_event *)
683 * ARRAY_SIZE(sc_exit_table), GFP_KERNEL);
684 if (!chan->sc_exit_table)
685 return -ENOMEM;
686 }
687
688
689 #ifdef CONFIG_COMPAT
690 if (!chan->compat_sc_table) {
691 /* create syscall table mapping compat syscall to events */
692 chan->compat_sc_table = kzalloc(sizeof(struct lttng_event *)
693 * ARRAY_SIZE(compat_sc_table), GFP_KERNEL);
694 if (!chan->compat_sc_table)
695 return -ENOMEM;
696 }
697
698 if (!chan->compat_sc_exit_table) {
699 /* create syscall table mapping compat syscall to events */
700 chan->compat_sc_exit_table = kzalloc(sizeof(struct lttng_event *)
701 * ARRAY_SIZE(compat_sc_exit_table), GFP_KERNEL);
702 if (!chan->compat_sc_exit_table)
703 return -ENOMEM;
704 }
705 #endif
706 if (!chan->sc_unknown) {
707 const struct lttng_event_desc *desc =
708 &__event_desc___syscall_enter_unknown;
709
710 memset(&ev, 0, sizeof(ev));
711 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
712 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
713 ev.instrumentation = LTTNG_KERNEL_NOOP;
714 chan->sc_unknown = lttng_event_create(chan, &ev, filter,
715 desc);
716 WARN_ON_ONCE(!chan->sc_unknown);
717 if (IS_ERR(chan->sc_unknown)) {
718 return PTR_ERR(chan->sc_unknown);
719 }
720 }
721
722 if (!chan->sc_compat_unknown) {
723 const struct lttng_event_desc *desc =
724 &__event_desc___compat_syscall_enter_unknown;
725
726 memset(&ev, 0, sizeof(ev));
727 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
728 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
729 ev.instrumentation = LTTNG_KERNEL_NOOP;
730 chan->sc_compat_unknown = lttng_event_create(chan, &ev, filter,
731 desc);
732 WARN_ON_ONCE(!chan->sc_unknown);
733 if (IS_ERR(chan->sc_compat_unknown)) {
734 return PTR_ERR(chan->sc_compat_unknown);
735 }
736 }
737
738 if (!chan->compat_sc_exit_unknown) {
739 const struct lttng_event_desc *desc =
740 &__event_desc___compat_syscall_exit_unknown;
741
742 memset(&ev, 0, sizeof(ev));
743 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
744 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
745 ev.instrumentation = LTTNG_KERNEL_NOOP;
746 chan->compat_sc_exit_unknown = lttng_event_create(chan, &ev,
747 filter, desc);
748 WARN_ON_ONCE(!chan->compat_sc_exit_unknown);
749 if (IS_ERR(chan->compat_sc_exit_unknown)) {
750 return PTR_ERR(chan->compat_sc_exit_unknown);
751 }
752 }
753
754 if (!chan->sc_exit_unknown) {
755 const struct lttng_event_desc *desc =
756 &__event_desc___syscall_exit_unknown;
757
758 memset(&ev, 0, sizeof(ev));
759 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
760 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
761 ev.instrumentation = LTTNG_KERNEL_NOOP;
762 chan->sc_exit_unknown = lttng_event_create(chan, &ev, filter,
763 desc);
764 WARN_ON_ONCE(!chan->sc_exit_unknown);
765 if (IS_ERR(chan->sc_exit_unknown)) {
766 return PTR_ERR(chan->sc_exit_unknown);
767 }
768 }
769
770 ret = fill_table(sc_table, ARRAY_SIZE(sc_table),
771 chan->sc_table, chan, filter, SC_TYPE_ENTRY);
772 if (ret)
773 return ret;
774 ret = fill_table(sc_exit_table, ARRAY_SIZE(sc_exit_table),
775 chan->sc_exit_table, chan, filter, SC_TYPE_EXIT);
776 if (ret)
777 return ret;
778
779 #ifdef CONFIG_COMPAT
780 ret = fill_table(compat_sc_table, ARRAY_SIZE(compat_sc_table),
781 chan->compat_sc_table, chan, filter,
782 SC_TYPE_COMPAT_ENTRY);
783 if (ret)
784 return ret;
785 ret = fill_table(compat_sc_exit_table, ARRAY_SIZE(compat_sc_exit_table),
786 chan->compat_sc_exit_table, chan, filter,
787 SC_TYPE_COMPAT_EXIT);
788 if (ret)
789 return ret;
790 #endif
791 if (!chan->sys_enter_registered) {
792 ret = lttng_wrapper_tracepoint_probe_register("sys_enter",
793 (void *) syscall_entry_probe, chan);
794 if (ret)
795 return ret;
796 chan->sys_enter_registered = 1;
797 }
798 /*
799 * We change the name of sys_exit tracepoint due to namespace
800 * conflict with sys_exit syscall entry.
801 */
802 if (!chan->sys_exit_registered) {
803 ret = lttng_wrapper_tracepoint_probe_register("sys_exit",
804 (void *) syscall_exit_probe, chan);
805 if (ret) {
806 WARN_ON_ONCE(lttng_wrapper_tracepoint_probe_unregister("sys_enter",
807 (void *) syscall_entry_probe, chan));
808 return ret;
809 }
810 chan->sys_exit_registered = 1;
811 }
812 return ret;
813 }
814
815 /*
816 * Only called at session destruction.
817 */
818 int lttng_syscalls_unregister(struct lttng_channel *chan)
819 {
820 int ret;
821
822 if (!chan->sc_table)
823 return 0;
824 if (chan->sys_enter_registered) {
825 ret = lttng_wrapper_tracepoint_probe_unregister("sys_exit",
826 (void *) syscall_exit_probe, chan);
827 if (ret)
828 return ret;
829 chan->sys_enter_registered = 0;
830 }
831 if (chan->sys_exit_registered) {
832 ret = lttng_wrapper_tracepoint_probe_unregister("sys_enter",
833 (void *) syscall_entry_probe, chan);
834 if (ret)
835 return ret;
836 chan->sys_exit_registered = 0;
837 }
838 /* lttng_event destroy will be performed by lttng_session_destroy() */
839 kfree(chan->sc_table);
840 kfree(chan->sc_exit_table);
841 #ifdef CONFIG_COMPAT
842 kfree(chan->compat_sc_table);
843 kfree(chan->compat_sc_exit_table);
844 #endif
845 kfree(chan->sc_filter);
846 return 0;
847 }
848
849 static
850 int get_syscall_nr(const char *syscall_name)
851 {
852 int syscall_nr = -1;
853 int i;
854
855 for (i = 0; i < ARRAY_SIZE(sc_table); i++) {
856 const struct trace_syscall_entry *entry;
857 const char *it_name;
858
859 entry = &sc_table[i];
860 if (!entry->desc)
861 continue;
862 it_name = entry->desc->name;
863 it_name += strlen(SYSCALL_ENTRY_STR);
864 if (!strcmp(syscall_name, it_name)) {
865 syscall_nr = i;
866 break;
867 }
868 }
869 return syscall_nr;
870 }
871
872 static
873 int get_compat_syscall_nr(const char *syscall_name)
874 {
875 int syscall_nr = -1;
876 int i;
877
878 for (i = 0; i < ARRAY_SIZE(compat_sc_table); i++) {
879 const struct trace_syscall_entry *entry;
880 const char *it_name;
881
882 entry = &compat_sc_table[i];
883 if (!entry->desc)
884 continue;
885 it_name = entry->desc->name;
886 it_name += strlen(COMPAT_SYSCALL_ENTRY_STR);
887 if (!strcmp(syscall_name, it_name)) {
888 syscall_nr = i;
889 break;
890 }
891 }
892 return syscall_nr;
893 }
894
895 int lttng_syscall_filter_enable(struct lttng_channel *chan,
896 const char *name)
897 {
898 int syscall_nr, compat_syscall_nr, ret;
899 struct lttng_syscall_filter *filter;
900
901 WARN_ON_ONCE(!chan->sc_table);
902
903 if (!name) {
904 /* Enable all system calls by removing filter */
905 if (chan->sc_filter) {
906 filter = chan->sc_filter;
907 rcu_assign_pointer(chan->sc_filter, NULL);
908 synchronize_trace();
909 kfree(filter);
910 }
911 chan->syscall_all = 1;
912 return 0;
913 }
914
915 if (!chan->sc_filter) {
916 if (chan->syscall_all) {
917 /*
918 * All syscalls are already enabled.
919 */
920 return -EEXIST;
921 }
922 filter = kzalloc(sizeof(struct lttng_syscall_filter),
923 GFP_KERNEL);
924 if (!filter)
925 return -ENOMEM;
926 } else {
927 filter = chan->sc_filter;
928 }
929 syscall_nr = get_syscall_nr(name);
930 compat_syscall_nr = get_compat_syscall_nr(name);
931 if (syscall_nr < 0 && compat_syscall_nr < 0) {
932 ret = -ENOENT;
933 goto error;
934 }
935 if (syscall_nr >= 0) {
936 if (test_bit(syscall_nr, filter->sc)) {
937 ret = -EEXIST;
938 goto error;
939 }
940 bitmap_set(filter->sc, syscall_nr, 1);
941 }
942 if (compat_syscall_nr >= 0) {
943 if (test_bit(compat_syscall_nr, filter->sc_compat)) {
944 ret = -EEXIST;
945 goto error;
946 }
947 bitmap_set(filter->sc_compat, compat_syscall_nr, 1);
948 }
949 if (!chan->sc_filter)
950 rcu_assign_pointer(chan->sc_filter, filter);
951 return 0;
952
953 error:
954 if (!chan->sc_filter)
955 kfree(filter);
956 return ret;
957 }
958
959 int lttng_syscall_filter_disable(struct lttng_channel *chan,
960 const char *name)
961 {
962 int syscall_nr, compat_syscall_nr, ret;
963 struct lttng_syscall_filter *filter;
964
965 WARN_ON_ONCE(!chan->sc_table);
966
967 if (!chan->sc_filter) {
968 filter = kzalloc(sizeof(struct lttng_syscall_filter),
969 GFP_KERNEL);
970 if (!filter)
971 return -ENOMEM;
972 /* Trace all system calls, then apply disable. */
973 bitmap_set(filter->sc, 0, NR_syscalls);
974 bitmap_set(filter->sc_compat, 0, NR_compat_syscalls);
975 } else {
976 filter = chan->sc_filter;
977 }
978
979 syscall_nr = get_syscall_nr(name);
980 compat_syscall_nr = get_compat_syscall_nr(name);
981 if (syscall_nr < 0 && compat_syscall_nr < 0) {
982 ret = -ENOENT;
983 goto error;
984 }
985 if (syscall_nr >= 0) {
986 if (!test_bit(syscall_nr, chan->sc_filter->sc)) {
987 ret = -EEXIST;
988 goto error;
989 }
990 bitmap_clear(chan->sc_filter->sc, syscall_nr, 1);
991 }
992 if (compat_syscall_nr >= 0) {
993 if (!test_bit(compat_syscall_nr, chan->sc_filter->sc_compat)) {
994 ret = -EEXIST;
995 goto error;
996 }
997 bitmap_clear(chan->sc_filter->sc_compat, compat_syscall_nr, 1);
998 }
999 if (!chan->sc_filter)
1000 rcu_assign_pointer(chan->sc_filter, filter);
1001 chan->syscall_all = 0;
1002 return 0;
1003
1004 error:
1005 if (!chan->sc_filter)
1006 kfree(filter);
1007 return ret;
1008 }
This page took 0.052736 seconds and 5 git commands to generate.