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