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