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