Fix: syscall_list_show NULL pointer deref
[lttng-modules.git] / lttng-syscalls.c
index 5023c2f9dcc2ff8c588ad159303255dabab92ac6..4eae6747f692c1149adbb5d52fef45a5b8e19ea0 100644 (file)
 #include <linux/bitmap.h>
 #include <linux/in.h>
 #include <linux/in6.h>
+#include <linux/seq_file.h>
 #include <asm/ptrace.h>
 #include <asm/syscall.h>
 
+#include "lib/bitfield.h"
 #include "wrapper/tracepoint.h"
 #include "lttng-events.h"
 
@@ -949,6 +951,12 @@ int get_compat_syscall_nr(const char *syscall_name)
        return syscall_nr;
 }
 
+static
+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)
 {
@@ -1033,6 +1041,12 @@ int lttng_syscall_filter_disable(struct lttng_channel *chan,
                filter = chan->sc_filter;
        }
 
+       if (!name) {
+               /* 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) {
@@ -1053,6 +1067,7 @@ int lttng_syscall_filter_disable(struct lttng_channel *chan,
                }
                bitmap_clear(chan->sc_filter->sc_compat, compat_syscall_nr, 1);
        }
+apply_filter:
        if (!chan->sc_filter)
                rcu_assign_pointer(chan->sc_filter, filter);
        chan->syscall_all = 0;
@@ -1063,3 +1078,145 @@ error:
                kfree(filter);
        return ret;
 }
+
+static
+const struct trace_syscall_entry *syscall_list_get_entry(loff_t *pos)
+{
+       const struct trace_syscall_entry *entry;
+       int iter = 0;
+
+       for (entry = sc_table;
+                       entry < sc_table + ARRAY_SIZE(sc_table);
+                        entry++) {
+               if (iter++ >= *pos)
+                       return entry;
+       }
+       for (entry = compat_sc_table;
+                       entry < compat_sc_table + ARRAY_SIZE(compat_sc_table);
+                        entry++) {
+               if (iter++ >= *pos)
+                       return entry;
+       }
+       /* End of list */
+       return NULL;
+}
+
+static
+void *syscall_list_start(struct seq_file *m, loff_t *pos)
+{
+       return (void *) syscall_list_get_entry(pos);
+}
+
+static
+void *syscall_list_next(struct seq_file *m, void *p, loff_t *ppos)
+{
+       (*ppos)++;
+       return (void *) syscall_list_get_entry(ppos);
+}
+
+static
+void syscall_list_stop(struct seq_file *m, void *p)
+{
+}
+
+static
+int get_sc_table(const struct trace_syscall_entry *entry,
+               const struct trace_syscall_entry **table,
+               unsigned int *bitness)
+{
+       if (entry >= sc_table && entry < sc_table + ARRAY_SIZE(sc_table)) {
+               if (bitness)
+                       *bitness = BITS_PER_LONG;
+               if (table)
+                       *table = sc_table;
+               return 0;
+       }
+       if (!(entry >= compat_sc_table
+                       && entry < compat_sc_table + ARRAY_SIZE(compat_sc_table))) {
+               return -EINVAL;
+       }
+       if (bitness)
+               *bitness = 32;
+       if (table)
+               *table = compat_sc_table;
+       return 0;
+}
+
+static
+int syscall_list_show(struct seq_file *m, void *p)
+{
+       const struct trace_syscall_entry *table, *entry = p;
+       unsigned int bitness;
+       int ret;
+
+       ret = get_sc_table(entry, &table, &bitness);
+       if (ret)
+               return ret;
+       if (!entry->desc)
+               return 0;
+       seq_printf(m,   "syscall { index = %lu; name = %s; bitness = %u; };\n",
+               table == sc_table ? entry - table :
+                       (entry - table) + ARRAY_SIZE(sc_table),
+               entry->desc->name,
+               bitness);
+       return 0;
+}
+
+static
+const struct seq_operations lttng_syscall_list_seq_ops = {
+       .start = syscall_list_start,
+       .next = syscall_list_next,
+       .stop = syscall_list_stop,
+       .show = syscall_list_show,
+};
+
+static
+int lttng_syscall_list_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &lttng_syscall_list_seq_ops);
+}
+
+const struct file_operations lttng_syscall_list_fops = {
+       .owner = THIS_MODULE,
+       .open = lttng_syscall_list_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = seq_release,
+};
+
+long lttng_channel_syscall_mask(struct lttng_channel *channel,
+               struct lttng_kernel_syscall_mask __user *usyscall_mask)
+{
+       uint32_t len, sc_tables_len, bitmask_len;
+       int ret = 0, bit;
+       char *tmp_mask;
+       struct lttng_syscall_filter *filter;
+
+       ret = get_user(len, &usyscall_mask->len);
+       if (ret)
+               return ret;
+       sc_tables_len = get_sc_tables_len();
+       bitmask_len = ALIGN(sc_tables_len, 8) >> 3;
+       if (len < sc_tables_len) {
+               return put_user(sc_tables_len, &usyscall_mask->len);
+       }
+       /* Array is large enough, we can copy array to user-space. */
+       tmp_mask = kzalloc(bitmask_len, GFP_KERNEL);
+       if (!tmp_mask)
+               return -ENOMEM;
+       filter = channel->sc_filter;
+
+       for (bit = 0; bit < ARRAY_SIZE(sc_table); bit++) {
+               bt_bitfield_write_be(tmp_mask, char, bit, 1,
+                       test_bit(bit, filter->sc));
+       }
+       for (; bit < sc_tables_len; bit++) {
+               bt_bitfield_write_be(tmp_mask, char, bit, 1,
+                       test_bit(bit - ARRAY_SIZE(sc_table),
+                               filter->sc_compat));
+       }
+       if (copy_to_user(usyscall_mask->mask, tmp_mask, bitmask_len))
+               ret = -EFAULT;
+       kfree(tmp_mask);
+       return ret;
+}
This page took 0.024675 seconds and 4 git commands to generate.