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