X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=lttng-syscalls.c;h=97a12c4835a896e0a0e050c98d5aa5cd0e25af5a;hb=refs%2Fheads%2Fstable-2.12;hp=0b980a1a92be53dc11442e672ff7f1ab0b08b5c6;hpb=e2129868ffc39d0277d39f67084398e2412cf7c6;p=lttng-modules.git diff --git a/lttng-syscalls.c b/lttng-syscalls.c index 0b980a1a..97a12c48 100644 --- a/lttng-syscalls.c +++ b/lttng-syscalls.c @@ -1,23 +1,10 @@ -/* +/* SPDX-License-Identifier: (GPL-2.0 or LGPL-2.1) + * * lttng-syscalls.c * * LTTng syscall probes. * * Copyright (C) 2010-2012 Mathieu Desnoyers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; only - * version 2.1 of the License. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include @@ -38,7 +25,9 @@ #include #include #include +#include #include +#include #ifndef CONFIG_COMPAT # ifndef is_compat_task @@ -48,7 +37,14 @@ /* in_compat_syscall appears in kernel 4.6. */ #ifndef in_compat_syscall - #define in_compat_syscall() is_compat_task() +# define in_compat_syscall() is_compat_task() +#endif + +/* in_x32_syscall appears in kernel 4.7. */ +#if (LTTNG_LINUX_VERSION_CODE < LTTNG_KERNEL_VERSION(4,7,0)) +# ifdef CONFIG_X86_X32_ABI +# define in_x32_syscall() is_x32_task() +# endif #endif enum sc_type { @@ -85,6 +81,18 @@ struct mmap_arg_struct; struct file_handle; struct user_msghdr; +/* + * Forward declaration for kernels >= 5.6 + */ +struct timex; +struct timeval; +struct itimerval; +struct itimerspec; + +#if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(5,6,0)) +typedef __kernel_old_time_t time_t; +#endif + #ifdef IA32_NR_syscalls #define NR_compat_syscalls IA32_NR_syscalls #else @@ -367,16 +375,18 @@ const struct trace_syscall_entry compat_sc_exit_table[] = { #undef CREATE_SYSCALL_TABLE struct lttng_syscall_filter { - DECLARE_BITMAP(sc, NR_syscalls); - DECLARE_BITMAP(sc_compat, NR_compat_syscalls); + DECLARE_BITMAP(sc_entry, NR_syscalls); + DECLARE_BITMAP(sc_exit, NR_syscalls); + DECLARE_BITMAP(sc_compat_entry, NR_compat_syscalls); + DECLARE_BITMAP(sc_compat_exit, NR_compat_syscalls); }; static void syscall_entry_unknown(struct lttng_event *event, struct pt_regs *regs, unsigned int id) { - unsigned long args[UNKNOWN_SYSCALL_NRARGS]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args); + lttng_syscall_get_arguments(current, regs, args); if (unlikely(in_compat_syscall())) __event_probe__compat_syscall_entry_unknown(event, id, args); else @@ -390,30 +400,30 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id) const struct trace_syscall_entry *table, *entry; size_t table_len; +#ifdef CONFIG_X86_X32_ABI + if (in_x32_syscall()) { + /* x32 system calls are not supported. */ + return; + } +#endif if (unlikely(in_compat_syscall())) { - struct lttng_syscall_filter *filter; - - filter = lttng_rcu_dereference(chan->sc_filter); - if (filter) { - if (id < 0 || id >= NR_compat_syscalls - || !test_bit(id, filter->sc_compat)) { - /* System call filtered out. */ - return; - } + struct lttng_syscall_filter *filter = chan->sc_filter; + + if (id < 0 || id >= NR_compat_syscalls + || (!READ_ONCE(chan->syscall_all) && !test_bit(id, filter->sc_compat_entry))) { + /* System call filtered out. */ + return; } table = compat_sc_table; table_len = ARRAY_SIZE(compat_sc_table); unknown_event = chan->sc_compat_unknown; } else { - struct lttng_syscall_filter *filter; - - filter = lttng_rcu_dereference(chan->sc_filter); - if (filter) { - if (id < 0 || id >= NR_syscalls - || !test_bit(id, filter->sc)) { - /* System call filtered out. */ - return; - } + struct lttng_syscall_filter *filter = chan->sc_filter; + + if (id < 0 || id >= NR_syscalls + || (!READ_ONCE(chan->syscall_all) && !test_bit(id, filter->sc_entry))) { + /* System call filtered out. */ + return; } table = sc_table; table_len = ARRAY_SIZE(sc_table); @@ -445,9 +455,9 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id) case 1: { void (*fptr)(void *__data, unsigned long arg0) = entry->func; - unsigned long args[1]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, args[0]); break; } @@ -456,9 +466,9 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id) void (*fptr)(void *__data, unsigned long arg0, unsigned long arg1) = entry->func; - unsigned long args[2]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, args[0], args[1]); break; } @@ -468,9 +478,9 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id) unsigned long arg0, unsigned long arg1, unsigned long arg2) = entry->func; - unsigned long args[3]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, args[0], args[1], args[2]); break; } @@ -481,9 +491,9 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id) unsigned long arg1, unsigned long arg2, unsigned long arg3) = entry->func; - unsigned long args[4]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, args[0], args[1], args[2], args[3]); break; } @@ -495,9 +505,9 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id) unsigned long arg2, unsigned long arg3, unsigned long arg4) = entry->func; - unsigned long args[5]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, args[0], args[1], args[2], args[3], args[4]); break; } @@ -510,9 +520,9 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id) unsigned long arg3, unsigned long arg4, unsigned long arg5) = entry->func; - unsigned long args[6]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, args[0], args[1], args[2], args[3], args[4], args[5]); break; @@ -525,9 +535,9 @@ void syscall_entry_probe(void *__data, struct pt_regs *regs, long id) static void syscall_exit_unknown(struct lttng_event *event, struct pt_regs *regs, int id, long ret) { - unsigned long args[UNKNOWN_SYSCALL_NRARGS]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, UNKNOWN_SYSCALL_NRARGS, args); + lttng_syscall_get_arguments(current, regs, args); if (unlikely(in_compat_syscall())) __event_probe__compat_syscall_exit_unknown(event, id, ret, args); @@ -543,31 +553,31 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret) size_t table_len; long id; +#ifdef CONFIG_X86_X32_ABI + if (in_x32_syscall()) { + /* x32 system calls are not supported. */ + return; + } +#endif id = syscall_get_nr(current, regs); if (unlikely(in_compat_syscall())) { - struct lttng_syscall_filter *filter; - - filter = lttng_rcu_dereference(chan->sc_filter); - if (filter) { - if (id < 0 || id >= NR_compat_syscalls - || !test_bit(id, filter->sc_compat)) { - /* System call filtered out. */ - return; - } + struct lttng_syscall_filter *filter = chan->sc_filter; + + if (id < 0 || id >= NR_compat_syscalls + || (!READ_ONCE(chan->syscall_all) && !test_bit(id, filter->sc_compat_exit))) { + /* System call filtered out. */ + return; } table = compat_sc_exit_table; table_len = ARRAY_SIZE(compat_sc_exit_table); unknown_event = chan->compat_sc_exit_unknown; } else { - struct lttng_syscall_filter *filter; - - filter = lttng_rcu_dereference(chan->sc_filter); - if (filter) { - if (id < 0 || id >= NR_syscalls - || !test_bit(id, filter->sc)) { - /* System call filtered out. */ - return; - } + struct lttng_syscall_filter *filter = chan->sc_filter; + + if (id < 0 || id >= NR_syscalls + || (!READ_ONCE(chan->syscall_all) && !test_bit(id, filter->sc_exit))) { + /* System call filtered out. */ + return; } table = sc_exit_table; table_len = ARRAY_SIZE(sc_exit_table); @@ -601,9 +611,9 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret) void (*fptr)(void *__data, long ret, unsigned long arg0) = entry->func; - unsigned long args[1]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, ret, args[0]); break; } @@ -613,9 +623,9 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret) long ret, unsigned long arg0, unsigned long arg1) = entry->func; - unsigned long args[2]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, ret, args[0], args[1]); break; } @@ -626,9 +636,9 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret) unsigned long arg0, unsigned long arg1, unsigned long arg2) = entry->func; - unsigned long args[3]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, ret, args[0], args[1], args[2]); break; } @@ -640,9 +650,9 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret) unsigned long arg1, unsigned long arg2, unsigned long arg3) = entry->func; - unsigned long args[4]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, ret, args[0], args[1], args[2], args[3]); break; } @@ -655,9 +665,9 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret) unsigned long arg2, unsigned long arg3, unsigned long arg4) = entry->func; - unsigned long args[5]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, ret, args[0], args[1], args[2], args[3], args[4]); break; } @@ -671,9 +681,9 @@ void syscall_exit_probe(void *__data, struct pt_regs *regs, long ret) unsigned long arg3, unsigned long arg4, unsigned long arg5) = entry->func; - unsigned long args[6]; + unsigned long args[LTTNG_SYSCALL_NR_ARGS]; - syscall_get_arguments(current, regs, 0, entry->nrargs, args); + lttng_syscall_get_arguments(current, regs, args); fptr(event, ret, args[0], args[1], args[2], args[3], args[4], args[5]); break; @@ -713,27 +723,23 @@ int fill_table(const struct trace_syscall_entry *table, size_t table_len, memset(&ev, 0, sizeof(ev)); switch (type) { case SC_TYPE_ENTRY: - strncpy(ev.name, SYSCALL_ENTRY_STR, - LTTNG_KERNEL_SYM_NAME_LEN); + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY; + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE; break; case SC_TYPE_EXIT: - strncpy(ev.name, SYSCALL_EXIT_STR, - LTTNG_KERNEL_SYM_NAME_LEN); + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT; + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE; break; case SC_TYPE_COMPAT_ENTRY: - strncpy(ev.name, COMPAT_SYSCALL_ENTRY_STR, - LTTNG_KERNEL_SYM_NAME_LEN); + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY; + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT; break; case SC_TYPE_COMPAT_EXIT: - strncpy(ev.name, COMPAT_SYSCALL_EXIT_STR, - LTTNG_KERNEL_SYM_NAME_LEN); - break; - default: - BUG_ON(1); + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT; + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT; break; } - strncat(ev.name, desc->name, - LTTNG_KERNEL_SYM_NAME_LEN - strlen(ev.name) - 1); + strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN - 1); ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; ev.instrumentation = LTTNG_KERNEL_SYSCALL; chan_table[i] = _lttng_event_create(chan, &ev, filter, @@ -760,7 +766,7 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) struct lttng_kernel_event ev; int ret; - wrapper_vmalloc_sync_all(); + wrapper_vmalloc_sync_mappings(); if (!chan->sc_table) { /* create syscall table mapping syscall to events */ @@ -803,6 +809,8 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN); ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; ev.instrumentation = LTTNG_KERNEL_SYSCALL; + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY; + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE; chan->sc_unknown = _lttng_event_create(chan, &ev, filter, desc, ev.instrumentation); @@ -820,6 +828,8 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN); ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; ev.instrumentation = LTTNG_KERNEL_SYSCALL; + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_ENTRY; + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT; chan->sc_compat_unknown = _lttng_event_create(chan, &ev, filter, desc, ev.instrumentation); @@ -837,6 +847,8 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN); ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; ev.instrumentation = LTTNG_KERNEL_SYSCALL; + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT; + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_COMPAT; chan->compat_sc_exit_unknown = _lttng_event_create(chan, &ev, filter, desc, ev.instrumentation); @@ -854,6 +866,8 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) strncpy(ev.name, desc->name, LTTNG_KERNEL_SYM_NAME_LEN); ev.name[LTTNG_KERNEL_SYM_NAME_LEN - 1] = '\0'; ev.instrumentation = LTTNG_KERNEL_SYSCALL; + ev.u.syscall.entryexit = LTTNG_KERNEL_SYSCALL_EXIT; + ev.u.syscall.abi = LTTNG_KERNEL_SYSCALL_ABI_NATIVE; chan->sc_exit_unknown = _lttng_event_create(chan, &ev, filter, desc, ev.instrumentation); WARN_ON_ONCE(!chan->sc_exit_unknown); @@ -883,6 +897,14 @@ int lttng_syscalls_register(struct lttng_channel *chan, void *filter) if (ret) return ret; #endif + + if (!chan->sc_filter) { + chan->sc_filter = kzalloc(sizeof(struct lttng_syscall_filter), + GFP_KERNEL); + if (!chan->sc_filter) + return -ENOMEM; + } + if (!chan->sys_enter_registered) { ret = lttng_wrapper_tracepoint_probe_register("sys_enter", (void *) syscall_entry_probe, chan); @@ -917,20 +939,24 @@ int lttng_syscalls_unregister(struct lttng_channel *chan) if (!chan->sc_table) return 0; if (chan->sys_enter_registered) { - ret = lttng_wrapper_tracepoint_probe_unregister("sys_exit", - (void *) syscall_exit_probe, chan); + ret = lttng_wrapper_tracepoint_probe_unregister("sys_enter", + (void *) syscall_entry_probe, chan); if (ret) return ret; chan->sys_enter_registered = 0; } if (chan->sys_exit_registered) { - ret = lttng_wrapper_tracepoint_probe_unregister("sys_enter", - (void *) syscall_entry_probe, chan); + ret = lttng_wrapper_tracepoint_probe_unregister("sys_exit", + (void *) syscall_exit_probe, chan); if (ret) return ret; chan->sys_exit_registered = 0; } - /* lttng_event destroy will be performed by lttng_session_destroy() */ + return 0; +} + +int lttng_syscalls_destroy(struct lttng_channel *chan) +{ kfree(chan->sc_table); kfree(chan->sc_exit_table); #ifdef CONFIG_COMPAT @@ -993,136 +1019,156 @@ uint32_t get_sc_tables_len(void) return ARRAY_SIZE(sc_table) + ARRAY_SIZE(compat_sc_table); } -int lttng_syscall_filter_enable(struct lttng_channel *chan, - const char *name) +static +const char *get_syscall_name(struct lttng_event *event) { - int syscall_nr, compat_syscall_nr, ret; - struct lttng_syscall_filter *filter; + size_t prefix_len = 0; - WARN_ON_ONCE(!chan->sc_table); + WARN_ON_ONCE(event->instrumentation != LTTNG_KERNEL_SYSCALL); - if (!name) { - /* Enable all system calls by removing filter */ - if (chan->sc_filter) { - filter = chan->sc_filter; - rcu_assign_pointer(chan->sc_filter, NULL); - synchronize_trace(); - kfree(filter); + switch (event->u.syscall.entryexit) { + case LTTNG_SYSCALL_ENTRY: + switch (event->u.syscall.abi) { + case LTTNG_SYSCALL_ABI_NATIVE: + prefix_len = strlen(SYSCALL_ENTRY_STR); + break; + case LTTNG_SYSCALL_ABI_COMPAT: + prefix_len = strlen(COMPAT_SYSCALL_ENTRY_STR); + break; } - chan->syscall_all = 1; - return 0; - } - - if (!chan->sc_filter) { - if (chan->syscall_all) { - /* - * All syscalls are already enabled. - */ - return -EEXIST; + break; + case LTTNG_SYSCALL_EXIT: + switch (event->u.syscall.abi) { + case LTTNG_SYSCALL_ABI_NATIVE: + prefix_len = strlen(SYSCALL_EXIT_STR); + break; + case LTTNG_SYSCALL_ABI_COMPAT: + prefix_len = strlen(COMPAT_SYSCALL_EXIT_STR); + break; } - filter = kzalloc(sizeof(struct lttng_syscall_filter), - GFP_KERNEL); - if (!filter) - return -ENOMEM; - } else { - filter = chan->sc_filter; + break; } - syscall_nr = get_syscall_nr(name); - compat_syscall_nr = get_compat_syscall_nr(name); - if (syscall_nr < 0 && compat_syscall_nr < 0) { - ret = -ENOENT; - goto error; + WARN_ON_ONCE(prefix_len == 0); + return event->desc->name + prefix_len; +} + +int lttng_syscall_filter_enable(struct lttng_channel *chan, + struct lttng_event *event) +{ + struct lttng_syscall_filter *filter = chan->sc_filter; + const char *syscall_name; + unsigned long *bitmap; + int syscall_nr; + + WARN_ON_ONCE(!chan->sc_table); + + syscall_name = get_syscall_name(event); + + switch (event->u.syscall.abi) { + case LTTNG_SYSCALL_ABI_NATIVE: + syscall_nr = get_syscall_nr(syscall_name); + break; + case LTTNG_SYSCALL_ABI_COMPAT: + syscall_nr = get_compat_syscall_nr(syscall_name); + break; + default: + return -EINVAL; } - if (syscall_nr >= 0) { - if (test_bit(syscall_nr, filter->sc)) { - ret = -EEXIST; - goto error; + if (syscall_nr < 0) + return -ENOENT; + + switch (event->u.syscall.entryexit) { + case LTTNG_SYSCALL_ENTRY: + switch (event->u.syscall.abi) { + case LTTNG_SYSCALL_ABI_NATIVE: + bitmap = filter->sc_entry; + break; + case LTTNG_SYSCALL_ABI_COMPAT: + bitmap = filter->sc_compat_entry; + break; + default: + return -EINVAL; } - bitmap_set(filter->sc, syscall_nr, 1); - } - if (compat_syscall_nr >= 0) { - if (test_bit(compat_syscall_nr, filter->sc_compat)) { - ret = -EEXIST; - goto error; + break; + case LTTNG_SYSCALL_EXIT: + switch (event->u.syscall.abi) { + case LTTNG_SYSCALL_ABI_NATIVE: + bitmap = filter->sc_exit; + break; + case LTTNG_SYSCALL_ABI_COMPAT: + bitmap = filter->sc_compat_exit; + break; + default: + return -EINVAL; } - bitmap_set(filter->sc_compat, compat_syscall_nr, 1); + break; + default: + return -EINVAL; } - if (!chan->sc_filter) - rcu_assign_pointer(chan->sc_filter, filter); + if (test_bit(syscall_nr, bitmap)) + return -EEXIST; + bitmap_set(bitmap, syscall_nr, 1); return 0; - -error: - if (!chan->sc_filter) - kfree(filter); - return ret; } int lttng_syscall_filter_disable(struct lttng_channel *chan, - const char *name) + struct lttng_event *event) { - int syscall_nr, compat_syscall_nr, ret; - struct lttng_syscall_filter *filter; + struct lttng_syscall_filter *filter = chan->sc_filter; + const char *syscall_name; + unsigned long *bitmap; + int syscall_nr; WARN_ON_ONCE(!chan->sc_table); - if (!chan->sc_filter) { - if (!chan->syscall_all) - return -EEXIST; - filter = kzalloc(sizeof(struct lttng_syscall_filter), - GFP_KERNEL); - if (!filter) - return -ENOMEM; - /* Trace all system calls, then apply disable. */ - bitmap_set(filter->sc, 0, NR_syscalls); - bitmap_set(filter->sc_compat, 0, NR_compat_syscalls); - } else { - filter = chan->sc_filter; - } - - if (!name) { - /* Fail if all syscalls are already disabled. */ - if (bitmap_empty(filter->sc, NR_syscalls) - && bitmap_empty(filter->sc_compat, - NR_compat_syscalls)) { - ret = -EEXIST; - goto error; - } + syscall_name = get_syscall_name(event); - /* Disable all system calls */ - bitmap_clear(filter->sc, 0, NR_syscalls); - bitmap_clear(filter->sc_compat, 0, NR_compat_syscalls); - goto apply_filter; - } - syscall_nr = get_syscall_nr(name); - compat_syscall_nr = get_compat_syscall_nr(name); - if (syscall_nr < 0 && compat_syscall_nr < 0) { - ret = -ENOENT; - goto error; + switch (event->u.syscall.abi) { + case LTTNG_SYSCALL_ABI_NATIVE: + syscall_nr = get_syscall_nr(syscall_name); + break; + case LTTNG_SYSCALL_ABI_COMPAT: + syscall_nr = get_compat_syscall_nr(syscall_name); + break; + default: + return -EINVAL; } - if (syscall_nr >= 0) { - if (!test_bit(syscall_nr, filter->sc)) { - ret = -EEXIST; - goto error; + if (syscall_nr < 0) + return -ENOENT; + + switch (event->u.syscall.entryexit) { + case LTTNG_SYSCALL_ENTRY: + switch (event->u.syscall.abi) { + case LTTNG_SYSCALL_ABI_NATIVE: + bitmap = filter->sc_entry; + break; + case LTTNG_SYSCALL_ABI_COMPAT: + bitmap = filter->sc_compat_entry; + break; + default: + return -EINVAL; } - bitmap_clear(filter->sc, syscall_nr, 1); - } - if (compat_syscall_nr >= 0) { - if (!test_bit(compat_syscall_nr, filter->sc_compat)) { - ret = -EEXIST; - goto error; + break; + case LTTNG_SYSCALL_EXIT: + switch (event->u.syscall.abi) { + case LTTNG_SYSCALL_ABI_NATIVE: + bitmap = filter->sc_exit; + break; + case LTTNG_SYSCALL_ABI_COMPAT: + bitmap = filter->sc_compat_exit; + break; + default: + return -EINVAL; } - bitmap_clear(filter->sc_compat, compat_syscall_nr, 1); + break; + default: + return -EINVAL; } -apply_filter: - if (!chan->sc_filter) - rcu_assign_pointer(chan->sc_filter, filter); - chan->syscall_all = 0; - return 0; + if (!test_bit(syscall_nr, bitmap)) + return -EEXIST; + bitmap_clear(bitmap, syscall_nr, 1); -error: - if (!chan->sc_filter) - kfree(filter); - return ret; + return 0; } static @@ -1236,6 +1282,9 @@ const struct file_operations lttng_syscall_list_fops = { .release = seq_release, }; +/* + * A syscall is enabled if it is traced for either entry or exit. + */ long lttng_channel_syscall_mask(struct lttng_channel *channel, struct lttng_kernel_syscall_mask __user *usyscall_mask) { @@ -1262,8 +1311,9 @@ long lttng_channel_syscall_mask(struct lttng_channel *channel, char state; if (channel->sc_table) { - if (filter) - state = test_bit(bit, filter->sc); + if (!READ_ONCE(channel->syscall_all) && filter) + state = test_bit(bit, filter->sc_entry) + || test_bit(bit, filter->sc_exit); else state = 1; } else { @@ -1275,9 +1325,11 @@ long lttng_channel_syscall_mask(struct lttng_channel *channel, char state; if (channel->compat_sc_table) { - if (filter) + if (!READ_ONCE(channel->syscall_all) && filter) state = test_bit(bit - ARRAY_SIZE(sc_table), - filter->sc_compat); + filter->sc_compat_entry) + || test_bit(bit - ARRAY_SIZE(sc_table), + filter->sc_compat_exit); else state = 1; } else {