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