implement syscall mask getter
[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 <linux/in.h>
29 #include <linux/in6.h>
30 #include <linux/seq_file.h>
31 #include <asm/ptrace.h>
32 #include <asm/syscall.h>
33
34 #include "lib/bitfield.h"
35 #include "wrapper/tracepoint.h"
36 #include "lttng-events.h"
37
38 #ifndef CONFIG_COMPAT
39 # ifndef is_compat_task
40 # define is_compat_task() (0)
41 # endif
42 #endif
43
44 enum sc_type {
45 SC_TYPE_ENTRY,
46 SC_TYPE_EXIT,
47 SC_TYPE_COMPAT_ENTRY,
48 SC_TYPE_COMPAT_EXIT,
49 };
50
51 #define SYSCALL_ENTRY_STR "syscall_entry_"
52 #define COMPAT_SYSCALL_ENTRY_STR "compat_syscall_entry_"
53 #define SYSCALL_EXIT_STR "syscall_exit_"
54 #define COMPAT_SYSCALL_EXIT_STR "compat_syscall_exit_"
55
56 static
57 void syscall_entry_probe(void *__data, struct pt_regs *regs, long id);
58 static
59 void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret);
60
61 /*
62 * Forward declarations for old kernels.
63 */
64 struct mmsghdr;
65 struct rlimit64;
66 struct oldold_utsname;
67 struct old_utsname;
68 struct sel_arg_struct;
69 struct mmap_arg_struct;
70
71 #ifdef IA32_NR_syscalls
72 #define NR_compat_syscalls IA32_NR_syscalls
73 #else
74 #define NR_compat_syscalls NR_syscalls
75 #endif
76
77 /*
78 * Create LTTng tracepoint probes.
79 */
80 #define LTTNG_PACKAGE_BUILD
81 #define CREATE_TRACE_POINTS
82 #define TP_MODULE_NOINIT
83 #define TRACE_INCLUDE_PATH ../instrumentation/syscalls/headers
84
85 #define PARAMS(args...) args
86
87 /* Handle unknown syscalls */
88 #define TRACE_SYSTEM syscalls_unknown
89 #include "instrumentation/syscalls/headers/syscalls_unknown.h"
90 #undef TRACE_SYSTEM
91
92 #define SC_ENTER
93
94 #undef sc_exit
95 #define sc_exit(...)
96 #undef sc_in
97 #define sc_in(...) __VA_ARGS__
98 #undef sc_out
99 #define sc_out(...)
100 #undef sc_inout
101 #define sc_inout(...) __VA_ARGS__
102
103 /* Hijack probe callback for system call enter */
104 #undef TP_PROBE_CB
105 #define TP_PROBE_CB(_template) &syscall_entry_probe
106 #define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
107 LTTNG_TRACEPOINT_EVENT(syscall_enter_##_name, PARAMS(_proto), PARAMS(_args), \
108 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
109 #define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _struct, _assign, _printk) \
110 LTTNG_TRACEPOINT_EVENT_CODE(syscall_enter_##_name, PARAMS(_proto), PARAMS(_args), \
111 PARAMS(_locvar), PARAMS(_code), \
112 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
113 #define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
114 LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(syscall_enter_##_name, PARAMS(_struct), PARAMS(_assign), \
115 PARAMS(_printk))
116 #define SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(_template, _name) \
117 LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(syscall_enter_##_template, syscall_enter_##_name)
118 #undef TRACE_SYSTEM
119 #define TRACE_SYSTEM syscall_enter_integers
120 #define TRACE_INCLUDE_FILE syscalls_integers
121 #include "instrumentation/syscalls/headers/syscalls_integers.h"
122 #undef TRACE_INCLUDE_FILE
123 #undef TRACE_SYSTEM
124 #define TRACE_SYSTEM syscall_enter_pointers
125 #define TRACE_INCLUDE_FILE syscalls_pointers
126 #include "instrumentation/syscalls/headers/syscalls_pointers.h"
127 #undef TRACE_INCLUDE_FILE
128 #undef TRACE_SYSTEM
129 #undef SC_LTTNG_TRACEPOINT_EVENT_CODE
130 #undef SC_LTTNG_TRACEPOINT_EVENT
131 #undef SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS
132 #undef SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS
133 #undef TP_PROBE_CB
134 #undef _TRACE_SYSCALLS_INTEGERS_H
135 #undef _TRACE_SYSCALLS_POINTERS_H
136
137 /* Hijack probe callback for compat system call enter */
138 #define TP_PROBE_CB(_template) &syscall_entry_probe
139 #define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
140 LTTNG_TRACEPOINT_EVENT(compat_syscall_enter_##_name, PARAMS(_proto), PARAMS(_args), \
141 PARAMS(_struct), PARAMS(_assign), \
142 PARAMS(_printk))
143 #define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _struct, _assign, _printk) \
144 LTTNG_TRACEPOINT_EVENT_CODE(compat_syscall_enter_##_name, PARAMS(_proto), PARAMS(_args), \
145 PARAMS(_locvar), PARAMS(_code), \
146 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
147 #define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
148 LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(compat_syscall_enter_##_name, PARAMS(_struct), \
149 PARAMS(_assign), PARAMS(_printk))
150 #define SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(_template, _name) \
151 LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(compat_syscall_enter_##_template, \
152 compat_syscall_enter_##_name)
153 #define TRACE_SYSTEM compat_syscall_enter_integers
154 #define TRACE_INCLUDE_FILE compat_syscalls_integers
155 #include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
156 #undef TRACE_INCLUDE_FILE
157 #undef TRACE_SYSTEM
158 #define TRACE_SYSTEM compat_syscall_enter_pointers
159 #define TRACE_INCLUDE_FILE compat_syscalls_pointers
160 #include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
161 #undef TRACE_INCLUDE_FILE
162 #undef TRACE_SYSTEM
163 #undef SC_LTTNG_TRACEPOINT_EVENT_CODE
164 #undef SC_LTTNG_TRACEPOINT_EVENT
165 #undef SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS
166 #undef SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS
167 #undef TP_PROBE_CB
168 #undef _TRACE_SYSCALLS_INTEGERS_H
169 #undef _TRACE_SYSCALLS_POINTERS_H
170
171 #undef SC_ENTER
172
173 #define SC_EXIT
174
175 #undef sc_exit
176 #define sc_exit(...) __VA_ARGS__
177 #undef sc_in
178 #define sc_in(...)
179 #undef sc_out
180 #define sc_out(...) __VA_ARGS__
181 #undef sc_inout
182 #define sc_inout(...) __VA_ARGS__
183
184 /* Hijack probe callback for system call exit */
185 #define TP_PROBE_CB(_template) &syscall_exit_probe
186 #define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
187 LTTNG_TRACEPOINT_EVENT(syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \
188 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
189 #define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _struct, _assign, _printk) \
190 LTTNG_TRACEPOINT_EVENT_CODE(syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \
191 PARAMS(_locvar), PARAMS(_code), \
192 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
193 #define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
194 LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(syscall_exit_##_name, PARAMS(_struct), \
195 PARAMS(_assign), PARAMS(_printk))
196 #define SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(_template, _name) \
197 LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(syscall_exit_##_template, \
198 syscall_exit_##_name)
199 #define TRACE_SYSTEM syscall_exit_integers
200 #define TRACE_INCLUDE_FILE syscalls_integers
201 #include "instrumentation/syscalls/headers/syscalls_integers.h"
202 #undef TRACE_INCLUDE_FILE
203 #undef TRACE_SYSTEM
204 #define TRACE_SYSTEM syscall_exit_pointers
205 #define TRACE_INCLUDE_FILE syscalls_pointers
206 #include "instrumentation/syscalls/headers/syscalls_pointers.h"
207 #undef TRACE_INCLUDE_FILE
208 #undef TRACE_SYSTEM
209 #undef SC_LTTNG_TRACEPOINT_EVENT_CODE
210 #undef SC_LTTNG_TRACEPOINT_EVENT
211 #undef SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS
212 #undef SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS
213 #undef TP_PROBE_CB
214 #undef _TRACE_SYSCALLS_INTEGERS_H
215 #undef _TRACE_SYSCALLS_POINTERS_H
216
217
218 /* Hijack probe callback for compat system call exit */
219 #define TP_PROBE_CB(_template) &syscall_exit_probe
220 #define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
221 LTTNG_TRACEPOINT_EVENT(compat_syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \
222 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
223 #define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code, _struct, _assign, _printk) \
224 LTTNG_TRACEPOINT_EVENT_CODE(compat_syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \
225 PARAMS(_locvar), PARAMS(_code), \
226 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
227 #define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
228 LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(compat_syscall_exit_##_name, PARAMS(_struct), \
229 PARAMS(_assign), PARAMS(_printk))
230 #define SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(_template, _name) \
231 LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(compat_syscall_exit_##_template, \
232 compat_syscall_exit_##_name)
233 #define TRACE_SYSTEM compat_syscall_exit_integers
234 #define TRACE_INCLUDE_FILE compat_syscalls_integers
235 #include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
236 #undef TRACE_INCLUDE_FILE
237 #undef TRACE_SYSTEM
238 #define TRACE_SYSTEM compat_syscall_exit_pointers
239 #define TRACE_INCLUDE_FILE compat_syscalls_pointers
240 #include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
241 #undef TRACE_INCLUDE_FILE
242 #undef TRACE_SYSTEM
243 #undef SC_LTTNG_TRACEPOINT_EVENT_CODE
244 #undef SC_LTTNG_TRACEPOINT_EVENT
245 #undef SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS
246 #undef SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS
247 #undef TP_PROBE_CB
248 #undef _TRACE_SYSCALLS_INTEGERS_H
249 #undef _TRACE_SYSCALLS_POINTERS_H
250
251 #undef SC_EXIT
252
253 #undef TP_MODULE_NOINIT
254 #undef LTTNG_PACKAGE_BUILD
255 #undef CREATE_TRACE_POINTS
256
257 struct trace_syscall_entry {
258 void *func;
259 const struct lttng_event_desc *desc;
260 const struct lttng_event_field *fields;
261 unsigned int nrargs;
262 };
263
264 #define CREATE_SYSCALL_TABLE
265
266 #define SC_ENTER
267
268 #undef sc_exit
269 #define sc_exit(...)
270
271 #undef TRACE_SYSCALL_TABLE
272 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
273 [ _nr ] = { \
274 .func = __event_probe__syscall_enter_##_template, \
275 .nrargs = (_nrargs), \
276 .fields = __event_fields___syscall_enter_##_template, \
277 .desc = &__event_desc___syscall_enter_##_name, \
278 },
279
280 /* Syscall enter tracing table */
281 static const struct trace_syscall_entry sc_table[] = {
282 #include "instrumentation/syscalls/headers/syscalls_integers.h"
283 #include "instrumentation/syscalls/headers/syscalls_pointers.h"
284 };
285
286 #undef TRACE_SYSCALL_TABLE
287 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
288 [ _nr ] = { \
289 .func = __event_probe__compat_syscall_enter_##_template, \
290 .nrargs = (_nrargs), \
291 .fields = __event_fields___compat_syscall_enter_##_template, \
292 .desc = &__event_desc___compat_syscall_enter_##_name, \
293 },
294
295 /* Compat syscall enter table */
296 const struct trace_syscall_entry compat_sc_table[] = {
297 #include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
298 #include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
299 };
300
301 #undef SC_ENTER
302
303 #define SC_EXIT
304
305 #undef sc_exit
306 #define sc_exit(...) __VA_ARGS__
307
308 #undef TRACE_SYSCALL_TABLE
309 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
310 [ _nr ] = { \
311 .func = __event_probe__syscall_exit_##_template, \
312 .nrargs = (_nrargs), \
313 .fields = __event_fields___syscall_exit_##_template, \
314 .desc = &__event_desc___syscall_exit_##_name, \
315 },
316
317 /* Syscall exit table */
318 static const struct trace_syscall_entry sc_exit_table[] = {
319 #include "instrumentation/syscalls/headers/syscalls_integers.h"
320 #include "instrumentation/syscalls/headers/syscalls_pointers.h"
321 };
322
323 #undef TRACE_SYSCALL_TABLE
324 #define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
325 [ _nr ] = { \
326 .func = __event_probe__compat_syscall_exit_##_template, \
327 .nrargs = (_nrargs), \
328 .fields = __event_fields___compat_syscall_exit_##_template, \
329 .desc = &__event_desc___compat_syscall_exit_##_name, \
330 },
331
332 /* Compat syscall exit table */
333 const struct trace_syscall_entry compat_sc_exit_table[] = {
334 #include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
335 #include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
336 };
337
338 #undef SC_EXIT
339
340 #undef CREATE_SYSCALL_TABLE
341
342 struct lttng_syscall_filter {
343 DECLARE_BITMAP(sc, NR_syscalls);
344 DECLARE_BITMAP(sc_compat, NR_compat_syscalls);
345 };
346
347 static void syscall_entry_unknown(struct lttng_event *event,
348 struct pt_regs *regs, unsigned int id)
349 {
350 unsigned long args[UNKNOWN_SYSCALL_NRARGS];
351
352 syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args);
353 if (unlikely(is_compat_task()))
354 __event_probe__compat_syscall_enter_unknown(event, id, args);
355 else
356 __event_probe__syscall_enter_unknown(event, id, args);
357 }
358
359 void syscall_entry_probe(void *__data, struct pt_regs *regs, long id)
360 {
361 struct lttng_channel *chan = __data;
362 struct lttng_event *event, *unknown_event;
363 const struct trace_syscall_entry *table, *entry;
364 size_t table_len;
365
366 if (unlikely(is_compat_task())) {
367 struct lttng_syscall_filter *filter;
368
369 filter = rcu_dereference(chan->sc_filter);
370 if (filter) {
371 if (id >= NR_compat_syscalls
372 || !test_bit(id, filter->sc_compat)) {
373 /* System call filtered out. */
374 return;
375 }
376 }
377 table = compat_sc_table;
378 table_len = ARRAY_SIZE(compat_sc_table);
379 unknown_event = chan->sc_compat_unknown;
380 } else {
381 struct lttng_syscall_filter *filter;
382
383 filter = rcu_dereference(chan->sc_filter);
384 if (filter) {
385 if (id >= NR_syscalls
386 || !test_bit(id, filter->sc)) {
387 /* System call filtered out. */
388 return;
389 }
390 }
391 table = sc_table;
392 table_len = ARRAY_SIZE(sc_table);
393 unknown_event = chan->sc_unknown;
394 }
395 if (unlikely(id >= table_len)) {
396 syscall_entry_unknown(unknown_event, regs, id);
397 return;
398 }
399 if (unlikely(is_compat_task()))
400 event = chan->compat_sc_table[id];
401 else
402 event = chan->sc_table[id];
403 if (unlikely(!event)) {
404 syscall_entry_unknown(unknown_event, regs, id);
405 return;
406 }
407 entry = &table[id];
408 WARN_ON_ONCE(!entry);
409
410 switch (entry->nrargs) {
411 case 0:
412 {
413 void (*fptr)(void *__data) = entry->func;
414
415 fptr(event);
416 break;
417 }
418 case 1:
419 {
420 void (*fptr)(void *__data, unsigned long arg0) = entry->func;
421 unsigned long args[1];
422
423 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
424 fptr(event, args[0]);
425 break;
426 }
427 case 2:
428 {
429 void (*fptr)(void *__data,
430 unsigned long arg0,
431 unsigned long arg1) = entry->func;
432 unsigned long args[2];
433
434 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
435 fptr(event, args[0], args[1]);
436 break;
437 }
438 case 3:
439 {
440 void (*fptr)(void *__data,
441 unsigned long arg0,
442 unsigned long arg1,
443 unsigned long arg2) = entry->func;
444 unsigned long args[3];
445
446 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
447 fptr(event, args[0], args[1], args[2]);
448 break;
449 }
450 case 4:
451 {
452 void (*fptr)(void *__data,
453 unsigned long arg0,
454 unsigned long arg1,
455 unsigned long arg2,
456 unsigned long arg3) = entry->func;
457 unsigned long args[4];
458
459 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
460 fptr(event, args[0], args[1], args[2], args[3]);
461 break;
462 }
463 case 5:
464 {
465 void (*fptr)(void *__data,
466 unsigned long arg0,
467 unsigned long arg1,
468 unsigned long arg2,
469 unsigned long arg3,
470 unsigned long arg4) = entry->func;
471 unsigned long args[5];
472
473 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
474 fptr(event, args[0], args[1], args[2], args[3], args[4]);
475 break;
476 }
477 case 6:
478 {
479 void (*fptr)(void *__data,
480 unsigned long arg0,
481 unsigned long arg1,
482 unsigned long arg2,
483 unsigned long arg3,
484 unsigned long arg4,
485 unsigned long arg5) = entry->func;
486 unsigned long args[6];
487
488 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
489 fptr(event, args[0], args[1], args[2],
490 args[3], args[4], args[5]);
491 break;
492 }
493 default:
494 break;
495 }
496 }
497
498 static void syscall_exit_unknown(struct lttng_event *event,
499 struct pt_regs *regs, unsigned int id, long ret)
500 {
501 unsigned long args[UNKNOWN_SYSCALL_NRARGS];
502
503 syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args);
504 if (unlikely(is_compat_task()))
505 __event_probe__compat_syscall_exit_unknown(event, id, ret,
506 args);
507 else
508 __event_probe__syscall_exit_unknown(event, id, ret, args);
509 }
510
511 void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret)
512 {
513 struct lttng_channel *chan = __data;
514 struct lttng_event *event, *unknown_event;
515 const struct trace_syscall_entry *table, *entry;
516 size_t table_len;
517 long id;
518
519 id = syscall_get_nr(current, regs);
520 if (unlikely(is_compat_task())) {
521 struct lttng_syscall_filter *filter;
522
523 filter = rcu_dereference(chan->sc_filter);
524 if (filter) {
525 if (id >= NR_compat_syscalls
526 || !test_bit(id, filter->sc_compat)) {
527 /* System call filtered out. */
528 return;
529 }
530 }
531 table = compat_sc_exit_table;
532 table_len = ARRAY_SIZE(compat_sc_exit_table);
533 unknown_event = chan->compat_sc_exit_unknown;
534 } else {
535 struct lttng_syscall_filter *filter;
536
537 filter = rcu_dereference(chan->sc_filter);
538 if (filter) {
539 if (id >= NR_syscalls
540 || !test_bit(id, filter->sc)) {
541 /* System call filtered out. */
542 return;
543 }
544 }
545 table = sc_exit_table;
546 table_len = ARRAY_SIZE(sc_exit_table);
547 unknown_event = chan->sc_exit_unknown;
548 }
549 if (unlikely(id >= table_len)) {
550 syscall_exit_unknown(unknown_event, regs, id, ret);
551 return;
552 }
553 if (unlikely(is_compat_task()))
554 event = chan->compat_sc_exit_table[id];
555 else
556 event = chan->sc_exit_table[id];
557 if (unlikely(!event)) {
558 syscall_exit_unknown(unknown_event, regs, id, ret);
559 return;
560 }
561 entry = &table[id];
562 WARN_ON_ONCE(!entry);
563
564 switch (entry->nrargs) {
565 case 0:
566 {
567 void (*fptr)(void *__data, long ret) = entry->func;
568
569 fptr(event, ret);
570 break;
571 }
572 case 1:
573 {
574 void (*fptr)(void *__data,
575 long ret,
576 unsigned long arg0) = entry->func;
577 unsigned long args[1];
578
579 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
580 fptr(event, ret, args[0]);
581 break;
582 }
583 case 2:
584 {
585 void (*fptr)(void *__data,
586 long ret,
587 unsigned long arg0,
588 unsigned long arg1) = entry->func;
589 unsigned long args[2];
590
591 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
592 fptr(event, ret, args[0], args[1]);
593 break;
594 }
595 case 3:
596 {
597 void (*fptr)(void *__data,
598 long ret,
599 unsigned long arg0,
600 unsigned long arg1,
601 unsigned long arg2) = entry->func;
602 unsigned long args[3];
603
604 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
605 fptr(event, ret, args[0], args[1], args[2]);
606 break;
607 }
608 case 4:
609 {
610 void (*fptr)(void *__data,
611 long ret,
612 unsigned long arg0,
613 unsigned long arg1,
614 unsigned long arg2,
615 unsigned long arg3) = entry->func;
616 unsigned long args[4];
617
618 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
619 fptr(event, ret, args[0], args[1], args[2], args[3]);
620 break;
621 }
622 case 5:
623 {
624 void (*fptr)(void *__data,
625 long ret,
626 unsigned long arg0,
627 unsigned long arg1,
628 unsigned long arg2,
629 unsigned long arg3,
630 unsigned long arg4) = entry->func;
631 unsigned long args[5];
632
633 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
634 fptr(event, ret, args[0], args[1], args[2], args[3], args[4]);
635 break;
636 }
637 case 6:
638 {
639 void (*fptr)(void *__data,
640 long ret,
641 unsigned long arg0,
642 unsigned long arg1,
643 unsigned long arg2,
644 unsigned long arg3,
645 unsigned long arg4,
646 unsigned long arg5) = entry->func;
647 unsigned long args[6];
648
649 syscall_get_arguments(current, regs, 0, entry->nrargs, args);
650 fptr(event, ret, args[0], args[1], args[2],
651 args[3], args[4], args[5]);
652 break;
653 }
654 default:
655 break;
656 }
657 }
658
659 /* noinline to diminish caller stack size */
660 static
661 int fill_table(const struct trace_syscall_entry *table, size_t table_len,
662 struct lttng_event **chan_table, struct lttng_channel *chan,
663 void *filter, enum sc_type type)
664 {
665 const struct lttng_event_desc *desc;
666 unsigned int i;
667
668 /* Allocate events for each syscall, insert into table */
669 for (i = 0; i < table_len; i++) {
670 struct lttng_kernel_event ev;
671 desc = table[i].desc;
672
673 if (!desc) {
674 /* Unknown syscall */
675 continue;
676 }
677 /*
678 * Skip those already populated by previous failed
679 * register for this channel.
680 */
681 if (chan_table[i])
682 continue;
683 memset(&ev, 0, sizeof(ev));
684 switch (type) {
685 case SC_TYPE_ENTRY:
686 strncpy(ev.name, SYSCALL_ENTRY_STR,
687 LTTNG_KERNEL_SYM_NAME_LEN);
688 break;
689 case SC_TYPE_EXIT:
690 strncpy(ev.name, SYSCALL_EXIT_STR,
691 LTTNG_KERNEL_SYM_NAME_LEN);
692 break;
693 case SC_TYPE_COMPAT_ENTRY:
694 strncpy(ev.name, COMPAT_SYSCALL_ENTRY_STR,
695 LTTNG_KERNEL_SYM_NAME_LEN);
696 break;
697 case SC_TYPE_COMPAT_EXIT:
698 strncpy(ev.name, COMPAT_SYSCALL_EXIT_STR,
699 LTTNG_KERNEL_SYM_NAME_LEN);
700 break;
701 default:
702 BUG_ON(1);
703 break;
704 }
705 strncat(ev.name, desc->name,
706 LTTNG_KERNEL_SYM_NAME_LEN - strlen(ev.name) - 1);
707 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
708 ev.instrumentation = LTTNG_KERNEL_NOOP;
709 chan_table[i] = lttng_event_create(chan, &ev, filter,
710 desc);
711 WARN_ON_ONCE(!chan_table[i]);
712 if (IS_ERR(chan_table[i])) {
713 /*
714 * If something goes wrong in event registration
715 * after the first one, we have no choice but to
716 * leave the previous events in there, until
717 * deleted by session teardown.
718 */
719 return PTR_ERR(chan_table[i]);
720 }
721 }
722 return 0;
723 }
724
725 int lttng_syscalls_register(struct lttng_channel *chan, void *filter)
726 {
727 struct lttng_kernel_event ev;
728 int ret;
729
730 wrapper_vmalloc_sync_all();
731
732 if (!chan->sc_table) {
733 /* create syscall table mapping syscall to events */
734 chan->sc_table = kzalloc(sizeof(struct lttng_event *)
735 * ARRAY_SIZE(sc_table), GFP_KERNEL);
736 if (!chan->sc_table)
737 return -ENOMEM;
738 }
739 if (!chan->sc_exit_table) {
740 /* create syscall table mapping syscall to events */
741 chan->sc_exit_table = kzalloc(sizeof(struct lttng_event *)
742 * ARRAY_SIZE(sc_exit_table), GFP_KERNEL);
743 if (!chan->sc_exit_table)
744 return -ENOMEM;
745 }
746
747
748 #ifdef CONFIG_COMPAT
749 if (!chan->compat_sc_table) {
750 /* create syscall table mapping compat syscall to events */
751 chan->compat_sc_table = kzalloc(sizeof(struct lttng_event *)
752 * ARRAY_SIZE(compat_sc_table), GFP_KERNEL);
753 if (!chan->compat_sc_table)
754 return -ENOMEM;
755 }
756
757 if (!chan->compat_sc_exit_table) {
758 /* create syscall table mapping compat syscall to events */
759 chan->compat_sc_exit_table = kzalloc(sizeof(struct lttng_event *)
760 * ARRAY_SIZE(compat_sc_exit_table), GFP_KERNEL);
761 if (!chan->compat_sc_exit_table)
762 return -ENOMEM;
763 }
764 #endif
765 if (!chan->sc_unknown) {
766 const struct lttng_event_desc *desc =
767 &__event_desc___syscall_enter_unknown;
768
769 memset(&ev, 0, sizeof(ev));
770 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
771 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
772 ev.instrumentation = LTTNG_KERNEL_NOOP;
773 chan->sc_unknown = lttng_event_create(chan, &ev, filter,
774 desc);
775 WARN_ON_ONCE(!chan->sc_unknown);
776 if (IS_ERR(chan->sc_unknown)) {
777 return PTR_ERR(chan->sc_unknown);
778 }
779 }
780
781 if (!chan->sc_compat_unknown) {
782 const struct lttng_event_desc *desc =
783 &__event_desc___compat_syscall_enter_unknown;
784
785 memset(&ev, 0, sizeof(ev));
786 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
787 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
788 ev.instrumentation = LTTNG_KERNEL_NOOP;
789 chan->sc_compat_unknown = lttng_event_create(chan, &ev, filter,
790 desc);
791 WARN_ON_ONCE(!chan->sc_unknown);
792 if (IS_ERR(chan->sc_compat_unknown)) {
793 return PTR_ERR(chan->sc_compat_unknown);
794 }
795 }
796
797 if (!chan->compat_sc_exit_unknown) {
798 const struct lttng_event_desc *desc =
799 &__event_desc___compat_syscall_exit_unknown;
800
801 memset(&ev, 0, sizeof(ev));
802 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
803 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
804 ev.instrumentation = LTTNG_KERNEL_NOOP;
805 chan->compat_sc_exit_unknown = lttng_event_create(chan, &ev,
806 filter, desc);
807 WARN_ON_ONCE(!chan->compat_sc_exit_unknown);
808 if (IS_ERR(chan->compat_sc_exit_unknown)) {
809 return PTR_ERR(chan->compat_sc_exit_unknown);
810 }
811 }
812
813 if (!chan->sc_exit_unknown) {
814 const struct lttng_event_desc *desc =
815 &__event_desc___syscall_exit_unknown;
816
817 memset(&ev, 0, sizeof(ev));
818 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
819 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
820 ev.instrumentation = LTTNG_KERNEL_NOOP;
821 chan->sc_exit_unknown = lttng_event_create(chan, &ev, filter,
822 desc);
823 WARN_ON_ONCE(!chan->sc_exit_unknown);
824 if (IS_ERR(chan->sc_exit_unknown)) {
825 return PTR_ERR(chan->sc_exit_unknown);
826 }
827 }
828
829 ret = fill_table(sc_table, ARRAY_SIZE(sc_table),
830 chan->sc_table, chan, filter, SC_TYPE_ENTRY);
831 if (ret)
832 return ret;
833 ret = fill_table(sc_exit_table, ARRAY_SIZE(sc_exit_table),
834 chan->sc_exit_table, chan, filter, SC_TYPE_EXIT);
835 if (ret)
836 return ret;
837
838 #ifdef CONFIG_COMPAT
839 ret = fill_table(compat_sc_table, ARRAY_SIZE(compat_sc_table),
840 chan->compat_sc_table, chan, filter,
841 SC_TYPE_COMPAT_ENTRY);
842 if (ret)
843 return ret;
844 ret = fill_table(compat_sc_exit_table, ARRAY_SIZE(compat_sc_exit_table),
845 chan->compat_sc_exit_table, chan, filter,
846 SC_TYPE_COMPAT_EXIT);
847 if (ret)
848 return ret;
849 #endif
850 if (!chan->sys_enter_registered) {
851 ret = lttng_wrapper_tracepoint_probe_register("sys_enter",
852 (void *) syscall_entry_probe, chan);
853 if (ret)
854 return ret;
855 chan->sys_enter_registered = 1;
856 }
857 /*
858 * We change the name of sys_exit tracepoint due to namespace
859 * conflict with sys_exit syscall entry.
860 */
861 if (!chan->sys_exit_registered) {
862 ret = lttng_wrapper_tracepoint_probe_register("sys_exit",
863 (void *) syscall_exit_probe, chan);
864 if (ret) {
865 WARN_ON_ONCE(lttng_wrapper_tracepoint_probe_unregister("sys_enter",
866 (void *) syscall_entry_probe, chan));
867 return ret;
868 }
869 chan->sys_exit_registered = 1;
870 }
871 return ret;
872 }
873
874 /*
875 * Only called at session destruction.
876 */
877 int lttng_syscalls_unregister(struct lttng_channel *chan)
878 {
879 int ret;
880
881 if (!chan->sc_table)
882 return 0;
883 if (chan->sys_enter_registered) {
884 ret = lttng_wrapper_tracepoint_probe_unregister("sys_exit",
885 (void *) syscall_exit_probe, chan);
886 if (ret)
887 return ret;
888 chan->sys_enter_registered = 0;
889 }
890 if (chan->sys_exit_registered) {
891 ret = lttng_wrapper_tracepoint_probe_unregister("sys_enter",
892 (void *) syscall_entry_probe, chan);
893 if (ret)
894 return ret;
895 chan->sys_exit_registered = 0;
896 }
897 /* lttng_event destroy will be performed by lttng_session_destroy() */
898 kfree(chan->sc_table);
899 kfree(chan->sc_exit_table);
900 #ifdef CONFIG_COMPAT
901 kfree(chan->compat_sc_table);
902 kfree(chan->compat_sc_exit_table);
903 #endif
904 kfree(chan->sc_filter);
905 return 0;
906 }
907
908 static
909 int get_syscall_nr(const char *syscall_name)
910 {
911 int syscall_nr = -1;
912 int i;
913
914 for (i = 0; i < ARRAY_SIZE(sc_table); i++) {
915 const struct trace_syscall_entry *entry;
916 const char *it_name;
917
918 entry = &sc_table[i];
919 if (!entry->desc)
920 continue;
921 it_name = entry->desc->name;
922 it_name += strlen(SYSCALL_ENTRY_STR);
923 if (!strcmp(syscall_name, it_name)) {
924 syscall_nr = i;
925 break;
926 }
927 }
928 return syscall_nr;
929 }
930
931 static
932 int get_compat_syscall_nr(const char *syscall_name)
933 {
934 int syscall_nr = -1;
935 int i;
936
937 for (i = 0; i < ARRAY_SIZE(compat_sc_table); i++) {
938 const struct trace_syscall_entry *entry;
939 const char *it_name;
940
941 entry = &compat_sc_table[i];
942 if (!entry->desc)
943 continue;
944 it_name = entry->desc->name;
945 it_name += strlen(COMPAT_SYSCALL_ENTRY_STR);
946 if (!strcmp(syscall_name, it_name)) {
947 syscall_nr = i;
948 break;
949 }
950 }
951 return syscall_nr;
952 }
953
954 static
955 uint32_t get_sc_tables_len(void)
956 {
957 return ARRAY_SIZE(sc_table) + ARRAY_SIZE(compat_sc_table);
958 }
959
960 int lttng_syscall_filter_enable(struct lttng_channel *chan,
961 const char *name)
962 {
963 int syscall_nr, compat_syscall_nr, ret;
964 struct lttng_syscall_filter *filter;
965
966 WARN_ON_ONCE(!chan->sc_table);
967
968 if (!name) {
969 /* Enable all system calls by removing filter */
970 if (chan->sc_filter) {
971 filter = chan->sc_filter;
972 rcu_assign_pointer(chan->sc_filter, NULL);
973 synchronize_trace();
974 kfree(filter);
975 }
976 chan->syscall_all = 1;
977 return 0;
978 }
979
980 if (!chan->sc_filter) {
981 if (chan->syscall_all) {
982 /*
983 * All syscalls are already enabled.
984 */
985 return -EEXIST;
986 }
987 filter = kzalloc(sizeof(struct lttng_syscall_filter),
988 GFP_KERNEL);
989 if (!filter)
990 return -ENOMEM;
991 } else {
992 filter = chan->sc_filter;
993 }
994 syscall_nr = get_syscall_nr(name);
995 compat_syscall_nr = get_compat_syscall_nr(name);
996 if (syscall_nr < 0 && compat_syscall_nr < 0) {
997 ret = -ENOENT;
998 goto error;
999 }
1000 if (syscall_nr >= 0) {
1001 if (test_bit(syscall_nr, filter->sc)) {
1002 ret = -EEXIST;
1003 goto error;
1004 }
1005 bitmap_set(filter->sc, syscall_nr, 1);
1006 }
1007 if (compat_syscall_nr >= 0) {
1008 if (test_bit(compat_syscall_nr, filter->sc_compat)) {
1009 ret = -EEXIST;
1010 goto error;
1011 }
1012 bitmap_set(filter->sc_compat, compat_syscall_nr, 1);
1013 }
1014 if (!chan->sc_filter)
1015 rcu_assign_pointer(chan->sc_filter, filter);
1016 return 0;
1017
1018 error:
1019 if (!chan->sc_filter)
1020 kfree(filter);
1021 return ret;
1022 }
1023
1024 int lttng_syscall_filter_disable(struct lttng_channel *chan,
1025 const char *name)
1026 {
1027 int syscall_nr, compat_syscall_nr, ret;
1028 struct lttng_syscall_filter *filter;
1029
1030 WARN_ON_ONCE(!chan->sc_table);
1031
1032 if (!chan->sc_filter) {
1033 filter = kzalloc(sizeof(struct lttng_syscall_filter),
1034 GFP_KERNEL);
1035 if (!filter)
1036 return -ENOMEM;
1037 /* Trace all system calls, then apply disable. */
1038 bitmap_set(filter->sc, 0, NR_syscalls);
1039 bitmap_set(filter->sc_compat, 0, NR_compat_syscalls);
1040 } else {
1041 filter = chan->sc_filter;
1042 }
1043
1044 if (!name) {
1045 /* Disable all system calls */
1046 bitmap_clear(filter->sc, 0, NR_syscalls);
1047 bitmap_clear(filter->sc_compat, 0, NR_compat_syscalls);
1048 goto apply_filter;
1049 }
1050 syscall_nr = get_syscall_nr(name);
1051 compat_syscall_nr = get_compat_syscall_nr(name);
1052 if (syscall_nr < 0 && compat_syscall_nr < 0) {
1053 ret = -ENOENT;
1054 goto error;
1055 }
1056 if (syscall_nr >= 0) {
1057 if (!test_bit(syscall_nr, chan->sc_filter->sc)) {
1058 ret = -EEXIST;
1059 goto error;
1060 }
1061 bitmap_clear(chan->sc_filter->sc, syscall_nr, 1);
1062 }
1063 if (compat_syscall_nr >= 0) {
1064 if (!test_bit(compat_syscall_nr, chan->sc_filter->sc_compat)) {
1065 ret = -EEXIST;
1066 goto error;
1067 }
1068 bitmap_clear(chan->sc_filter->sc_compat, compat_syscall_nr, 1);
1069 }
1070 apply_filter:
1071 if (!chan->sc_filter)
1072 rcu_assign_pointer(chan->sc_filter, filter);
1073 chan->syscall_all = 0;
1074 return 0;
1075
1076 error:
1077 if (!chan->sc_filter)
1078 kfree(filter);
1079 return ret;
1080 }
1081
1082 static
1083 const struct trace_syscall_entry *syscall_list_get_entry(loff_t *pos)
1084 {
1085 const struct trace_syscall_entry *entry;
1086 int iter = 0;
1087
1088 for (entry = sc_table;
1089 entry < sc_table + ARRAY_SIZE(sc_table);
1090 entry++) {
1091 if (iter++ >= *pos)
1092 return entry;
1093 }
1094 for (entry = compat_sc_table;
1095 entry < compat_sc_table + ARRAY_SIZE(compat_sc_table);
1096 entry++) {
1097 if (iter++ >= *pos)
1098 return entry;
1099 }
1100 /* End of list */
1101 return NULL;
1102 }
1103
1104 static
1105 void *syscall_list_start(struct seq_file *m, loff_t *pos)
1106 {
1107 return (void *) syscall_list_get_entry(pos);
1108 }
1109
1110 static
1111 void *syscall_list_next(struct seq_file *m, void *p, loff_t *ppos)
1112 {
1113 (*ppos)++;
1114 return (void *) syscall_list_get_entry(ppos);
1115 }
1116
1117 static
1118 void syscall_list_stop(struct seq_file *m, void *p)
1119 {
1120 }
1121
1122 static
1123 int get_sc_table(const struct trace_syscall_entry *entry,
1124 const struct trace_syscall_entry **table,
1125 unsigned int *bitness)
1126 {
1127 if (entry >= sc_table && entry < sc_table + ARRAY_SIZE(sc_table)) {
1128 if (bitness)
1129 *bitness = BITS_PER_LONG;
1130 if (table)
1131 *table = sc_table;
1132 return 0;
1133 }
1134 if (!(entry >= compat_sc_table
1135 && entry < compat_sc_table + ARRAY_SIZE(compat_sc_table))) {
1136 return -EINVAL;
1137 }
1138 if (bitness)
1139 *bitness = 32;
1140 if (table)
1141 *table = compat_sc_table;
1142 return 0;
1143 }
1144
1145 static
1146 int syscall_list_show(struct seq_file *m, void *p)
1147 {
1148 const struct trace_syscall_entry *table, *entry = p;
1149 unsigned int bitness;
1150 int ret;
1151
1152 ret = get_sc_table(entry, &table, &bitness);
1153 if (ret)
1154 return ret;
1155 seq_printf(m, "syscall { index = %lu; name = %s; bitness = %u; };\n",
1156 entry - table,
1157 entry->desc->name,
1158 bitness);
1159 return 0;
1160 }
1161
1162 static
1163 const struct seq_operations lttng_syscall_list_seq_ops = {
1164 .start = syscall_list_start,
1165 .next = syscall_list_next,
1166 .stop = syscall_list_stop,
1167 .show = syscall_list_show,
1168 };
1169
1170 static
1171 int lttng_syscall_list_open(struct inode *inode, struct file *file)
1172 {
1173 return seq_open(file, &lttng_syscall_list_seq_ops);
1174 }
1175
1176 const struct file_operations lttng_syscall_list_fops = {
1177 .owner = THIS_MODULE,
1178 .open = lttng_syscall_list_open,
1179 .read = seq_read,
1180 .llseek = seq_lseek,
1181 .release = seq_release,
1182 };
1183
1184 long lttng_channel_syscall_mask(struct lttng_channel *channel,
1185 struct lttng_kernel_syscall_mask __user *usyscall_mask)
1186 {
1187 uint32_t len, sc_tables_len, bitmask_len;
1188 int ret = 0, bit;
1189 char *tmp_mask;
1190 struct lttng_syscall_filter *filter;
1191
1192 ret = get_user(len, &usyscall_mask->len);
1193 if (ret)
1194 return ret;
1195 sc_tables_len = get_sc_tables_len();
1196 bitmask_len = ALIGN(sc_tables_len, 8) >> 3;
1197 if (len < sc_tables_len) {
1198 return put_user(sc_tables_len, &usyscall_mask->len);
1199 }
1200 /* Array is large enough, we can copy array to user-space. */
1201 tmp_mask = kzalloc(bitmask_len, GFP_KERNEL);
1202 if (!tmp_mask)
1203 return -ENOMEM;
1204 filter = channel->sc_filter;
1205
1206 for (bit = 0; bit < ARRAY_SIZE(sc_table); bit++) {
1207 bt_bitfield_write_be(tmp_mask, char, bit, 1,
1208 test_bit(bit, filter->sc));
1209 }
1210 for (; bit < sc_tables_len; bit++) {
1211 bt_bitfield_write_be(tmp_mask, char, bit, 1,
1212 test_bit(bit - ARRAY_SIZE(sc_table),
1213 filter->sc_compat));
1214 }
1215 if (copy_to_user(usyscall_mask->mask, tmp_mask, bitmask_len))
1216 ret = -EFAULT;
1217 kfree(tmp_mask);
1218 return ret;
1219 }
This page took 0.063093 seconds and 5 git commands to generate.