Implement event notifiers for syscalls
[lttng-modules.git] / src / lttng-syscalls.c
... / ...
CommitLineData
1/* SPDX-License-Identifier: (GPL-2.0-only or LGPL-2.1-only)
2 *
3 * lttng-syscalls.c
4 *
5 * LTTng syscall probes.
6 *
7 * Copyright (C) 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 */
9
10#include <linux/module.h>
11#include <linux/slab.h>
12#include <linux/compat.h>
13#include <linux/err.h>
14#include <linux/bitmap.h>
15#include <linux/in.h>
16#include <linux/in6.h>
17#include <linux/seq_file.h>
18#include <linux/stringify.h>
19#include <linux/file.h>
20#include <linux/anon_inodes.h>
21#include <linux/fcntl.h>
22#include <linux/mman.h>
23#include <asm/ptrace.h>
24#include <asm/syscall.h>
25
26#include <lttng/bitfield.h>
27#include <wrapper/tracepoint.h>
28#include <wrapper/file.h>
29#include <wrapper/rcu.h>
30#include <wrapper/syscall.h>
31#include <lttng/events.h>
32#include <lttng/utils.h>
33
34#ifndef CONFIG_COMPAT
35# ifndef is_compat_task
36# define is_compat_task() (0)
37# endif
38#endif
39
40/* in_compat_syscall appears in kernel 4.6. */
41#ifndef in_compat_syscall
42 #define in_compat_syscall() is_compat_task()
43#endif
44
45enum sc_type {
46 SC_TYPE_ENTRY,
47 SC_TYPE_EXIT,
48 SC_TYPE_COMPAT_ENTRY,
49 SC_TYPE_COMPAT_EXIT,
50};
51
52#define SYSCALL_ENTRY_TOK syscall_entry_
53#define COMPAT_SYSCALL_ENTRY_TOK compat_syscall_entry_
54#define SYSCALL_EXIT_TOK syscall_exit_
55#define COMPAT_SYSCALL_EXIT_TOK compat_syscall_exit_
56
57#define SYSCALL_ENTRY_STR __stringify(SYSCALL_ENTRY_TOK)
58#define COMPAT_SYSCALL_ENTRY_STR __stringify(COMPAT_SYSCALL_ENTRY_TOK)
59#define SYSCALL_EXIT_STR __stringify(SYSCALL_EXIT_TOK)
60#define COMPAT_SYSCALL_EXIT_STR __stringify(COMPAT_SYSCALL_EXIT_TOK)
61
62static
63void syscall_entry_event_probe(void *__data, struct pt_regs *regs, long id);
64static
65void syscall_exit_event_probe(void *__data, struct pt_regs *regs, long ret);
66
67static
68void syscall_entry_event_notifier_probe(void *__data, struct pt_regs *regs,
69 long id);
70
71/*
72 * Forward declarations for old kernels.
73 */
74struct mmsghdr;
75struct rlimit64;
76struct oldold_utsname;
77struct old_utsname;
78struct sel_arg_struct;
79struct mmap_arg_struct;
80struct file_handle;
81struct user_msghdr;
82
83/*
84 * Forward declaration for kernels >= 5.6
85 */
86struct timex;
87struct timeval;
88struct itimerval;
89struct itimerspec;
90
91#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0))
92typedef __kernel_old_time_t time_t;
93#endif
94
95#ifdef IA32_NR_syscalls
96#define NR_compat_syscalls IA32_NR_syscalls
97#else
98#define NR_compat_syscalls NR_syscalls
99#endif
100
101/*
102 * Create LTTng tracepoint probes.
103 */
104#define LTTNG_PACKAGE_BUILD
105#define CREATE_TRACE_POINTS
106#define TP_MODULE_NOINIT
107#define TRACE_INCLUDE_PATH instrumentation/syscalls/headers
108
109#define PARAMS(args...) args
110
111/* Handle unknown syscalls */
112#undef TRACE_SYSTEM
113#define TRACE_SYSTEM syscalls_unknown
114#include <instrumentation/syscalls/headers/syscalls_unknown.h>
115#undef TRACE_SYSTEM
116
117#define SC_ENTER
118
119#undef sc_exit
120#define sc_exit(...)
121#undef sc_in
122#define sc_in(...) __VA_ARGS__
123#undef sc_out
124#define sc_out(...)
125#undef sc_inout
126#define sc_inout(...) __VA_ARGS__
127
128/* Hijack probe callback for system call enter */
129#undef TP_PROBE_CB
130#define TP_PROBE_CB(_template) &syscall_entry_event_probe
131#define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \
132 LTTNG_TRACEPOINT_EVENT(syscall_entry_##_name, PARAMS(_proto), PARAMS(_args), \
133 PARAMS(_fields))
134#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code_pre, _fields, _code_post) \
135 LTTNG_TRACEPOINT_EVENT_CODE(syscall_entry_##_name, PARAMS(_proto), PARAMS(_args), \
136 PARAMS(_locvar), PARAMS(_code_pre), \
137 PARAMS(_fields), PARAMS(_code_post))
138#define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _fields) \
139 LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(syscall_entry_##_name, PARAMS(_fields))
140#define SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(_template, _name) \
141 LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(syscall_entry_##_template, syscall_entry_##_name)
142/* Enumerations only defined at first inclusion. */
143#define SC_LTTNG_TRACEPOINT_ENUM(_name, _values) \
144 LTTNG_TRACEPOINT_ENUM(_name, PARAMS(_values))
145#undef TRACE_SYSTEM
146#define TRACE_SYSTEM syscall_entry_integers
147#define TRACE_INCLUDE_FILE syscalls_integers
148#include <instrumentation/syscalls/headers/syscalls_integers.h>
149#undef TRACE_INCLUDE_FILE
150#undef TRACE_SYSTEM
151#define TRACE_SYSTEM syscall_entry_pointers
152#define TRACE_INCLUDE_FILE syscalls_pointers
153#include <instrumentation/syscalls/headers/syscalls_pointers.h>
154#undef TRACE_INCLUDE_FILE
155#undef TRACE_SYSTEM
156#undef SC_LTTNG_TRACEPOINT_ENUM
157#undef SC_LTTNG_TRACEPOINT_EVENT_CODE
158#undef SC_LTTNG_TRACEPOINT_EVENT
159#undef SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS
160#undef SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS
161#undef TP_PROBE_CB
162#undef _TRACE_SYSCALLS_INTEGERS_H
163#undef _TRACE_SYSCALLS_POINTERS_H
164
165/* Hijack probe callback for compat system call enter */
166#define TP_PROBE_CB(_template) &syscall_entry_event_probe
167#define LTTNG_SC_COMPAT
168#define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \
169 LTTNG_TRACEPOINT_EVENT(compat_syscall_entry_##_name, PARAMS(_proto), PARAMS(_args), \
170 PARAMS(_fields))
171#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code_pre, _fields, _code_post) \
172 LTTNG_TRACEPOINT_EVENT_CODE(compat_syscall_entry_##_name, PARAMS(_proto), PARAMS(_args), \
173 PARAMS(_locvar), PARAMS(_code_pre), PARAMS(_fields), PARAMS(_code_post))
174#define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _fields) \
175 LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(compat_syscall_entry_##_name, PARAMS(_fields))
176#define SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(_template, _name) \
177 LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(compat_syscall_entry_##_template, \
178 compat_syscall_entry_##_name)
179/* Enumerations only defined at inital inclusion (not here). */
180#define SC_LTTNG_TRACEPOINT_ENUM(_name, _values)
181#define TRACE_SYSTEM compat_syscall_entry_integers
182#define TRACE_INCLUDE_FILE compat_syscalls_integers
183#include <instrumentation/syscalls/headers/compat_syscalls_integers.h>
184#undef TRACE_INCLUDE_FILE
185#undef TRACE_SYSTEM
186#define TRACE_SYSTEM compat_syscall_entry_pointers
187#define TRACE_INCLUDE_FILE compat_syscalls_pointers
188#include <instrumentation/syscalls/headers/compat_syscalls_pointers.h>
189#undef TRACE_INCLUDE_FILE
190#undef TRACE_SYSTEM
191#undef SC_LTTNG_TRACEPOINT_ENUM
192#undef SC_LTTNG_TRACEPOINT_EVENT_CODE
193#undef SC_LTTNG_TRACEPOINT_EVENT
194#undef SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS
195#undef SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS
196#undef TP_PROBE_CB
197#undef _TRACE_SYSCALLS_INTEGERS_H
198#undef _TRACE_SYSCALLS_POINTERS_H
199#undef LTTNG_SC_COMPAT
200
201#undef SC_ENTER
202
203#define SC_EXIT
204
205#undef sc_exit
206#define sc_exit(...) __VA_ARGS__
207#undef sc_in
208#define sc_in(...)
209#undef sc_out
210#define sc_out(...) __VA_ARGS__
211#undef sc_inout
212#define sc_inout(...) __VA_ARGS__
213
214/* Hijack probe callback for system call exit */
215#define TP_PROBE_CB(_template) &syscall_exit_event_probe
216#define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \
217 LTTNG_TRACEPOINT_EVENT(syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \
218 PARAMS(_fields))
219#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code_pre, _fields, _code_post) \
220 LTTNG_TRACEPOINT_EVENT_CODE(syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \
221 PARAMS(_locvar), PARAMS(_code_pre), PARAMS(_fields), PARAMS(_code_post))
222#define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _fields) \
223 LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(syscall_exit_##_name, PARAMS(_fields))
224#define SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(_template, _name) \
225 LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(syscall_exit_##_template, \
226 syscall_exit_##_name)
227/* Enumerations only defined at inital inclusion (not here). */
228#define SC_LTTNG_TRACEPOINT_ENUM(_name, _values)
229#define TRACE_SYSTEM syscall_exit_integers
230#define TRACE_INCLUDE_FILE syscalls_integers
231#include <instrumentation/syscalls/headers/syscalls_integers.h>
232#undef TRACE_INCLUDE_FILE
233#undef TRACE_SYSTEM
234#define TRACE_SYSTEM syscall_exit_pointers
235#define TRACE_INCLUDE_FILE syscalls_pointers
236#include <instrumentation/syscalls/headers/syscalls_pointers.h>
237#undef TRACE_INCLUDE_FILE
238#undef TRACE_SYSTEM
239#undef SC_LTTNG_TRACEPOINT_ENUM
240#undef SC_LTTNG_TRACEPOINT_EVENT_CODE
241#undef SC_LTTNG_TRACEPOINT_EVENT
242#undef SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS
243#undef SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS
244#undef TP_PROBE_CB
245#undef _TRACE_SYSCALLS_INTEGERS_H
246#undef _TRACE_SYSCALLS_POINTERS_H
247
248
249/* Hijack probe callback for compat system call exit */
250#define TP_PROBE_CB(_template) &syscall_exit_event_probe
251#define LTTNG_SC_COMPAT
252#define SC_LTTNG_TRACEPOINT_EVENT(_name, _proto, _args, _fields) \
253 LTTNG_TRACEPOINT_EVENT(compat_syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \
254 PARAMS(_fields))
255#define SC_LTTNG_TRACEPOINT_EVENT_CODE(_name, _proto, _args, _locvar, _code_pre, _fields, _code_post) \
256 LTTNG_TRACEPOINT_EVENT_CODE(compat_syscall_exit_##_name, PARAMS(_proto), PARAMS(_args), \
257 PARAMS(_locvar), PARAMS(_code_pre), PARAMS(_fields), PARAMS(_code_post))
258#define SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(_name, _fields) \
259 LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS(compat_syscall_exit_##_name, PARAMS(_fields))
260#define SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(_template, _name) \
261 LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS(compat_syscall_exit_##_template, \
262 compat_syscall_exit_##_name)
263/* Enumerations only defined at inital inclusion (not here). */
264#define SC_LTTNG_TRACEPOINT_ENUM(_name, _values)
265#define TRACE_SYSTEM compat_syscall_exit_integers
266#define TRACE_INCLUDE_FILE compat_syscalls_integers
267#include <instrumentation/syscalls/headers/compat_syscalls_integers.h>
268#undef TRACE_INCLUDE_FILE
269#undef TRACE_SYSTEM
270#define TRACE_SYSTEM compat_syscall_exit_pointers
271#define TRACE_INCLUDE_FILE compat_syscalls_pointers
272#include <instrumentation/syscalls/headers/compat_syscalls_pointers.h>
273#undef TRACE_INCLUDE_FILE
274#undef TRACE_SYSTEM
275#undef SC_LTTNG_TRACEPOINT_ENUM
276#undef SC_LTTNG_TRACEPOINT_EVENT_CODE
277#undef SC_LTTNG_TRACEPOINT_EVENT
278#undef SC_LTTNG_TRACEPOINT_EVENT_CLASS_NOARGS
279#undef SC_LTTNG_TRACEPOINT_EVENT_INSTANCE_NOARGS
280#undef TP_PROBE_CB
281#undef _TRACE_SYSCALLS_INTEGERS_H
282#undef _TRACE_SYSCALLS_POINTERS_H
283#undef LTTNG_SC_COMPAT
284
285#undef SC_EXIT
286
287#undef TP_MODULE_NOINIT
288#undef LTTNG_PACKAGE_BUILD
289#undef CREATE_TRACE_POINTS
290
291struct trace_syscall_entry {
292 void *event_func;
293 void *event_notifier_func;
294 const struct lttng_event_desc *desc;
295 const struct lttng_event_field *fields;
296 unsigned int nrargs;
297};
298
299#define CREATE_SYSCALL_TABLE
300
301#define SC_ENTER
302
303#undef sc_exit
304#define sc_exit(...)
305
306#undef TRACE_SYSCALL_TABLE
307#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
308 [ _nr ] = { \
309 .event_func = __event_probe__syscall_entry_##_template, \
310 .event_notifier_func = __event_notifier_probe__syscall_entry_##_template, \
311 .nrargs = (_nrargs), \
312 .fields = __event_fields___syscall_entry_##_template, \
313 .desc = &__event_desc___syscall_entry_##_name, \
314 },
315
316/* Event syscall enter tracing table */
317static const struct trace_syscall_entry sc_table[] = {
318#include <instrumentation/syscalls/headers/syscalls_integers.h>
319#include <instrumentation/syscalls/headers/syscalls_pointers.h>
320};
321
322#undef TRACE_SYSCALL_TABLE
323#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
324 [ _nr ] = { \
325 .event_func = __event_probe__compat_syscall_entry_##_template, \
326 .event_notifier_func = __event_notifier_probe__compat_syscall_entry_##_template, \
327 .nrargs = (_nrargs), \
328 .fields = __event_fields___compat_syscall_entry_##_template, \
329 .desc = &__event_desc___compat_syscall_entry_##_name, \
330 },
331
332/* Event compat syscall enter table */
333const struct trace_syscall_entry compat_sc_table[] = {
334#include <instrumentation/syscalls/headers/compat_syscalls_integers.h>
335#include <instrumentation/syscalls/headers/compat_syscalls_pointers.h>
336};
337
338#undef SC_ENTER
339
340#define SC_EXIT
341
342#undef sc_exit
343#define sc_exit(...) __VA_ARGS__
344
345#undef TRACE_SYSCALL_TABLE
346#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
347 [ _nr ] = { \
348 .event_func = __event_probe__syscall_exit_##_template, \
349 .event_notifier_func = __event_notifier_probe__syscall_exit_##_template, \
350 .nrargs = (_nrargs), \
351 .fields = __event_fields___syscall_exit_##_template, \
352 .desc = &__event_desc___syscall_exit_##_name, \
353 },
354
355/* Event syscall exit table */
356static const struct trace_syscall_entry sc_exit_table[] = {
357#include <instrumentation/syscalls/headers/syscalls_integers.h>
358#include <instrumentation/syscalls/headers/syscalls_pointers.h>
359};
360
361#undef TRACE_SYSCALL_TABLE
362#define TRACE_SYSCALL_TABLE(_template, _name, _nr, _nrargs) \
363 [ _nr ] = { \
364 .event_func = __event_probe__compat_syscall_exit_##_template, \
365 .event_notifier_func = __event_notifier_probe__compat_syscall_exit_##_template, \
366 .nrargs = (_nrargs), \
367 .fields = __event_fields___compat_syscall_exit_##_template, \
368 .desc = &__event_desc___compat_syscall_exit_##_name, \
369 },
370
371/* Event compat syscall exit table */
372const struct trace_syscall_entry compat_sc_exit_table[] = {
373#include <instrumentation/syscalls/headers/compat_syscalls_integers.h>
374#include <instrumentation/syscalls/headers/compat_syscalls_pointers.h>
375};
376
377#undef SC_EXIT
378
379#undef CREATE_SYSCALL_TABLE
380
381struct lttng_syscall_filter {
382 DECLARE_BITMAP(sc_entry, NR_syscalls);
383 DECLARE_BITMAP(sc_exit, NR_syscalls);
384 DECLARE_BITMAP(sc_compat_entry, NR_compat_syscalls);
385 DECLARE_BITMAP(sc_compat_exit, NR_compat_syscalls);
386};
387
388static void syscall_entry_event_unknown(struct lttng_event *event,
389 struct pt_regs *regs, unsigned int id)
390{
391 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
392
393 lttng_syscall_get_arguments(current, regs, args);
394 if (unlikely(in_compat_syscall()))
395 __event_probe__compat_syscall_entry_unknown(event, id, args);
396 else
397 __event_probe__syscall_entry_unknown(event, id, args);
398}
399
400static void syscall_entry_event_notifier_unknown(
401 struct lttng_event_notifier_group *notifier_group,
402 struct pt_regs *regs, unsigned int id)
403{
404 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
405 struct lttng_event *event;
406
407 lttng_syscall_get_arguments(current, regs, args);
408 if (unlikely(in_compat_syscall()))
409 __event_probe__compat_syscall_notifier_entry_unknown(event, id, args);
410 else
411 __event_probe__syscall_notifier_entry_unknown(event, id, args);
412}
413
414static __always_inline
415void syscall_entry_call_func(void *func, unsigned int nrargs, void *data,
416 struct pt_regs *regs)
417{
418 switch (nrargs) {
419 case 0:
420 {
421 void (*fptr)(void *__data) = func;
422
423 fptr(data);
424 break;
425 }
426 case 1:
427 {
428 void (*fptr)(void *__data, unsigned long arg0) = func;
429 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
430
431 lttng_syscall_get_arguments(current, regs, args);
432 fptr(data, args[0]);
433 break;
434 }
435 case 2:
436 {
437 void (*fptr)(void *__data,
438 unsigned long arg0,
439 unsigned long arg1) = func;
440 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
441
442 lttng_syscall_get_arguments(current, regs, args);
443 fptr(data, args[0], args[1]);
444 break;
445 }
446 case 3:
447 {
448 void (*fptr)(void *__data,
449 unsigned long arg0,
450 unsigned long arg1,
451 unsigned long arg2) = func;
452 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
453
454 lttng_syscall_get_arguments(current, regs, args);
455 fptr(data, args[0], args[1], args[2]);
456 break;
457 }
458 case 4:
459 {
460 void (*fptr)(void *__data,
461 unsigned long arg0,
462 unsigned long arg1,
463 unsigned long arg2,
464 unsigned long arg3) = func;
465 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
466
467 lttng_syscall_get_arguments(current, regs, args);
468 fptr(data, args[0], args[1], args[2], args[3]);
469 break;
470 }
471 case 5:
472 {
473 void (*fptr)(void *__data,
474 unsigned long arg0,
475 unsigned long arg1,
476 unsigned long arg2,
477 unsigned long arg3,
478 unsigned long arg4) = func;
479 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
480
481 lttng_syscall_get_arguments(current, regs, args);
482 fptr(data, args[0], args[1], args[2], args[3], args[4]);
483 break;
484 }
485 case 6:
486 {
487 void (*fptr)(void *__data,
488 unsigned long arg0,
489 unsigned long arg1,
490 unsigned long arg2,
491 unsigned long arg3,
492 unsigned long arg4,
493 unsigned long arg5) = func;
494 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
495
496 lttng_syscall_get_arguments(current, regs, args);
497 fptr(data, args[0], args[1], args[2],
498 args[3], args[4], args[5]);
499 break;
500 }
501 default:
502 break;
503 }
504}
505
506void syscall_entry_event_probe(void *__data, struct pt_regs *regs, long id)
507{
508 struct lttng_channel *chan = __data;
509 struct lttng_event *event, *unknown_event;
510 const struct trace_syscall_entry *table, *entry;
511 size_t table_len;
512
513 if (unlikely(in_compat_syscall())) {
514 struct lttng_syscall_filter *filter = chan->sc_filter;
515
516 if (id < 0 || id >= NR_compat_syscalls
517 || (!READ_ONCE(chan->syscall_all) && !test_bit(id, filter->sc_compat_entry))) {
518 /* System call filtered out. */
519 return;
520 }
521 table = compat_sc_table;
522 table_len = ARRAY_SIZE(compat_sc_table);
523 unknown_event = chan->sc_compat_unknown;
524 } else {
525 struct lttng_syscall_filter *filter = chan->sc_filter;
526
527 if (id < 0 || id >= NR_syscalls
528 || (!READ_ONCE(chan->syscall_all) && !test_bit(id, filter->sc_entry))) {
529 /* System call filtered out. */
530 return;
531 }
532 table = sc_table;
533 table_len = ARRAY_SIZE(sc_table);
534 unknown_event = chan->sc_unknown;
535 }
536 if (unlikely(id < 0 || id >= table_len)) {
537 syscall_entry_event_unknown(unknown_event, regs, id);
538 return;
539 }
540 if (unlikely(in_compat_syscall()))
541 event = chan->compat_sc_table[id];
542 else
543 event = chan->sc_table[id];
544 if (unlikely(!event)) {
545 syscall_entry_event_unknown(unknown_event, regs, id);
546 return;
547 }
548 entry = &table[id];
549 WARN_ON_ONCE(!entry);
550 syscall_entry_call_func(entry->event_func, entry->nrargs, event, regs);
551}
552
553void syscall_entry_event_notifier_probe(void *__data, struct pt_regs *regs, long id)
554{
555 struct lttng_event_notifier_group *event_notifier_group = __data;
556 const struct trace_syscall_entry *entry;
557 struct list_head *dispatch_list;
558 struct lttng_event_notifier *iter;
559 size_t table_len;
560
561 if (unlikely(in_compat_syscall())) {
562 table_len = ARRAY_SIZE(compat_sc_table);
563 if (unlikely(id < 0 || id >= table_len)) {
564 return;
565 }
566 entry = &compat_sc_table[id];
567 dispatch_list = &event_notifier_group->event_notifier_compat_syscall_dispatch[id];
568 } else {
569 table_len = ARRAY_SIZE(sc_table);
570 if (unlikely(id < 0 || id >= table_len)) {
571 return;
572 }
573 entry = &sc_table[id];
574 dispatch_list = &event_notifier_group->event_notifier_syscall_dispatch[id];
575 }
576
577 if (unlikely(id < 0 || id >= table_len)) {
578 syscall_entry_event_notifier_unknown(event_notifier_group, regs, id);
579 return;
580 }
581
582 /* TODO handle unknown syscall */
583
584 list_for_each_entry_rcu(iter, dispatch_list, u.syscall.node) {
585 BUG_ON(iter->u.syscall.syscall_id != id);
586 syscall_entry_call_func(entry->event_notifier_func,
587 entry->nrargs, iter, regs);
588 }
589}
590
591static void syscall_exit_event_unknown(struct lttng_event *event,
592 struct pt_regs *regs, int id, long ret)
593{
594 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
595
596 lttng_syscall_get_arguments(current, regs, args);
597 if (unlikely(in_compat_syscall()))
598 __event_probe__compat_syscall_exit_unknown(event, id, ret,
599 args);
600 else
601 __event_probe__syscall_exit_unknown(event, id, ret, args);
602}
603
604void syscall_exit_event_probe(void *__data, struct pt_regs *regs, long ret)
605{
606 struct lttng_channel *chan = __data;
607 struct lttng_event *event, *unknown_event;
608 const struct trace_syscall_entry *table, *entry;
609 size_t table_len;
610 long id;
611
612 id = syscall_get_nr(current, regs);
613 if (unlikely(in_compat_syscall())) {
614 struct lttng_syscall_filter *filter = chan->sc_filter;
615
616 if (id < 0 || id >= NR_compat_syscalls
617 || (!READ_ONCE(chan->syscall_all) && !test_bit(id, filter->sc_compat_exit))) {
618 /* System call filtered out. */
619 return;
620 }
621 table = compat_sc_exit_table;
622 table_len = ARRAY_SIZE(compat_sc_exit_table);
623 unknown_event = chan->compat_sc_exit_unknown;
624 } else {
625 struct lttng_syscall_filter *filter = chan->sc_filter;
626
627 if (id < 0 || id >= NR_syscalls
628 || (!READ_ONCE(chan->syscall_all) && !test_bit(id, filter->sc_exit))) {
629 /* System call filtered out. */
630 return;
631 }
632 table = sc_exit_table;
633 table_len = ARRAY_SIZE(sc_exit_table);
634 unknown_event = chan->sc_exit_unknown;
635 }
636 if (unlikely(id < 0 || id >= table_len)) {
637 syscall_exit_event_unknown(unknown_event, regs, id, ret);
638 return;
639 }
640 if (unlikely(in_compat_syscall()))
641 event = chan->compat_sc_exit_table[id];
642 else
643 event = chan->sc_exit_table[id];
644 if (unlikely(!event)) {
645 syscall_exit_event_unknown(unknown_event, regs, id, ret);
646 return;
647 }
648 entry = &table[id];
649 WARN_ON_ONCE(!entry);
650
651 switch (entry->nrargs) {
652 case 0:
653 {
654 void (*fptr)(void *__data, long ret) = entry->event_func;
655
656 fptr(event, ret);
657 break;
658 }
659 case 1:
660 {
661 void (*fptr)(void *__data,
662 long ret,
663 unsigned long arg0) = entry->event_func;
664 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
665
666 lttng_syscall_get_arguments(current, regs, args);
667 fptr(event, ret, args[0]);
668 break;
669 }
670 case 2:
671 {
672 void (*fptr)(void *__data,
673 long ret,
674 unsigned long arg0,
675 unsigned long arg1) = entry->event_func;
676 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
677
678 lttng_syscall_get_arguments(current, regs, args);
679 fptr(event, ret, args[0], args[1]);
680 break;
681 }
682 case 3:
683 {
684 void (*fptr)(void *__data,
685 long ret,
686 unsigned long arg0,
687 unsigned long arg1,
688 unsigned long arg2) = entry->event_func;
689 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
690
691 lttng_syscall_get_arguments(current, regs, args);
692 fptr(event, ret, args[0], args[1], args[2]);
693 break;
694 }
695 case 4:
696 {
697 void (*fptr)(void *__data,
698 long ret,
699 unsigned long arg0,
700 unsigned long arg1,
701 unsigned long arg2,
702 unsigned long arg3) = entry->event_func;
703 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
704
705 lttng_syscall_get_arguments(current, regs, args);
706 fptr(event, ret, args[0], args[1], args[2], args[3]);
707 break;
708 }
709 case 5:
710 {
711 void (*fptr)(void *__data,
712 long ret,
713 unsigned long arg0,
714 unsigned long arg1,
715 unsigned long arg2,
716 unsigned long arg3,
717 unsigned long arg4) = entry->event_func;
718 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
719
720 lttng_syscall_get_arguments(current, regs, args);
721 fptr(event, ret, args[0], args[1], args[2], args[3], args[4]);
722 break;
723 }
724 case 6:
725 {
726 void (*fptr)(void *__data,
727 long ret,
728 unsigned long arg0,
729 unsigned long arg1,
730 unsigned long arg2,
731 unsigned long arg3,
732 unsigned long arg4,
733 unsigned long arg5) = entry->event_func;
734 unsigned long args[LTTNG_SYSCALL_NR_ARGS];
735
736 lttng_syscall_get_arguments(current, regs, args);
737 fptr(event, ret, args[0], args[1], args[2],
738 args[3], args[4], args[5]);
739 break;
740 }
741 default:
742 break;
743 }
744}
745
746/*
747 * noinline to diminish caller stack size.
748 * Should be called with sessions lock held.
749 */
750static
751int fill_event_table(const struct trace_syscall_entry *table, size_t table_len,
752 struct lttng_event **chan_table, struct lttng_channel *chan,
753 void *filter, enum sc_type type)
754{
755 const struct lttng_event_desc *desc;
756 unsigned int i;
757
758 /* Allocate events for each syscall, insert into table */
759 for (i = 0; i < table_len; i++) {
760 struct lttng_kernel_event ev;
761 desc = table[i].desc;
762
763 if (!desc) {
764 /* Unknown syscall */
765 continue;
766 }
767 /*
768 * Skip those already populated by previous failed
769 * register for this channel.
770 */
771 if (chan_table[i])
772 continue;
773 memset(&ev, 0, sizeof(ev));
774 switch (type) {
775 case SC_TYPE_ENTRY:
776 ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY;
777 ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE;
778 break;
779 case SC_TYPE_EXIT:
780 ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT;
781 ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE;
782 break;
783 case SC_TYPE_COMPAT_ENTRY:
784 ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY;
785 ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT;
786 break;
787 case SC_TYPE_COMPAT_EXIT:
788 ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT;
789 ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT;
790 break;
791 }
792 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN - 1);
793 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
794 ev.instrumentation = LTTNG_KERNEL_SYSCALL;
795 chan_table[i] = _lttng_event_create(chan, &ev, filter,
796 desc, ev.instrumentation);
797 WARN_ON_ONCE(!chan_table[i]);
798 if (IS_ERR(chan_table[i])) {
799 /*
800 * If something goes wrong in event registration
801 * after the first one, we have no choice but to
802 * leave the previous events in there, until
803 * deleted by session teardown.
804 */
805 return PTR_ERR(chan_table[i]);
806 }
807 }
808 return 0;
809}
810
811/*
812 * Should be called with sessions lock held.
813 */
814int lttng_syscalls_register_event(struct lttng_channel *chan, void *filter)
815{
816 struct lttng_kernel_event ev;
817 int ret;
818
819 wrapper_vmalloc_sync_mappings();
820
821 if (!chan->sc_table) {
822 /* create syscall table mapping syscall to events */
823 chan->sc_table = kzalloc(sizeof(struct lttng_event *)
824 * ARRAY_SIZE(sc_table), GFP_KERNEL);
825 if (!chan->sc_table)
826 return -ENOMEM;
827 }
828 if (!chan->sc_exit_table) {
829 /* create syscall table mapping syscall to events */
830 chan->sc_exit_table = kzalloc(sizeof(struct lttng_event *)
831 * ARRAY_SIZE(sc_exit_table), GFP_KERNEL);
832 if (!chan->sc_exit_table)
833 return -ENOMEM;
834 }
835
836
837#ifdef CONFIG_COMPAT
838 if (!chan->compat_sc_table) {
839 /* create syscall table mapping compat syscall to events */
840 chan->compat_sc_table = kzalloc(sizeof(struct lttng_event *)
841 * ARRAY_SIZE(compat_sc_table), GFP_KERNEL);
842 if (!chan->compat_sc_table)
843 return -ENOMEM;
844 }
845
846 if (!chan->compat_sc_exit_table) {
847 /* create syscall table mapping compat syscall to events */
848 chan->compat_sc_exit_table = kzalloc(sizeof(struct lttng_event *)
849 * ARRAY_SIZE(compat_sc_exit_table), GFP_KERNEL);
850 if (!chan->compat_sc_exit_table)
851 return -ENOMEM;
852 }
853#endif
854 if (!chan->sc_unknown) {
855 const struct lttng_event_desc *desc =
856 &__event_desc___syscall_entry_unknown;
857
858 memset(&ev, 0, sizeof(ev));
859 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
860 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
861 ev.instrumentation = LTTNG_KERNEL_SYSCALL;
862 ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY;
863 ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE;
864 chan->sc_unknown = _lttng_event_create(chan, &ev, filter,
865 desc,
866 ev.instrumentation);
867 WARN_ON_ONCE(!chan->sc_unknown);
868 if (IS_ERR(chan->sc_unknown)) {
869 return PTR_ERR(chan->sc_unknown);
870 }
871 }
872
873 if (!chan->sc_compat_unknown) {
874 const struct lttng_event_desc *desc =
875 &__event_desc___compat_syscall_entry_unknown;
876
877 memset(&ev, 0, sizeof(ev));
878 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
879 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
880 ev.instrumentation = LTTNG_KERNEL_SYSCALL;
881 ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY;
882 ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT;
883 chan->sc_compat_unknown = _lttng_event_create(chan, &ev, filter,
884 desc,
885 ev.instrumentation);
886 WARN_ON_ONCE(!chan->sc_unknown);
887 if (IS_ERR(chan->sc_compat_unknown)) {
888 return PTR_ERR(chan->sc_compat_unknown);
889 }
890 }
891
892 if (!chan->compat_sc_exit_unknown) {
893 const struct lttng_event_desc *desc =
894 &__event_desc___compat_syscall_exit_unknown;
895
896 memset(&ev, 0, sizeof(ev));
897 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
898 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
899 ev.instrumentation = LTTNG_KERNEL_SYSCALL;
900 ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT;
901 ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT;
902 chan->compat_sc_exit_unknown = _lttng_event_create(chan, &ev,
903 filter, desc,
904 ev.instrumentation);
905 WARN_ON_ONCE(!chan->compat_sc_exit_unknown);
906 if (IS_ERR(chan->compat_sc_exit_unknown)) {
907 return PTR_ERR(chan->compat_sc_exit_unknown);
908 }
909 }
910
911 if (!chan->sc_exit_unknown) {
912 const struct lttng_event_desc *desc =
913 &__event_desc___syscall_exit_unknown;
914
915 memset(&ev, 0, sizeof(ev));
916 strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN);
917 ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
918 ev.instrumentation = LTTNG_KERNEL_SYSCALL;
919 ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT;
920 ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE;
921 chan->sc_exit_unknown = _lttng_event_create(chan, &ev, filter,
922 desc, ev.instrumentation);
923 WARN_ON_ONCE(!chan->sc_exit_unknown);
924 if (IS_ERR(chan->sc_exit_unknown)) {
925 return PTR_ERR(chan->sc_exit_unknown);
926 }
927 }
928
929 ret = fill_event_table(sc_table, ARRAY_SIZE(sc_table),
930 chan->sc_table, chan, filter, SC_TYPE_ENTRY);
931 if (ret)
932 return ret;
933 ret = fill_event_table(sc_exit_table, ARRAY_SIZE(sc_exit_table),
934 chan->sc_exit_table, chan, filter, SC_TYPE_EXIT);
935 if (ret)
936 return ret;
937
938#ifdef CONFIG_COMPAT
939 ret = fill_event_table(compat_sc_table, ARRAY_SIZE(compat_sc_table),
940 chan->compat_sc_table, chan, filter,
941 SC_TYPE_COMPAT_ENTRY);
942 if (ret)
943 return ret;
944 ret = fill_event_table(compat_sc_exit_table, ARRAY_SIZE(compat_sc_exit_table),
945 chan->compat_sc_exit_table, chan, filter,
946 SC_TYPE_COMPAT_EXIT);
947 if (ret)
948 return ret;
949#endif
950
951 if (!chan->sc_filter) {
952 chan->sc_filter = kzalloc(sizeof(struct lttng_syscall_filter),
953 GFP_KERNEL);
954 if (!chan->sc_filter)
955 return -ENOMEM;
956 }
957
958 if (!chan->sys_enter_registered) {
959 ret = lttng_wrapper_tracepoint_probe_register("sys_enter",
960 (void *) syscall_entry_event_probe, chan);
961 if (ret)
962 return ret;
963 chan->sys_enter_registered = 1;
964 }
965 /*
966 * We change the name of sys_exit tracepoint due to namespace
967 * conflict with sys_exit syscall entry.
968 */
969 if (!chan->sys_exit_registered) {
970 ret = lttng_wrapper_tracepoint_probe_register("sys_exit",
971 (void *) syscall_exit_event_probe, chan);
972 if (ret) {
973 WARN_ON_ONCE(lttng_wrapper_tracepoint_probe_unregister("sys_enter",
974 (void *) syscall_entry_event_probe, chan));
975 return ret;
976 }
977 chan->sys_exit_registered = 1;
978 }
979 return ret;
980}
981
982/*
983 * Should be called with sessions lock held.
984 */
985int lttng_syscalls_register_event_notifier(struct lttng_event_notifier_enabler *event_notifier_enabler, void *filter)
986{
987 struct lttng_event_notifier_group *group = event_notifier_enabler->group;
988 unsigned int i;
989 int ret = 0;
990
991 wrapper_vmalloc_sync_mappings();
992
993 if (!group->event_notifier_syscall_dispatch) {
994 group->event_notifier_syscall_dispatch = kzalloc(sizeof(struct list_head)
995 * ARRAY_SIZE(sc_table), GFP_KERNEL);
996 if (!group->event_notifier_syscall_dispatch)
997 return -ENOMEM;
998
999 /* Initialize all list_head */
1000 for (i = 0; i < ARRAY_SIZE(sc_table); i++)
1001 INIT_LIST_HEAD(&group->event_notifier_syscall_dispatch[i]);
1002 }
1003
1004#ifdef CONFIG_COMPAT
1005 if (!group->event_notifier_compat_syscall_dispatch) {
1006 group->event_notifier_compat_syscall_dispatch = kzalloc(sizeof(struct list_head)
1007 * ARRAY_SIZE(compat_sc_table), GFP_KERNEL);
1008 if (!group->event_notifier_syscall_dispatch)
1009 return -ENOMEM;
1010
1011 /* Initialize all list_head */
1012 for (i = 0; i < ARRAY_SIZE(compat_sc_table); i++)
1013 INIT_LIST_HEAD(&group->event_notifier_compat_syscall_dispatch[i]);
1014 }
1015#endif
1016
1017 if (!group->sys_enter_registered) {
1018 ret = lttng_wrapper_tracepoint_probe_register("sys_enter",
1019 (void *) syscall_entry_event_notifier_probe, group);
1020 if (ret)
1021 return ret;
1022 group->sys_enter_registered = 1;
1023 }
1024
1025 return ret;
1026}
1027
1028static int create_matching_event_notifiers(struct lttng_event_notifier_enabler *event_notifier_enabler,
1029 void *filter, const struct trace_syscall_entry *table,
1030 size_t table_len, bool is_compat)
1031{
1032 struct lttng_event_notifier_group *group = event_notifier_enabler->group;
1033 const struct lttng_event_desc *desc;
1034 uint64_t user_token = event_notifier_enabler->base.user_token;
1035 unsigned int i;
1036 int ret = 0;
1037
1038 /* iterate over all syscall and create event_notifier that match */
1039 for (i = 0; i < table_len; i++) {
1040 struct lttng_event_notifier *event_notifier;
1041 struct lttng_kernel_event_notifier event_notifier_param;
1042 struct hlist_head *head;
1043 int found = 0;
1044
1045 desc = table[i].desc;
1046 if (!desc) {
1047 /* Unknown syscall */
1048 continue;
1049 }
1050
1051 if (!lttng_desc_match_enabler(desc,
1052 lttng_event_notifier_enabler_as_enabler(event_notifier_enabler)))
1053 continue;
1054
1055 /*
1056 * Check if already created.
1057 */
1058 head = utils_borrow_hash_table_bucket(group->event_notifiers_ht.table,
1059 LTTNG_EVENT_NOTIFIER_HT_SIZE, desc->name);
1060 lttng_hlist_for_each_entry(event_notifier, head, hlist) {
1061 if (event_notifier->desc == desc
1062 && event_notifier->user_token == event_notifier_enabler->base.user_token)
1063 found = 1;
1064 }
1065 if (found)
1066 continue;
1067
1068 memset(&event_notifier_param, 0, sizeof(event_notifier_param));
1069 strncat(event_notifier_param.event.name, desc->name,
1070 LTTNG_KERNEL_SYM_NAME_LEN - strlen(event_notifier_param.event.name) - 1);
1071 event_notifier_param.event.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0';
1072 event_notifier_param.event.instrumentation = LTTNG_KERNEL_SYSCALL;
1073
1074 event_notifier = _lttng_event_notifier_create(desc, user_token, group,
1075 &event_notifier_param, filter,
1076 event_notifier_param.event.instrumentation);
1077 if (IS_ERR(event_notifier)) {
1078 printk(KERN_INFO "Unable to create event_notifier %s\n",
1079 desc->name);
1080 ret = -ENOMEM;
1081 goto end;
1082 }
1083
1084 event_notifier->u.syscall.syscall_id = i;
1085 event_notifier->u.syscall.is_compat = is_compat;
1086 }
1087end:
1088 return ret;
1089
1090}
1091
1092int lttng_syscals_create_matching_event_notifiers(struct lttng_event_notifier_enabler *event_notifier_enabler, void *filter)
1093{
1094 int ret;
1095
1096 ret = create_matching_event_notifiers(event_notifier_enabler, filter, sc_table,
1097 ARRAY_SIZE(sc_table), false);
1098 if (ret)
1099 goto end;
1100
1101 ret = create_matching_event_notifiers(event_notifier_enabler, filter, compat_sc_table,
1102 ARRAY_SIZE(compat_sc_table), true);
1103end:
1104 return ret;
1105}
1106
1107/*
1108 * Unregister the syscall event_notifier probes from the callsites.
1109 */
1110int lttng_syscalls_unregister_event_notifier(struct lttng_event_notifier_group *event_notifier_group)
1111{
1112 int ret;
1113
1114 /*
1115 * Only register the event_notifier probe on the `sys_enter` callsite for now.
1116 * At the moment, we don't think it's desirable to have one fired
1117 * event_notifier for the entry and one for the exit of a syscall.
1118 */
1119 if (event_notifier_group->sys_enter_registered) {
1120 ret = lttng_wrapper_tracepoint_probe_unregister("sys_enter",
1121 (void *) syscall_entry_event_notifier_probe, event_notifier_group);
1122 if (ret)
1123 return ret;
1124 event_notifier_group->sys_enter_registered = 0;
1125 }
1126
1127 kfree(event_notifier_group->event_notifier_syscall_dispatch);
1128#ifdef CONFIG_COMPAT
1129 kfree(event_notifier_group->event_notifier_compat_syscall_dispatch);
1130#endif
1131 return 0;
1132}
1133
1134int lttng_syscalls_unregister_event(struct lttng_channel *chan)
1135{
1136 int ret;
1137
1138 if (!chan->sc_table)
1139 return 0;
1140 if (chan->sys_enter_registered) {
1141 ret = lttng_wrapper_tracepoint_probe_unregister("sys_enter",
1142 (void *) syscall_entry_event_probe, chan);
1143 if (ret)
1144 return ret;
1145 chan->sys_enter_registered = 0;
1146 }
1147 if (chan->sys_exit_registered) {
1148 ret = lttng_wrapper_tracepoint_probe_unregister("sys_exit",
1149 (void *) syscall_exit_event_probe, chan);
1150 if (ret)
1151 return ret;
1152 chan->sys_exit_registered = 0;
1153 }
1154 return 0;
1155}
1156
1157int lttng_syscalls_destroy_event(struct lttng_channel *chan)
1158{
1159 kfree(chan->sc_table);
1160 kfree(chan->sc_exit_table);
1161#ifdef CONFIG_COMPAT
1162 kfree(chan->compat_sc_table);
1163 kfree(chan->compat_sc_exit_table);
1164#endif
1165 kfree(chan->sc_filter);
1166 return 0;
1167}
1168
1169static
1170int get_syscall_nr(const char *syscall_name)
1171{
1172 int syscall_nr = -1;
1173 int i;
1174
1175 for (i = 0; i < ARRAY_SIZE(sc_table); i++) {
1176 const struct trace_syscall_entry *entry;
1177 const char *it_name;
1178
1179 entry = &sc_table[i];
1180 if (!entry->desc)
1181 continue;
1182 it_name = entry->desc->name;
1183 it_name += strlen(SYSCALL_ENTRY_STR);
1184 if (!strcmp(syscall_name, it_name)) {
1185 syscall_nr = i;
1186 break;
1187 }
1188 }
1189 return syscall_nr;
1190}
1191
1192static
1193int get_compat_syscall_nr(const char *syscall_name)
1194{
1195 int syscall_nr = -1;
1196 int i;
1197
1198 for (i = 0; i < ARRAY_SIZE(compat_sc_table); i++) {
1199 const struct trace_syscall_entry *entry;
1200 const char *it_name;
1201
1202 entry = &compat_sc_table[i];
1203 if (!entry->desc)
1204 continue;
1205 it_name = entry->desc->name;
1206 it_name += strlen(COMPAT_SYSCALL_ENTRY_STR);
1207 if (!strcmp(syscall_name, it_name)) {
1208 syscall_nr = i;
1209 break;
1210 }
1211 }
1212 return syscall_nr;
1213}
1214
1215static
1216uint32_t get_sc_tables_len(void)
1217{
1218 return ARRAY_SIZE(sc_table) + ARRAY_SIZE(compat_sc_table);
1219}
1220
1221static
1222const char *get_syscall_name(struct lttng_event *event)
1223{
1224 size_t prefix_len = 0;
1225
1226 WARN_ON_ONCE(event->instrumentation != LTTNG_KERNEL_SYSCALL);
1227
1228 switch (event->u.syscall.entryexit) {
1229 case LTTNG_SYSCALL_ENTRY:
1230 switch (event->u.syscall.abi) {
1231 case LTTNG_SYSCALL_ABI_NATIVE:
1232 prefix_len = strlen(SYSCALL_ENTRY_STR);
1233 break;
1234 case LTTNG_SYSCALL_ABI_COMPAT:
1235 prefix_len = strlen(COMPAT_SYSCALL_ENTRY_STR);
1236 break;
1237 }
1238 break;
1239 case LTTNG_SYSCALL_EXIT:
1240 switch (event->u.syscall.abi) {
1241 case LTTNG_SYSCALL_ABI_NATIVE:
1242 prefix_len = strlen(SYSCALL_EXIT_STR);
1243 break;
1244 case LTTNG_SYSCALL_ABI_COMPAT:
1245 prefix_len = strlen(COMPAT_SYSCALL_EXIT_STR);
1246 break;
1247 }
1248 break;
1249 }
1250 WARN_ON_ONCE(prefix_len == 0);
1251 return event->desc->name + prefix_len;
1252}
1253
1254int lttng_syscall_filter_enable_event(struct lttng_channel *chan,
1255 struct lttng_event *event)
1256{
1257 struct lttng_syscall_filter *filter = chan->sc_filter;
1258 const char *syscall_name;
1259 unsigned long *bitmap;
1260 int syscall_nr;
1261
1262 WARN_ON_ONCE(!chan->sc_table);
1263
1264 syscall_name = get_syscall_name(event);
1265
1266 switch (event->u.syscall.abi) {
1267 case LTTNG_SYSCALL_ABI_NATIVE:
1268 syscall_nr = get_syscall_nr(syscall_name);
1269 break;
1270 case LTTNG_SYSCALL_ABI_COMPAT:
1271 syscall_nr = get_compat_syscall_nr(syscall_name);
1272 break;
1273 default:
1274 return -EINVAL;
1275 }
1276 if (syscall_nr < 0)
1277 return -ENOENT;
1278
1279 switch (event->u.syscall.entryexit) {
1280 case LTTNG_SYSCALL_ENTRY:
1281 switch (event->u.syscall.abi) {
1282 case LTTNG_SYSCALL_ABI_NATIVE:
1283 bitmap = filter->sc_entry;
1284 break;
1285 case LTTNG_SYSCALL_ABI_COMPAT:
1286 bitmap = filter->sc_compat_entry;
1287 break;
1288 default:
1289 return -EINVAL;
1290 }
1291 break;
1292 case LTTNG_SYSCALL_EXIT:
1293 switch (event->u.syscall.abi) {
1294 case LTTNG_SYSCALL_ABI_NATIVE:
1295 bitmap = filter->sc_exit;
1296 break;
1297 case LTTNG_SYSCALL_ABI_COMPAT:
1298 bitmap = filter->sc_compat_exit;
1299 break;
1300 default:
1301 return -EINVAL;
1302 }
1303 break;
1304 default:
1305 return -EINVAL;
1306 }
1307 if (test_bit(syscall_nr, bitmap))
1308 return -EEXIST;
1309 bitmap_set(bitmap, syscall_nr, 1);
1310 return 0;
1311}
1312
1313int lttng_syscall_filter_enable_event_notifier(
1314 struct lttng_event_notifier *event_notifier)
1315{
1316 struct lttng_event_notifier_group *group = event_notifier->group;
1317 unsigned int syscall_id = event_notifier->u.syscall.syscall_id;
1318 struct list_head *dispatch_list;
1319
1320 if (event_notifier->u.syscall.is_compat)
1321 dispatch_list = &group->event_notifier_compat_syscall_dispatch[syscall_id];
1322 else
1323 dispatch_list = &group->event_notifier_syscall_dispatch[syscall_id];
1324
1325 list_add_rcu(&event_notifier->u.syscall.node, dispatch_list);
1326
1327 return 0;
1328}
1329
1330int lttng_syscall_filter_disable_event(struct lttng_channel *chan,
1331 struct lttng_event *event)
1332{
1333 struct lttng_syscall_filter *filter = chan->sc_filter;
1334 const char *syscall_name;
1335 unsigned long *bitmap;
1336 int syscall_nr;
1337
1338 WARN_ON_ONCE(!chan->sc_table);
1339
1340 syscall_name = get_syscall_name(event);
1341
1342 switch (event->u.syscall.abi) {
1343 case LTTNG_SYSCALL_ABI_NATIVE:
1344 syscall_nr = get_syscall_nr(syscall_name);
1345 break;
1346 case LTTNG_SYSCALL_ABI_COMPAT:
1347 syscall_nr = get_compat_syscall_nr(syscall_name);
1348 break;
1349 default:
1350 return -EINVAL;
1351 }
1352 if (syscall_nr < 0)
1353 return -ENOENT;
1354
1355 switch (event->u.syscall.entryexit) {
1356 case LTTNG_SYSCALL_ENTRY:
1357 switch (event->u.syscall.abi) {
1358 case LTTNG_SYSCALL_ABI_NATIVE:
1359 bitmap = filter->sc_entry;
1360 break;
1361 case LTTNG_SYSCALL_ABI_COMPAT:
1362 bitmap = filter->sc_compat_entry;
1363 break;
1364 default:
1365 return -EINVAL;
1366 }
1367 break;
1368 case LTTNG_SYSCALL_EXIT:
1369 switch (event->u.syscall.abi) {
1370 case LTTNG_SYSCALL_ABI_NATIVE:
1371 bitmap = filter->sc_exit;
1372 break;
1373 case LTTNG_SYSCALL_ABI_COMPAT:
1374 bitmap = filter->sc_compat_exit;
1375 break;
1376 default:
1377 return -EINVAL;
1378 }
1379 break;
1380 default:
1381 return -EINVAL;
1382 }
1383 if (!test_bit(syscall_nr, bitmap))
1384 return -EEXIST;
1385 bitmap_clear(bitmap, syscall_nr, 1);
1386
1387 return 0;
1388}
1389
1390int lttng_syscall_filter_disable_event_notifier(
1391 struct lttng_event_notifier *event_notifier)
1392{
1393 list_del_rcu(&event_notifier->u.syscall.node);
1394 return 0;
1395}
1396
1397static
1398const struct trace_syscall_entry *syscall_list_get_entry(loff_t *pos)
1399{
1400 const struct trace_syscall_entry *entry;
1401 int iter = 0;
1402
1403 for (entry = sc_table;
1404 entry < sc_table + ARRAY_SIZE(sc_table);
1405 entry++) {
1406 if (iter++ >= *pos)
1407 return entry;
1408 }
1409 for (entry = compat_sc_table;
1410 entry < compat_sc_table + ARRAY_SIZE(compat_sc_table);
1411 entry++) {
1412 if (iter++ >= *pos)
1413 return entry;
1414 }
1415 /* End of list */
1416 return NULL;
1417}
1418
1419static
1420void *syscall_list_start(struct seq_file *m, loff_t *pos)
1421{
1422 return (void *) syscall_list_get_entry(pos);
1423}
1424
1425static
1426void *syscall_list_next(struct seq_file *m, void *p, loff_t *ppos)
1427{
1428 (*ppos)++;
1429 return (void *) syscall_list_get_entry(ppos);
1430}
1431
1432static
1433void syscall_list_stop(struct seq_file *m, void *p)
1434{
1435}
1436
1437static
1438int get_sc_table(const struct trace_syscall_entry *entry,
1439 const struct trace_syscall_entry **table,
1440 unsigned int *bitness)
1441{
1442 if (entry >= sc_table && entry < sc_table + ARRAY_SIZE(sc_table)) {
1443 if (bitness)
1444 *bitness = BITS_PER_LONG;
1445 if (table)
1446 *table = sc_table;
1447 return 0;
1448 }
1449 if (!(entry >= compat_sc_table
1450 && entry < compat_sc_table + ARRAY_SIZE(compat_sc_table))) {
1451 return -EINVAL;
1452 }
1453 if (bitness)
1454 *bitness = 32;
1455 if (table)
1456 *table = compat_sc_table;
1457 return 0;
1458}
1459
1460static
1461int syscall_list_show(struct seq_file *m, void *p)
1462{
1463 const struct trace_syscall_entry *table, *entry = p;
1464 unsigned int bitness;
1465 unsigned long index;
1466 int ret;
1467 const char *name;
1468
1469 ret = get_sc_table(entry, &table, &bitness);
1470 if (ret)
1471 return ret;
1472 if (!entry->desc)
1473 return 0;
1474 if (table == sc_table) {
1475 index = entry - table;
1476 name = &entry->desc->name[strlen(SYSCALL_ENTRY_STR)];
1477 } else {
1478 index = (entry - table) + ARRAY_SIZE(sc_table);
1479 name = &entry->desc->name[strlen(COMPAT_SYSCALL_ENTRY_STR)];
1480 }
1481 seq_printf(m, "syscall { index = %lu; name = %s; bitness = %u; };\n",
1482 index, name, bitness);
1483 return 0;
1484}
1485
1486static
1487const struct seq_operations lttng_syscall_list_seq_ops = {
1488 .start = syscall_list_start,
1489 .next = syscall_list_next,
1490 .stop = syscall_list_stop,
1491 .show = syscall_list_show,
1492};
1493
1494static
1495int lttng_syscall_list_open(struct inode *inode, struct file *file)
1496{
1497 return seq_open(file, &lttng_syscall_list_seq_ops);
1498}
1499
1500const struct file_operations lttng_syscall_list_fops = {
1501 .owner = THIS_MODULE,
1502 .open = lttng_syscall_list_open,
1503 .read = seq_read,
1504 .llseek = seq_lseek,
1505 .release = seq_release,
1506};
1507
1508/*
1509 * A syscall is enabled if it is traced for either entry or exit.
1510 */
1511long lttng_channel_syscall_mask(struct lttng_channel *channel,
1512 struct lttng_kernel_syscall_mask __user *usyscall_mask)
1513{
1514 uint32_t len, sc_tables_len, bitmask_len;
1515 int ret = 0, bit;
1516 char *tmp_mask;
1517 struct lttng_syscall_filter *filter;
1518
1519 ret = get_user(len, &usyscall_mask->len);
1520 if (ret)
1521 return ret;
1522 sc_tables_len = get_sc_tables_len();
1523 bitmask_len = ALIGN(sc_tables_len, 8) >> 3;
1524 if (len < sc_tables_len) {
1525 return put_user(sc_tables_len, &usyscall_mask->len);
1526 }
1527 /* Array is large enough, we can copy array to user-space. */
1528 tmp_mask = kzalloc(bitmask_len, GFP_KERNEL);
1529 if (!tmp_mask)
1530 return -ENOMEM;
1531 filter = channel->sc_filter;
1532
1533 for (bit = 0; bit < ARRAY_SIZE(sc_table); bit++) {
1534 char state;
1535
1536 if (channel->sc_table) {
1537 if (!READ_ONCE(channel->syscall_all) && filter)
1538 state = test_bit(bit, filter->sc_entry)
1539 || test_bit(bit, filter->sc_exit);
1540 else
1541 state = 1;
1542 } else {
1543 state = 0;
1544 }
1545 bt_bitfield_write_be(tmp_mask, char, bit, 1, state);
1546 }
1547 for (; bit < sc_tables_len; bit++) {
1548 char state;
1549
1550 if (channel->compat_sc_table) {
1551 if (!READ_ONCE(channel->syscall_all) && filter)
1552 state = test_bit(bit - ARRAY_SIZE(sc_table),
1553 filter->sc_compat_entry)
1554 || test_bit(bit - ARRAY_SIZE(sc_table),
1555 filter->sc_compat_exit);
1556 else
1557 state = 1;
1558 } else {
1559 state = 0;
1560 }
1561 bt_bitfield_write_be(tmp_mask, char, bit, 1, state);
1562 }
1563 if (copy_to_user(usyscall_mask->mask, tmp_mask, bitmask_len))
1564 ret = -EFAULT;
1565 kfree(tmp_mask);
1566 return ret;
1567}
1568
1569int lttng_abi_syscall_list(void)
1570{
1571 struct file *syscall_list_file;
1572 int file_fd, ret;
1573
1574 file_fd = lttng_get_unused_fd();
1575 if (file_fd < 0) {
1576 ret = file_fd;
1577 goto fd_error;
1578 }
1579
1580 syscall_list_file = anon_inode_getfile("[lttng_syscall_list]",
1581 &lttng_syscall_list_fops,
1582 NULL, O_RDWR);
1583 if (IS_ERR(syscall_list_file)) {
1584 ret = PTR_ERR(syscall_list_file);
1585 goto file_error;
1586 }
1587 ret = lttng_syscall_list_fops.open(NULL, syscall_list_file);
1588 if (ret < 0)
1589 goto open_error;
1590 fd_install(file_fd, syscall_list_file);
1591 return file_fd;
1592
1593open_error:
1594 fput(syscall_list_file);
1595file_error:
1596 put_unused_fd(file_fd);
1597fd_error:
1598 return ret;
1599}
This page took 0.028148 seconds and 4 git commands to generate.