Syscall filtering: apply to syscall exit
[lttng-modules.git] / lttng-syscalls.c
CommitLineData
259b6cb3
MD
1/*
2 * lttng-syscalls.c
3 *
2faf7d1b 4 * LTTng syscall probes.
259b6cb3 5 *
886d51a3
MD
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
259b6cb3
MD
21 */
22
23#include <linux/module.h>
24#include <linux/slab.h>
6333ace3 25#include <linux/compat.h>
abc0446a 26#include <linux/err.h>
80f87dd2 27#include <linux/bitmap.h>
259b6cb3
MD
28#include <asm/ptrace.h>
29#include <asm/syscall.h>
30
3a523f5b 31#include "wrapper/tracepoint.h"
a90917c3 32#include "lttng-events.h"
259b6cb3 33
6333ace3 34#ifndef CONFIG_COMPAT
bfa949bf
MD
35# ifndef is_compat_task
36# define is_compat_task() (0)
37# endif
6333ace3
MD
38#endif
39
5b7ac358
MD
40enum 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
a93244f8 52static
2faf7d1b 53void syscall_entry_probe(void *__data, struct pt_regs *regs, long id);
5b7ac358
MD
54static
55void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret);
259b6cb3 56
3a523f5b
MD
57/*
58 * Forward declarations for old kernels.
59 */
60struct mmsghdr;
61struct rlimit64;
62struct oldold_utsname;
63struct old_utsname;
64struct sel_arg_struct;
65struct mmap_arg_struct;
66
80f87dd2
MD
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
f7bdf4db
MD
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
259b6cb3
MD
80/*
81 * Create LTTng tracepoint probes.
82 */
83#define LTTNG_PACKAGE_BUILD
84#define CREATE_TRACE_POINTS
2655f9ad 85#define TP_MODULE_NOINIT
2f804c0a 86#define TRACE_INCLUDE_PATH ../instrumentation/syscalls/headers
259b6cb3 87
a93244f8
MD
88#define PARAMS(args...) args
89
5b7ac358
MD
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 */
a93244f8 97#undef TP_PROBE_CB
259b6cb3 98#define TP_PROBE_CB(_template) &syscall_entry_probe
a93244f8 99#define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
5b7ac358 100 TRACE_EVENT(syscall_enter_##_name, PARAMS(_proto), PARAMS(_args),\
a93244f8
MD
101 PARAMS(_struct), PARAMS(_assign), PARAMS(_printk))
102#define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
5b7ac358 103 DECLARE_EVENT_CLASS_NOARGS(syscall_enter_##_name, PARAMS(_struct), PARAMS(_assign),\
a93244f8
MD
104 PARAMS(_printk))
105#define SC_DEFINE_EVENT_NOARGS(_template, _name) \
5b7ac358 106 DEFINE_EVENT_NOARGS(syscall_enter_##_template, syscall_enter_##_name)
a93244f8 107#undef TRACE_SYSTEM
5b7ac358
MD
108#define TRACE_SYSTEM syscall_enter_integers
109#define TRACE_INCLUDE_FILE syscalls_integers
177b3692 110#include "instrumentation/syscalls/headers/syscalls_integers.h"
5b7ac358 111#undef TRACE_INCLUDE_FILE
a93244f8 112#undef TRACE_SYSTEM
5b7ac358
MD
113#define TRACE_SYSTEM syscall_enter_pointers
114#define TRACE_INCLUDE_FILE syscalls_pointers
177b3692 115#include "instrumentation/syscalls/headers/syscalls_pointers.h"
5b7ac358 116#undef TRACE_INCLUDE_FILE
a93244f8
MD
117#undef TRACE_SYSTEM
118#undef SC_TRACE_EVENT
119#undef SC_DECLARE_EVENT_CLASS_NOARGS
120#undef SC_DEFINE_EVENT_NOARGS
5b7ac358 121#undef TP_PROBE_CB
a93244f8
MD
122#undef _TRACE_SYSCALLS_integers_H
123#undef _TRACE_SYSCALLS_pointers_H
124
5b7ac358
MD
125
126/* Hijack probe callback for compat system call enter */
a93244f8
MD
127#define TP_PROBE_CB(_template) &syscall_entry_probe
128#define SC_TRACE_EVENT(_name, _proto, _args, _struct, _assign, _printk) \
5b7ac358 129 TRACE_EVENT(compat_syscall_enter_##_name, PARAMS(_proto), PARAMS(_args), \
a93244f8
MD
130 PARAMS(_struct), PARAMS(_assign), \
131 PARAMS(_printk))
132#define SC_DECLARE_EVENT_CLASS_NOARGS(_name, _struct, _assign, _printk) \
5b7ac358
MD
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), \
a93244f8
MD
192 PARAMS(_assign), PARAMS(_printk))
193#define SC_DEFINE_EVENT_NOARGS(_template, _name) \
5b7ac358
MD
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
a93244f8 198#include "instrumentation/syscalls/headers/compat_syscalls_integers.h"
5b7ac358 199#undef TRACE_INCLUDE_FILE
a93244f8 200#undef TRACE_SYSTEM
5b7ac358
MD
201#define TRACE_SYSTEM compat_syscall_exit_pointers
202#define TRACE_INCLUDE_FILE compat_syscalls_pointers
a93244f8 203#include "instrumentation/syscalls/headers/compat_syscalls_pointers.h"
5b7ac358 204#undef TRACE_INCLUDE_FILE
a93244f8
MD
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
5b7ac358
MD
210#undef _TRACE_SYSCALLS_integers_H
211#undef _TRACE_SYSCALLS_pointers_H
212
259b6cb3 213
2655f9ad 214#undef TP_MODULE_NOINIT
259b6cb3
MD
215#undef LTTNG_PACKAGE_BUILD
216#undef CREATE_TRACE_POINTS
217
a93244f8
MD
218struct 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
259b6cb3 227#undef TRACE_SYSCALL_TABLE
f7bdf4db 228#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
259b6cb3 229 [ _nr ] = { \
5b7ac358 230 .func = __event_probe__syscall_enter_##_template, \
259b6cb3 231 .nrargs = (_nrargs), \
5b7ac358
MD
232 .fields = __event_fields___syscall_enter_##_template, \
233 .desc = &__event_desc___syscall_enter_##_name, \
259b6cb3
MD
234 },
235
5b7ac358 236/* Syscall enter tracing table */
49c50022 237static const struct trace_syscall_entry sc_table[] = {
177b3692
MD
238#include "instrumentation/syscalls/headers/syscalls_integers.h"
239#include "instrumentation/syscalls/headers/syscalls_pointers.h"
259b6cb3
MD
240};
241
a93244f8
MD
242#undef TRACE_SYSCALL_TABLE
243#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
244 [ _nr ] = { \
5b7ac358 245 .func = __event_probe__compat_syscall_enter_##_template, \
a93244f8 246 .nrargs = (_nrargs), \
5b7ac358
MD
247 .fields = __event_fields___compat_syscall_enter_##_template, \
248 .desc = &__event_desc___compat_syscall_enter_##_name, \
a93244f8
MD
249 },
250
5b7ac358 251/* Compat syscall enter table */
a93244f8
MD
252const 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};
259b6cb3 256
5b7ac358
MD
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 */
267static 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 */
282const 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
a93244f8 287#undef CREATE_SYSCALL_TABLE
2faf7d1b 288
80f87dd2
MD
289struct lttng_syscall_filter {
290 DECLARE_BITMAP(sc, NR_syscalls);
291 DECLARE_BITMAP(sc_compat, NR_compat_syscalls);
292};
293
a90917c3 294static void syscall_entry_unknown(struct lttng_event *event,
f405cfce
MD
295 struct pt_regs *regs, unsigned int id)
296{
297 unsigned long args[UNKNOWN_SYSCALL_NRARGS];
f405cfce 298
f405cfce 299 syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args);
a93244f8 300 if (unlikely(is_compat_task()))
5b7ac358 301 __event_probe__compat_syscall_enter_unknown(event, id, args);
a93244f8 302 else
5b7ac358 303 __event_probe__syscall_enter_unknown(event, id, args);
f405cfce
MD
304}
305
2faf7d1b 306void syscall_entry_probe(void *__data, struct pt_regs *regs, long id)
259b6cb3 307{
a90917c3
MD
308 struct lttng_channel *chan = __data;
309 struct lttng_event *event, *unknown_event;
49c50022
MD
310 const struct trace_syscall_entry *table, *entry;
311 size_t table_len;
259b6cb3 312
b76dc1a0 313 if (unlikely(is_compat_task())) {
80f87dd2
MD
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 }
49c50022 324 table = compat_sc_table;
a93244f8 325 table_len = ARRAY_SIZE(compat_sc_table);
49c50022
MD
326 unknown_event = chan->sc_compat_unknown;
327 } else {
80f87dd2
MD
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 }
49c50022
MD
338 table = sc_table;
339 table_len = ARRAY_SIZE(sc_table);
340 unknown_event = chan->sc_unknown;
b76dc1a0 341 }
49c50022
MD
342 if (unlikely(id >= table_len)) {
343 syscall_entry_unknown(unknown_event, regs, id);
259b6cb3 344 return;
f405cfce 345 }
49c50022
MD
346 if (unlikely(is_compat_task()))
347 event = chan->compat_sc_table[id];
348 else
349 event = chan->sc_table[id];
f405cfce 350 if (unlikely(!event)) {
49c50022 351 syscall_entry_unknown(unknown_event, regs, id);
f405cfce
MD
352 return;
353 }
49c50022 354 entry = &table[id];
f405cfce 355 WARN_ON_ONCE(!entry);
259b6cb3
MD
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
5b7ac358
MD
445static 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
458void 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
2a0c4816 600/* noinline to diminish caller stack size */
49c50022
MD
601static
602int fill_table(const struct trace_syscall_entry *table, size_t table_len,
5b7ac358
MD
603 struct lttng_event **chan_table, struct lttng_channel *chan,
604 void *filter, enum sc_type type)
259b6cb3 605{
2a0c4816 606 const struct lttng_event_desc *desc;
259b6cb3 607 unsigned int i;
49c50022
MD
608
609 /* Allocate events for each syscall, insert into table */
610 for (i = 0; i < table_len; i++) {
611 struct lttng_kernel_event ev;
2a0c4816 612 desc = table[i].desc;
49c50022
MD
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));
5b7ac358
MD
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);
f8695253 648 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
49c50022 649 ev.instrumentation = LTTNG_KERNEL_NOOP;
a90917c3 650 chan_table[i] = lttng_event_create(chan, &ev, filter,
49c50022 651 desc);
abc0446a
MD
652 WARN_ON_ONCE(!chan_table[i]);
653 if (IS_ERR(chan_table[i])) {
49c50022
MD
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 */
abc0446a 660 return PTR_ERR(chan_table[i]);
49c50022
MD
661 }
662 }
663 return 0;
664}
665
a90917c3 666int lttng_syscalls_register(struct lttng_channel *chan, void *filter)
49c50022 667{
2a0c4816 668 struct lttng_kernel_event ev;
259b6cb3
MD
669 int ret;
670
671 wrapper_vmalloc_sync_all();
259b6cb3
MD
672
673 if (!chan->sc_table) {
674 /* create syscall table mapping syscall to events */
a90917c3 675 chan->sc_table = kzalloc(sizeof(struct lttng_event *)
259b6cb3
MD
676 * ARRAY_SIZE(sc_table), GFP_KERNEL);
677 if (!chan->sc_table)
678 return -ENOMEM;
679 }
5b7ac358
MD
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
259b6cb3 688
49c50022
MD
689#ifdef CONFIG_COMPAT
690 if (!chan->compat_sc_table) {
691 /* create syscall table mapping compat syscall to events */
a90917c3 692 chan->compat_sc_table = kzalloc(sizeof(struct lttng_event *)
a93244f8 693 * ARRAY_SIZE(compat_sc_table), GFP_KERNEL);
49c50022
MD
694 if (!chan->compat_sc_table)
695 return -ENOMEM;
696 }
5b7ac358
MD
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 }
49c50022 705#endif
f405cfce 706 if (!chan->sc_unknown) {
f405cfce 707 const struct lttng_event_desc *desc =
5b7ac358 708 &__event_desc___syscall_enter_unknown;
2f804c0a 709
f405cfce 710 memset(&ev, 0, sizeof(ev));
f8695253
MD
711 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
712 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
f405cfce 713 ev.instrumentation = LTTNG_KERNEL_NOOP;
a90917c3 714 chan->sc_unknown = lttng_event_create(chan, &ev, filter,
f405cfce 715 desc);
abc0446a
MD
716 WARN_ON_ONCE(!chan->sc_unknown);
717 if (IS_ERR(chan->sc_unknown)) {
718 return PTR_ERR(chan->sc_unknown);
f405cfce
MD
719 }
720 }
721
b76dc1a0 722 if (!chan->sc_compat_unknown) {
b76dc1a0 723 const struct lttng_event_desc *desc =
5b7ac358 724 &__event_desc___compat_syscall_enter_unknown;
b76dc1a0
MD
725
726 memset(&ev, 0, sizeof(ev));
f8695253
MD
727 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
728 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
b76dc1a0 729 ev.instrumentation = LTTNG_KERNEL_NOOP;
a90917c3 730 chan->sc_compat_unknown = lttng_event_create(chan, &ev, filter,
b76dc1a0 731 desc);
abc0446a
MD
732 WARN_ON_ONCE(!chan->sc_unknown);
733 if (IS_ERR(chan->sc_compat_unknown)) {
734 return PTR_ERR(chan->sc_compat_unknown);
b76dc1a0
MD
735 }
736 }
737
5b7ac358 738 if (!chan->compat_sc_exit_unknown) {
2f804c0a 739 const struct lttng_event_desc *desc =
5b7ac358 740 &__event_desc___compat_syscall_exit_unknown;
2f804c0a
MD
741
742 memset(&ev, 0, sizeof(ev));
f8695253
MD
743 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
744 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
2f804c0a 745 ev.instrumentation = LTTNG_KERNEL_NOOP;
5b7ac358
MD
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,
2f804c0a 763 desc);
5b7ac358
MD
764 WARN_ON_ONCE(!chan->sc_exit_unknown);
765 if (IS_ERR(chan->sc_exit_unknown)) {
766 return PTR_ERR(chan->sc_exit_unknown);
2f804c0a
MD
767 }
768 }
769
49c50022 770 ret = fill_table(sc_table, ARRAY_SIZE(sc_table),
5b7ac358
MD
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);
49c50022
MD
776 if (ret)
777 return ret;
5b7ac358 778
49c50022 779#ifdef CONFIG_COMPAT
a93244f8 780 ret = fill_table(compat_sc_table, ARRAY_SIZE(compat_sc_table),
5b7ac358
MD
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);
49c50022
MD
788 if (ret)
789 return ret;
790#endif
80f87dd2
MD
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 }
63728b02
MD
798 /*
799 * We change the name of sys_exit tracepoint due to namespace
800 * conflict with sys_exit syscall entry.
801 */
80f87dd2
MD
802 if (!chan->sys_exit_registered) {
803 ret = lttng_wrapper_tracepoint_probe_register("sys_exit",
5b7ac358 804 (void *) syscall_exit_probe, chan);
80f87dd2
MD
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;
63728b02 811 }
259b6cb3
MD
812 return ret;
813}
814
815/*
816 * Only called at session destruction.
817 */
a90917c3 818int lttng_syscalls_unregister(struct lttng_channel *chan)
259b6cb3
MD
819{
820 int ret;
821
822 if (!chan->sc_table)
823 return 0;
80f87dd2
MD
824 if (chan->sys_enter_registered) {
825 ret = lttng_wrapper_tracepoint_probe_unregister("sys_exit",
5b7ac358 826 (void *) syscall_exit_probe, chan);
80f87dd2
MD
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 }
a90917c3 838 /* lttng_event destroy will be performed by lttng_session_destroy() */
259b6cb3 839 kfree(chan->sc_table);
5b7ac358 840 kfree(chan->sc_exit_table);
49c50022
MD
841#ifdef CONFIG_COMPAT
842 kfree(chan->compat_sc_table);
5b7ac358 843 kfree(chan->compat_sc_exit_table);
49c50022 844#endif
80f87dd2
MD
845 kfree(chan->sc_filter);
846 return 0;
847}
848
849static
850int 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;
5b7ac358 857 const char *it_name;
80f87dd2
MD
858
859 entry = &sc_table[i];
860 if (!entry->desc)
861 continue;
5b7ac358
MD
862 it_name = entry->desc->name;
863 it_name += strlen(SYSCALL_ENTRY_STR);
864 if (!strcmp(syscall_name, it_name)) {
80f87dd2
MD
865 syscall_nr = i;
866 break;
867 }
868 }
869 return syscall_nr;
870}
871
872static
873int 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;
5b7ac358 880 const char *it_name;
80f87dd2
MD
881
882 entry = &compat_sc_table[i];
883 if (!entry->desc)
884 continue;
5b7ac358
MD
885 it_name = entry->desc->name;
886 it_name += strlen(COMPAT_SYSCALL_ENTRY_STR);
887 if (!strcmp(syscall_name, it_name)) {
80f87dd2
MD
888 syscall_nr = i;
889 break;
890 }
891 }
892 return syscall_nr;
893}
894
895int 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
953error:
954 if (!chan->sc_filter)
955 kfree(filter);
956 return ret;
957}
958
959int 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;
259b6cb3 1002 return 0;
80f87dd2
MD
1003
1004error:
1005 if (!chan->sc_filter)
1006 kfree(filter);
1007 return ret;
259b6cb3 1008}
This page took 0.068455 seconds and 4 git commands to generate.