File: //usr/src/sysdig-0.27.1/ppm_fillers.c
/*
Copyright (c) 2013-2018 Draios Inc. dba Sysdig.
This file is dual licensed under either the MIT or GPL 2. See MIT.txt
or GPL2.txt for full copies of the license.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#ifndef UDIG
#include <linux/compat.h>
#include <linux/cdev.h>
#include <asm/unistd.h>
#include <net/sock.h>
#include <net/af_unix.h>
#include <net/compat.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/fdtable.h>
#include <linux/file.h>
#include <linux/fs_struct.h>
#include <linux/pid_namespace.h>
#include <linux/ptrace.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/quota.h>
#include <linux/tty.h>
#include <linux/uaccess.h>
#include <linux/audit.h>
#ifdef CONFIG_CGROUPS
#include <linux/cgroup.h>
#endif
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 20)
#include "ppm_syscall.h"
#else
#include <asm/syscall.h>
#endif
#else /* UDIG */
#define _GNU_SOURCE
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <stdarg.h>
#include <limits.h>
#include <unistd.h>
#include <sys/mman.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <time.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <sched.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <poll.h>
#include <sys/sem.h>
#include <sys/file.h>
#include <sys/quota.h>
#include <sys/ptrace.h>
#include "udig_capture.h"
#include "ppm_ringbuffer.h"
#include "ppm_events_public.h"
#include "ppm_events.h"
#include "ppm.h"
#include "udig_inf.h"
#endif /* UDIG */
#include "ppm_ringbuffer.h"
#include "ppm_events_public.h"
#include "ppm_events.h"
#include "ppm.h"
#include "ppm_flag_helpers.h"
#ifndef UDIG
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
#include <linux/bpf.h>
#endif
#include "kernel_hacks.h"
#endif /* UDIG */
#define merge_64(hi, lo) ((((unsigned long long)(hi)) << 32) + ((lo) & 0xffffffffUL))
#ifndef UDIG
static inline struct pid_namespace *pid_ns_for_children(struct task_struct *task)
{
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0))
return task->nsproxy->pid_ns;
#else
return task->nsproxy->pid_ns_for_children;
#endif
}
#endif /* UDIG */
int f_sys_generic(struct event_filler_arguments *args)
{
int res;
long table_index = args->syscall_id - SYSCALL_TABLE_ID0;
const enum ppm_syscall_code *cur_g_syscall_code_routing_table = args->cur_g_syscall_code_routing_table;
#ifdef _HAS_SOCKETCALL
if (unlikely(args->syscall_id == args->socketcall_syscall)) {
/*
* All the socket calls should be implemented
*/
ASSERT(false);
return PPM_FAILURE_BUG;
}
#endif
/*
* name
*/
if (likely(table_index >= 0 &&
table_index < SYSCALL_TABLE_SIZE)) {
enum ppm_syscall_code sc_code = cur_g_syscall_code_routing_table[table_index];
/*
* ID
*/
res = val_to_ring(args, sc_code, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
if (args->event_type == PPME_GENERIC_E) {
/*
* nativeID
*/
res = val_to_ring(args, args->syscall_id, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
}
} else {
ASSERT(false);
res = val_to_ring(args, (unsigned long)"<out of bound>", 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
}
return add_sentinel(args);
}
int f_sys_empty(struct event_filler_arguments *args)
{
return add_sentinel(args);
}
int f_sys_single(struct event_filler_arguments *args)
{
int res;
unsigned long val;
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_single_x(struct event_filler_arguments *args)
{
int res;
int64_t retval;
retval = (int64_t)(long)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
static inline uint32_t get_fd_dev(int64_t fd)
{
#ifdef UDIG
return 0;
#else
struct files_struct *files;
struct fdtable *fdt;
struct file *file;
struct inode *inode;
struct super_block *sb;
uint32_t dev = 0;
if (fd < 0)
return dev;
files = current->files;
if (unlikely(!files))
return dev;
spin_lock(&files->file_lock);
fdt = files_fdtable(files);
if (unlikely(fd > fdt->max_fds))
goto out_unlock;
file = fdt->fd[fd];
if (unlikely(!file))
goto out_unlock;
inode = file_inode(file);
if (unlikely(!inode))
goto out_unlock;
sb = inode->i_sb;
if (unlikely(!sb))
goto out_unlock;
dev = new_encode_dev(sb->s_dev);
out_unlock:
spin_unlock(&files->file_lock);
return dev;
#endif /* UDIG */
}
int f_sys_open_x(struct event_filler_arguments *args)
{
unsigned long val;
unsigned long flags;
unsigned long modes;
int res;
int64_t retval;
/*
* fd
*/
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* name
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* Flags
* Note that we convert them into the ppm portable representation before pushing them to the ring
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &flags);
res = val_to_ring(args, open_flags_to_scap(flags), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* mode
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &modes);
res = val_to_ring(args, open_modes_to_scap(flags, modes), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* dev
*/
res = val_to_ring(args, get_fd_dev(retval), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_read_x(struct event_filler_arguments *args)
{
unsigned long val;
int res;
int64_t retval;
unsigned long bufsize;
/*
* Retrieve the FD. It will be used for dynamic snaplen calculation.
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
args->fd = (int)val;
/*
* res
*/
retval = (int64_t)(long)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* data
*/
if (retval < 0) {
/*
* The operation failed, return an empty buffer
*/
val = 0;
bufsize = 0;
} else {
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
/*
* The return value can be lower than the value provided by the user,
* and we take that into account.
*/
bufsize = retval;
}
/*
* Copy the buffer
*/
args->enforce_snaplen = true;
res = val_to_ring(args, val, bufsize, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_write_x(struct event_filler_arguments *args)
{
unsigned long val;
int res;
int64_t retval;
unsigned long bufsize;
/*
* Retrieve the FD. It will be used for dynamic snaplen calculation.
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
args->fd = (int)val;
/*
* res
*/
retval = (int64_t)(long)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* data
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
bufsize = val;
/*
* Copy the buffer
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
args->enforce_snaplen = true;
res = val_to_ring(args, val, bufsize, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
#ifndef UDIG
/*
* get_mm_counter was not inline and exported between 3.0 and 3.4
* https://github.com/torvalds/linux/commit/69c978232aaa99476f9bd002c2a29a84fa3779b5
* Hence the crap in these two functions
*/
unsigned long ppm_get_mm_counter(struct mm_struct *mm, int member)
{
long val = 0;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
val = get_mm_counter(mm, member);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
val = atomic_long_read(&mm->rss_stat.count[member]);
if (val < 0)
val = 0;
#endif
return val;
}
static unsigned long ppm_get_mm_swap(struct mm_struct *mm)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
return ppm_get_mm_counter(mm, MM_SWAPENTS);
#endif
return 0;
}
static unsigned long ppm_get_mm_rss(struct mm_struct *mm)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
return get_mm_rss(mm);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
return ppm_get_mm_counter(mm, MM_FILEPAGES) +
ppm_get_mm_counter(mm, MM_ANONPAGES);
#else
return get_mm_rss(mm);
#endif
return 0;
}
#ifdef CONFIG_CGROUPS
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
static int ppm_cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)
{
char *start;
struct dentry *dentry = rcu_dereference(cgrp->dentry);
if (!dentry) {
/*
* Inactive subsystems have no dentry for their root
* cgroup
*/
strcpy(buf, "/");
return 0;
}
start = buf + buflen;
*--start = '\0';
for (;;) {
int len = dentry->d_name.len;
start -= len;
if (start < buf)
return -ENAMETOOLONG;
memcpy(start, cgrp->dentry->d_name.name, len);
cgrp = cgrp->parent;
if (!cgrp)
break;
dentry = rcu_dereference(cgrp->dentry);
if (!cgrp->parent)
continue;
if (--start < buf)
return -ENAMETOOLONG;
*start = '/';
}
memmove(buf, start, buf + buflen - start);
return 0;
}
#endif
static int append_cgroup(const char *subsys_name, int subsys_id, char *buf, int *available)
{
int pathlen;
int subsys_len;
char *path;
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0) || LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
int res;
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
struct cgroup_subsys_state *css = task_css(current, subsys_id);
#else
struct cgroup_subsys_state *css = task_subsys_state(current, subsys_id);
#endif
if (!css) {
ASSERT(false);
return 1;
}
if (!css->cgroup) {
ASSERT(false);
return 1;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
// According to https://github.com/torvalds/linux/commit/4c737b41de7f4eef2a593803bad1b918dd718b10
// cgroup_path now returns an int again
res = cgroup_path(css->cgroup, buf, *available);
if (res < 0) {
ASSERT(false);
path = "NA";
} else {
path = buf;
}
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
path = cgroup_path(css->cgroup, buf, *available);
if (!path) {
ASSERT(false);
path = "NA";
}
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
res = cgroup_path(css->cgroup, buf, *available);
if (res < 0) {
ASSERT(false);
path = "NA";
} else {
path = buf;
}
#else
res = ppm_cgroup_path(css->cgroup, buf, *available);
if (res < 0) {
ASSERT(false);
path = "NA";
} else {
path = buf;
}
#endif
pathlen = strlen(path);
subsys_len = strlen(subsys_name);
if (subsys_len + 1 + pathlen + 1 > *available)
return 1;
memmove(buf + subsys_len + 1, path, pathlen);
memcpy(buf, subsys_name, subsys_len);
buf += subsys_len;
*buf++ = '=';
buf += pathlen;
*buf++ = 0;
*available -= (subsys_len + 1 + pathlen + 1);
return 0;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
#define SUBSYS(_x) \
if (append_cgroup(#_x, _x ## _cgrp_id, args->str_storage + STR_STORAGE_SIZE - available, &available)) \
goto cgroups_error;
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)
#define IS_SUBSYS_ENABLED(option) IS_BUILTIN(option)
#define SUBSYS(_x) \
if (append_cgroup(#_x, _x ## _subsys_id, args->str_storage + STR_STORAGE_SIZE - available, &available)) \
goto cgroups_error;
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0)
#define IS_SUBSYS_ENABLED(option) IS_ENABLED(option)
#define SUBSYS(_x) \
if (append_cgroup(#_x, _x ## _subsys_id, args->str_storage + STR_STORAGE_SIZE - available, &available)) \
goto cgroups_error;
#else
#define SUBSYS(_x) \
if (append_cgroup(#_x, _x ## _subsys_id, args->str_storage + STR_STORAGE_SIZE - available, &available)) \
goto cgroups_error;
#endif
#endif
#endif /* UDIG */
/* Takes in a NULL-terminated array of pointers to strings in userspace, and
* concatenates them to a single \0-separated string. Return the length of this
* string, or <0 on error */
int accumulate_argv_or_env(const char __user * __user *argv,
char *str_storage,
int available)
{
int len = 0;
int n_bytes_copied;
if (argv == NULL)
return len;
for (;;) {
const char __user *p;
if (unlikely(ppm_get_user(p, argv)))
return PPM_FAILURE_INVALID_USER_MEMORY;
if (p == NULL)
break;
/* need at least enough space for a \0 */
if (available < 1)
return PPM_FAILURE_BUFFER_FULL;
n_bytes_copied = ppm_strncpy_from_user(&str_storage[len], p,
available);
/* ppm_strncpy_from_user includes the trailing \0 in its return
* count. I want to pretend it was strncpy_from_user() so I
* subtract off the 1 */
n_bytes_copied--;
if (n_bytes_copied < 0)
return PPM_FAILURE_INVALID_USER_MEMORY;
if (n_bytes_copied >= available)
return PPM_FAILURE_BUFFER_FULL;
/* update buffer. I want to keep the trailing \0, so I +1 */
available -= n_bytes_copied+1;
len += n_bytes_copied+1;
argv++;
}
return len;
}
#ifndef UDIG
#ifdef CONFIG_COMPAT
/* compat version that deals correctly with 32bits pointers of argv */
static int compat_accumulate_argv_or_env(compat_uptr_t argv,
char *str_storage,
int available)
{
int len = 0;
int n_bytes_copied;
if (compat_ptr(argv) == NULL)
return len;
for (;;) {
compat_uptr_t compat_p;
const char __user *p;
if (unlikely(ppm_get_user(compat_p, compat_ptr(argv))))
return PPM_FAILURE_INVALID_USER_MEMORY;
p = compat_ptr(compat_p);
if (p == NULL)
break;
/* need at least enough space for a \0 */
if (available < 1)
return PPM_FAILURE_BUFFER_FULL;
n_bytes_copied = ppm_strncpy_from_user(&str_storage[len], p,
available);
/* ppm_strncpy_from_user includes the trailing \0 in its return
* count. I want to pretend it was strncpy_from_user() so I
* subtract off the 1 */
n_bytes_copied--;
if (n_bytes_copied < 0) {
return PPM_FAILURE_INVALID_USER_MEMORY;
}
if (n_bytes_copied >= available)
return PPM_FAILURE_BUFFER_FULL;
/* update buffer. I want to keep the trailing \0, so I +1 */
available -= n_bytes_copied+1;
len += n_bytes_copied+1;
argv += sizeof(compat_uptr_t);
}
return len;
}
#endif
static int ppm_get_tty(void)
{
/* Locking of the signal structures seems too complicated across
* multiple kernel versions to get it right, so simply do protected
* memory accesses, and in the worst case we get some garbage,
* which is not the end of the world. In the vast majority of accesses,
* we'll be just fine.
*/
struct signal_struct *sig;
struct tty_struct *tty;
struct tty_driver *driver;
int major;
int minor_start;
int index;
int tty_nr = 0;
sig = current->signal;
if (!sig)
return 0;
if (unlikely(copy_from_kernel_nofault(&tty, &sig->tty, sizeof(tty))))
return 0;
if (!tty)
return 0;
if (unlikely(copy_from_kernel_nofault(&index, &tty->index, sizeof(index))))
return 0;
if (unlikely(copy_from_kernel_nofault(&driver, &tty->driver, sizeof(driver))))
return 0;
if (!driver)
return 0;
if (unlikely(copy_from_kernel_nofault(&major, &driver->major, sizeof(major))))
return 0;
if (unlikely(copy_from_kernel_nofault(&minor_start, &driver->minor_start, sizeof(minor_start))))
return 0;
tty_nr = new_encode_dev(MKDEV(major, minor_start) + index);
return tty_nr;
}
#endif /* UDIG */
int f_proc_startupdate(struct event_filler_arguments *args)
{
#ifdef UDIG
return udig_proc_startupdate(args);
#else /* UDIG */
unsigned long val;
int res = 0;
unsigned int exe_len = 0; /* the length of the executable string */
int args_len = 0; /*the combined length of the arguments string + executable string */
struct mm_struct *mm = current->mm;
int64_t retval;
int ptid;
char *spwd = "";
long total_vm = 0;
long total_rss = 0;
long swap = 0;
int available = STR_STORAGE_SIZE;
/*
* Make sure the operation was successful
*/
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
if (unlikely(retval < 0 &&
args->event_type != PPME_SYSCALL_EXECVE_19_X)) {
/* The call failed, but this syscall has no exe, args
* anyway, so I report empty ones */
*args->str_storage = 0;
/*
* exe
*/
res = val_to_ring(args, (uint64_t)(long)args->str_storage, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* Args
*/
res = val_to_ring(args, (int64_t)(long)args->str_storage, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
} else {
if (likely(retval >= 0)) {
/*
* The call succeeded. Get exe, args from the current
* process; put one \0-separated exe-args string into
* str_storage
*/
if (unlikely(!mm)) {
args->str_storage[0] = 0;
pr_info("f_proc_startupdate drop, mm=NULL\n");
return PPM_FAILURE_BUG;
}
if (unlikely(!mm->arg_end)) {
args->str_storage[0] = 0;
pr_info("f_proc_startupdate drop, mm->arg_end=NULL\n");
return PPM_FAILURE_BUG;
}
args_len = mm->arg_end - mm->arg_start;
if (args_len) {
if (args_len > PAGE_SIZE)
args_len = PAGE_SIZE;
if (unlikely(ppm_copy_from_user(args->str_storage, (const void __user *)mm->arg_start, args_len)))
args_len = 0;
else
args->str_storage[args_len - 1] = 0;
}
} else {
/*
* The execve call failed. I get exe, args from the
* input args; put one \0-separated exe-args string into
* str_storage
*/
args->str_storage[0] = 0;
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
#ifdef CONFIG_COMPAT
if (unlikely(args->compat))
args_len = compat_accumulate_argv_or_env((compat_uptr_t)val,
args->str_storage, available);
else
#endif
args_len = accumulate_argv_or_env((const char __user * __user *)val,
args->str_storage, available);
if (unlikely(args_len < 0))
args_len = 0;
}
if (args_len == 0)
*args->str_storage = 0;
exe_len = strnlen(args->str_storage, args_len);
if (exe_len < args_len)
++exe_len;
/*
* exe
*/
res = val_to_ring(args, (uint64_t)(long)args->str_storage, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* Args
*/
res = val_to_ring(args, (int64_t)(long)args->str_storage + exe_len, args_len - exe_len, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
}
/*
* tid
*/
res = val_to_ring(args, (int64_t)current->pid, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* pid
*/
res = val_to_ring(args, (int64_t)current->tgid, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* ptid
*/
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
if (current->real_parent)
ptid = current->real_parent->pid;
#else
if (current->parent)
ptid = current->parent->pid;
#endif
else
ptid = 0;
res = val_to_ring(args, (int64_t)ptid, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* cwd, pushed empty to avoid breaking compatibility
* with the older event format
*/
res = val_to_ring(args, (uint64_t)(long)spwd, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* fdlimit
*/
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
res = val_to_ring(args, (int64_t)rlimit(RLIMIT_NOFILE), 0, false, 0);
#else
res = val_to_ring(args, (int64_t)0, 0, false, 0);
#endif
if (res != PPM_SUCCESS)
return res;
/*
* pgft_maj
*/
res = val_to_ring(args, current->maj_flt, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* pgft_min
*/
res = val_to_ring(args, current->min_flt, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
if (mm) {
total_vm = mm->total_vm << (PAGE_SHIFT-10);
total_rss = ppm_get_mm_rss(mm) << (PAGE_SHIFT-10);
swap = ppm_get_mm_swap(mm) << (PAGE_SHIFT-10);
}
/*
* vm_size
*/
res = val_to_ring(args, total_vm, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* vm_rss
*/
res = val_to_ring(args, total_rss, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* vm_swap
*/
res = val_to_ring(args, swap, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* comm
*/
res = val_to_ring(args, (uint64_t)current->comm, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* cgroups
*/
args->str_storage[0] = 0;
#ifdef CONFIG_CGROUPS
rcu_read_lock();
#include <linux/cgroup_subsys.h>
cgroups_error:
rcu_read_unlock();
#endif
res = val_to_ring(args, (int64_t)(long)args->str_storage, STR_STORAGE_SIZE - available, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
if (args->event_type == PPME_SYSCALL_CLONE_20_X ||
args->event_type == PPME_SYSCALL_FORK_20_X ||
args->event_type == PPME_SYSCALL_VFORK_20_X) {
/*
* clone-only parameters
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
uint64_t euid = from_kuid_munged(current_user_ns(), current_euid());
uint64_t egid = from_kgid_munged(current_user_ns(), current_egid());
#elif LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
uint64_t euid = current_euid();
uint64_t egid = current_egid();
#else
uint64_t euid = current->euid;
uint64_t egid = current->egid;
#endif
int64_t in_pidns = 0;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
struct pid_namespace *pidns = task_active_pid_ns(current);
#endif
/*
* flags
*/
if (args->event_type == PPME_SYSCALL_CLONE_20_X) {
#ifdef CONFIG_S390
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
#else
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
#endif
} else
val = 0;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
if(pidns != &init_pid_ns || pid_ns_for_children(current) != pidns)
in_pidns = PPM_CL_CHILD_IN_PIDNS;
#endif
res = val_to_ring(args, (uint64_t)clone_flags_to_scap(val) | in_pidns, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* uid
*/
res = val_to_ring(args, euid, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* gid
*/
res = val_to_ring(args, egid, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* vtid
*/
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
res = val_to_ring(args, task_pid_vnr(current), 0, false, 0);
#else
/* Not relevant in old kernels */
res = val_to_ring(args, 0, 0, false, 0);
#endif
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* vpid
*/
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
res = val_to_ring(args, task_tgid_vnr(current), 0, false, 0);
#else
/* Not relevant in old kernels */
res = val_to_ring(args, 0, 0, false, 0);
#endif
if (unlikely(res != PPM_SUCCESS))
return res;
} else if (args->event_type == PPME_SYSCALL_EXECVE_19_X) {
/*
* execve-only parameters
*/
long env_len = 0;
int tty_nr = 0;
if (likely(retval >= 0)) {
/*
* Already checked for mm validity
*/
env_len = mm->env_end - mm->env_start;
if (env_len) {
if (env_len > PAGE_SIZE)
env_len = PAGE_SIZE;
if (unlikely(ppm_copy_from_user(args->str_storage, (const void __user *)mm->env_start, env_len)))
env_len = 0;
else
args->str_storage[env_len - 1] = 0;
}
} else {
/*
* The call failed, so get the env from the arguments
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
#ifdef CONFIG_COMPAT
if (unlikely(args->compat))
env_len = compat_accumulate_argv_or_env((compat_uptr_t)val,
args->str_storage, available);
else
#endif
env_len = accumulate_argv_or_env((const char __user * __user *)val,
args->str_storage, available);
if (unlikely(env_len < 0))
env_len = 0;
}
if (env_len == 0)
*args->str_storage = 0;
/*
* environ
*/
res = val_to_ring(args, (int64_t)(long)args->str_storage, env_len, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* tty
*/
tty_nr = ppm_get_tty();
res = val_to_ring(args, tty_nr, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* pgid
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
res = val_to_ring(args, (int64_t)task_pgrp_nr_ns(current, task_active_pid_ns(current)), 0, false, 0);
#else
res = val_to_ring(args, (int64_t)process_group(current), 0, false, 0);
#endif
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* loginuid
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
val = from_kuid(current_user_ns(), audit_get_loginuid(current));
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
val = audit_get_loginuid(current);
#else
val = audit_get_loginuid(current->audit_context);
#endif
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
}
return add_sentinel(args);
#endif /* UDIG */
}
int f_sys_execve_e(struct event_filler_arguments *args)
{
int res;
unsigned long val;
/*
* filename
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (res == PPM_FAILURE_INVALID_USER_MEMORY)
res = val_to_ring(args, (unsigned long)"<NA>", 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_socket_bind_x(struct event_filler_arguments *args)
{
int res;
int64_t retval;
int err = 0;
u16 size = 0;
struct sockaddr __user *usrsockaddr;
unsigned long val;
struct sockaddr_storage address;
char *targetbuf = args->str_storage;
/*
* res
*/
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
/*
* addr
*/
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
#ifndef UDIG
else
val = args->socketcall_args[1];
#endif
usrsockaddr = (struct sockaddr __user *)val;
/*
* Get the address len
*/
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
#ifndef UDIG
else
val = args->socketcall_args[2];
#endif
if (usrsockaddr != NULL && val != 0) {
/*
* Copy the address
*/
err = addr_to_kernel(usrsockaddr, val, (struct sockaddr *)&address);
if (likely(err >= 0)) {
/*
* Convert the fd into socket endpoint information
*/
size = pack_addr((struct sockaddr *)&address,
val,
targetbuf,
STR_STORAGE_SIZE);
}
}
/*
* Copy the endpoint info into the ring
*/
res = val_to_ring(args,
(uint64_t)(unsigned long)targetbuf,
size,
false,
0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_connect_x(struct event_filler_arguments *args)
{
int res;
int64_t retval;
int err = 0;
int fd;
struct sockaddr __user *usrsockaddr;
u16 size = 0;
char *targetbuf = args->str_storage;
struct sockaddr_storage address;
unsigned long val;
/*
* Push the result
*/
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
/*
* Retrieve the fd and push it to the ring.
* Note that, even if we are in the exit callback, the arguments are still
* in the stack, and therefore we can consume them.
*/
if (!args->is_socketcall) {
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
fd = (int)val;
}
#ifndef UDIG
else
fd = (int)args->socketcall_args[0];
#endif
if (fd >= 0) {
/*
* Get the address
*/
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
#ifndef UDIG
else
val = args->socketcall_args[1];
#endif
usrsockaddr = (struct sockaddr __user *)val;
/*
* Get the address len
*/
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
#ifndef UDIG
else
val = args->socketcall_args[2];
#endif
if (usrsockaddr != NULL && val != 0) {
/*
* Copy the address
*/
err = addr_to_kernel(usrsockaddr, val, (struct sockaddr *)&address);
if (likely(err >= 0)) {
/*
* Convert the fd into socket endpoint information
*/
size = fd_to_socktuple(fd,
(struct sockaddr *)&address,
val,
true,
false,
targetbuf,
STR_STORAGE_SIZE);
}
}
}
/*
* Copy the endpoint info into the ring
*/
res = val_to_ring(args,
(uint64_t)(unsigned long)targetbuf,
size,
false,
0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_socketpair_x(struct event_filler_arguments *args)
{
int res;
int64_t retval;
unsigned long val;
int fds[2];
int err;
struct socket *sock;
struct unix_sock *us;
struct sock *speer;
/*
* retval
*/
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* If the call was successful, copy the FDs
*/
#ifndef UDIG
if (likely(retval >= 0)) {
/*
* fds
*/
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 3, 1, &val);
else
val = args->socketcall_args[3];
#ifdef CONFIG_COMPAT
if (!args->compat) {
#endif
if (unlikely(ppm_copy_from_user(fds, (const void __user *)val, sizeof(fds))))
return PPM_FAILURE_INVALID_USER_MEMORY;
#ifdef CONFIG_COMPAT
} else {
if (unlikely(ppm_copy_from_user(fds, (const void __user *)compat_ptr(val), sizeof(fds))))
return PPM_FAILURE_INVALID_USER_MEMORY;
}
#endif
res = val_to_ring(args, fds[0], 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
res = val_to_ring(args, fds[1], 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/* get socket source and peer address */
sock = sockfd_lookup(fds[0], &err);
if (likely(sock != NULL)) {
us = unix_sk(sock->sk);
speer = us->peer;
res = val_to_ring(args, (unsigned long)us, 0, false, 0);
if (unlikely(res != PPM_SUCCESS)) {
sockfd_put(sock);
return res;
}
res = val_to_ring(args, (unsigned long)speer, 0, false, 0);
if (unlikely(res != PPM_SUCCESS)) {
sockfd_put(sock);
return res;
}
sockfd_put(sock);
} else {
return err;
}
} else {
#endif /* UDIG */
res = val_to_ring(args, 0, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
res = val_to_ring(args, 0, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
res = val_to_ring(args, 0, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
res = val_to_ring(args, 0, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
#ifndef UDIG
}
#endif
return add_sentinel(args);
}
static int parse_sockopt(struct event_filler_arguments *args, int level, int optname, const void __user *optval, int optlen)
{
union {
uint32_t val32;
uint64_t val64;
struct timeval tv;
} u;
nanoseconds ns = 0;
if (level == SOL_SOCKET) {
switch (optname) {
#ifdef SO_ERROR
case SO_ERROR:
if (unlikely(ppm_copy_from_user(&u.val32, optval, sizeof(u.val32))))
return PPM_FAILURE_INVALID_USER_MEMORY;
return val_to_ring(args, -(int)u.val32, 0, false, PPM_SOCKOPT_IDX_ERRNO);
#endif
#ifdef SO_RCVTIMEO
case SO_RCVTIMEO:
#endif
#ifdef SO_SNDTIMEO
case SO_SNDTIMEO:
#endif
if (unlikely(ppm_copy_from_user(&u.tv, optval, sizeof(u.tv)))) {
return PPM_FAILURE_INVALID_USER_MEMORY;
}
ns = u.tv.tv_sec * SECOND_IN_NS + u.tv.tv_usec * 1000;
return val_to_ring(args, ns, 0, false, PPM_SOCKOPT_IDX_TIMEVAL);
#ifdef SO_COOKIE
case SO_COOKIE:
if (unlikely(ppm_copy_from_user(&u.val64, optval, sizeof(u.val64))))
return PPM_FAILURE_INVALID_USER_MEMORY;
return val_to_ring(args, u.val64, 0, false, PPM_SOCKOPT_IDX_UINT64);
#endif
#ifdef SO_DEBUG
case SO_DEBUG:
#endif
#ifdef SO_REUSEADDR
case SO_REUSEADDR:
#endif
#ifdef SO_TYPE
case SO_TYPE:
#endif
#ifdef SO_DONTROUTE
case SO_DONTROUTE:
#endif
#ifdef SO_BROADCAST
case SO_BROADCAST:
#endif
#ifdef SO_SNDBUF
case SO_SNDBUF:
#endif
#ifdef SO_RCVBUF
case SO_RCVBUF:
#endif
#ifdef SO_SNDBUFFORCE
case SO_SNDBUFFORCE:
#endif
#ifdef SO_RCVBUFFORCE
case SO_RCVBUFFORCE:
#endif
#ifdef SO_KEEPALIVE
case SO_KEEPALIVE:
#endif
#ifdef SO_OOBINLINE
case SO_OOBINLINE:
#endif
#ifdef SO_NO_CHECK
case SO_NO_CHECK:
#endif
#ifdef SO_PRIORITY
case SO_PRIORITY:
#endif
#ifdef SO_BSDCOMPAT
case SO_BSDCOMPAT:
#endif
#ifdef SO_REUSEPORT
case SO_REUSEPORT:
#endif
#ifdef SO_PASSCRED
case SO_PASSCRED:
#endif
#ifdef SO_RCVLOWAT
case SO_RCVLOWAT:
#endif
#ifdef SO_SNDLOWAT
case SO_SNDLOWAT:
#endif
#ifdef SO_SECURITY_AUTHENTICATION
case SO_SECURITY_AUTHENTICATION:
#endif
#ifdef SO_SECURITY_ENCRYPTION_TRANSPORT
case SO_SECURITY_ENCRYPTION_TRANSPORT:
#endif
#ifdef SO_SECURITY_ENCRYPTION_NETWORK
case SO_SECURITY_ENCRYPTION_NETWORK:
#endif
#ifdef SO_BINDTODEVICE
case SO_BINDTODEVICE:
#endif
#ifdef SO_DETACH_FILTER
case SO_DETACH_FILTER:
#endif
#ifdef SO_TIMESTAMP
case SO_TIMESTAMP:
#endif
#ifdef SO_ACCEPTCONN
case SO_ACCEPTCONN:
#endif
#ifdef SO_PEERSEC
case SO_PEERSEC:
#endif
#ifdef SO_PASSSEC
case SO_PASSSEC:
#endif
#ifdef SO_TIMESTAMPNS
case SO_TIMESTAMPNS:
#endif
#ifdef SO_MARK
case SO_MARK:
#endif
#ifdef SO_TIMESTAMPING
case SO_TIMESTAMPING:
#endif
#ifdef SO_PROTOCOL
case SO_PROTOCOL:
#endif
#ifdef SO_DOMAIN
case SO_DOMAIN:
#endif
#ifdef SO_RXQ_OVFL
case SO_RXQ_OVFL:
#endif
#ifdef SO_WIFI_STATUS
case SO_WIFI_STATUS:
#endif
#ifdef SO_PEEK_OFF
case SO_PEEK_OFF:
#endif
#ifdef SO_NOFCS
case SO_NOFCS:
#endif
#ifdef SO_LOCK_FILTER
case SO_LOCK_FILTER:
#endif
#ifdef SO_SELECT_ERR_QUEUE
case SO_SELECT_ERR_QUEUE:
#endif
#ifdef SO_BUSY_POLL
case SO_BUSY_POLL:
#endif
#ifdef SO_MAX_PACING_RATE
case SO_MAX_PACING_RATE:
#endif
#ifdef SO_BPF_EXTENSIONS
case SO_BPF_EXTENSIONS:
#endif
#ifdef SO_INCOMING_CPU
case SO_INCOMING_CPU:
#endif
if (unlikely(ppm_copy_from_user(&u.val32, optval, sizeof(u.val32))))
return PPM_FAILURE_INVALID_USER_MEMORY;
return val_to_ring(args, u.val32, 0, false, PPM_SOCKOPT_IDX_UINT32);
default:
return val_to_ring(args, (unsigned long)optval, optlen, true, PPM_SOCKOPT_IDX_UNKNOWN);
}
} else {
return val_to_ring(args, (unsigned long)optval, optlen, true, PPM_SOCKOPT_IDX_UNKNOWN);
}
}
int f_sys_setsockopt_x(struct event_filler_arguments *args)
{
int res;
int64_t retval;
unsigned long val[5] = {};
syscall_get_arguments_deprecated(current, args->regs, 0, 5, val);
retval = (int64_t)(long)syscall_get_return_value(current, args->regs);
/* retval */
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/* fd */
res = val_to_ring(args, val[0], 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/* level */
res = val_to_ring(args, sockopt_level_to_scap(val[1]), 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/* optname */
res = val_to_ring(args, sockopt_optname_to_scap(val[1], val[2]), 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/* optval */
res = parse_sockopt(args, val[1], val[2], (const void __user*)val[3], val[4]);
if (unlikely(res != PPM_SUCCESS))
return res;
/* optlen */
res = val_to_ring(args, val[4], 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_getsockopt_x(struct event_filler_arguments *args)
{
int res;
int64_t retval;
uint32_t optlen;
unsigned long val[5] = {};
syscall_get_arguments_deprecated(current, args->regs, 0, 5, val);
retval = (int64_t)(long)syscall_get_return_value(current, args->regs);
/* retval */
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/* fd */
res = val_to_ring(args, val[0], 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/* level */
res = val_to_ring(args, sockopt_level_to_scap(val[1]), 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/* optname */
res = val_to_ring(args, sockopt_optname_to_scap(val[1], val[2]), 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
if (unlikely(ppm_copy_from_user(&optlen, (const void __user*)val[4], sizeof(optlen))))
return PPM_FAILURE_INVALID_USER_MEMORY;
/* optval */
res = parse_sockopt(args, val[1], val[2], (const void __user*)val[3], optlen);
if (unlikely(res != PPM_SUCCESS))
return res;
/* optlen */
res = val_to_ring(args, optlen, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_accept4_e(struct event_filler_arguments *args)
{
int res;
/*
* push the flags into the ring.
* XXX we don't support flags yet and so we just return zero
*/
/* res = val_to_ring(args, args->socketcall_args[3]); */
res = val_to_ring(args, 0, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_accept_x(struct event_filler_arguments *args)
{
int res;
int fd;
char *targetbuf = args->str_storage;
u16 size = 0;
unsigned long queuepct = 0;
unsigned long ack_backlog = 0;
unsigned long max_ack_backlog = 0;
unsigned long srvskfd;
int err = 0;
struct socket *sock;
/*
* Push the fd
*/
fd = syscall_get_return_value(current, args->regs);
res = val_to_ring(args, (int64_t)fd, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* Convert the fd into socket endpoint information
*/
size = fd_to_socktuple(fd,
NULL,
0,
false,
true,
targetbuf,
STR_STORAGE_SIZE);
/*
* Copy the endpoint info into the ring
*/
res = val_to_ring(args,
(uint64_t)(unsigned long)targetbuf,
size,
false,
0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* queuepct
*/
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &srvskfd);
#ifndef UDIG
else
srvskfd = args->socketcall_args[0];
#endif
#ifndef UDIG
sock = sockfd_lookup(srvskfd, &err);
if (sock && sock->sk) {
ack_backlog = sock->sk->sk_ack_backlog;
max_ack_backlog = sock->sk->sk_max_ack_backlog;
}
if (sock)
sockfd_put(sock);
if (max_ack_backlog)
queuepct = (unsigned long)ack_backlog * 100 / max_ack_backlog;
#endif /* UDIG */
res = val_to_ring(args, queuepct, 0, false, 0);
if (res != PPM_SUCCESS)
return res;
res = val_to_ring(args, ack_backlog, 0, false, 0);
if (res != PPM_SUCCESS)
return res;
res = val_to_ring(args, max_ack_backlog, 0, false, 0);
if (res != PPM_SUCCESS)
return res;
return add_sentinel(args);
}
int f_sys_send_e_common(struct event_filler_arguments *args, int *fd)
{
int res;
unsigned long size;
unsigned long val;
/*
* fd
*/
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
#ifndef UDIG
else
val = args->socketcall_args[0];
#endif
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
*fd = val;
/*
* size
*/
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &size);
#ifndef UDIG
else
size = args->socketcall_args[2];
#endif
res = val_to_ring(args, size, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return PPM_SUCCESS;
}
int f_sys_send_e(struct event_filler_arguments *args)
{
int res;
int fd;
res = f_sys_send_e_common(args, &fd);
if (likely(res == PPM_SUCCESS))
return add_sentinel(args);
return res;
}
int f_sys_sendto_e(struct event_filler_arguments *args)
{
unsigned long val;
int res;
u16 size = 0;
char *targetbuf = args->str_storage;
int fd;
struct sockaddr __user *usrsockaddr;
struct sockaddr_storage address;
int err = 0;
*targetbuf = 250;
/*
* Push the common params to the ring
*/
res = f_sys_send_e_common(args, &fd);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* Get the address
*/
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 4, 1, &val);
#ifndef UDIG
else
val = args->socketcall_args[4];
#endif
usrsockaddr = (struct sockaddr __user *)val;
/*
* Get the address len
*/
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 5, 1, &val);
#ifndef UDIG
else
val = args->socketcall_args[5];
#endif
if (usrsockaddr != NULL && val != 0) {
/*
* Copy the address
*/
err = addr_to_kernel(usrsockaddr, val, (struct sockaddr *)&address);
if (likely(err >= 0)) {
/*
* Convert the fd into socket endpoint information
*/
size = fd_to_socktuple(fd,
(struct sockaddr *)&address,
val,
true,
false,
targetbuf,
STR_STORAGE_SIZE);
}
}
/*
* Copy the endpoint info into the ring
*/
res = val_to_ring(args,
(uint64_t)(unsigned long)targetbuf,
size,
false,
0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_send_x(struct event_filler_arguments *args)
{
unsigned long val;
int res;
int64_t retval;
unsigned long bufsize;
/*
* Retrieve the FD. It will be used for dynamic snaplen calculation.
*/
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
#ifndef UDIG
else
val = args->socketcall_args[0];
#endif
args->fd = (int)val;
/*
* res
*/
retval = (int64_t)(long)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* data
*/
if (retval < 0) {
/*
* The operation failed, return an empty buffer
*/
val = 0;
bufsize = 0;
} else {
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
#ifndef UDIG
else
val = args->socketcall_args[1];
#endif
/*
* The return value can be lower than the value provided by the user,
* and we take that into account.
*/
bufsize = retval;
}
args->enforce_snaplen = true;
res = val_to_ring(args, val, bufsize, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_recv_x_common(struct event_filler_arguments *args, int64_t *retval)
{
int res;
unsigned long val;
unsigned long bufsize;
/*
* Retrieve the FD. It will be used for dynamic snaplen calculation.
*/
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
#ifndef UDIG
else
val = args->socketcall_args[1];
#endif
args->fd = (int)val;
/*
* res
*/
*retval = (int64_t)(long)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, *retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* data
*/
if (*retval < 0) {
/*
* The operation failed, return an empty buffer
*/
val = 0;
bufsize = 0;
} else {
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
#ifndef UDIG
else
val = args->socketcall_args[1];
#endif
/*
* The return value can be lower than the value provided by the user,
* and we take that into account.
*/
bufsize = *retval;
}
args->enforce_snaplen = true;
res = val_to_ring(args, val, bufsize, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return PPM_SUCCESS;
}
int f_sys_recv_x(struct event_filler_arguments *args)
{
int res;
int64_t retval;
res = f_sys_recv_x_common(args, &retval);
if (likely(res == PPM_SUCCESS))
return add_sentinel(args);
return res;
}
int f_sys_recvfrom_x(struct event_filler_arguments *args)
{
unsigned long val;
int res;
u16 size = 0;
int64_t retval;
char *targetbuf = args->str_storage;
int fd;
struct sockaddr __user *usrsockaddr;
struct sockaddr_storage address;
int addrlen;
int err = 0;
/*
* Push the common params to the ring
*/
res = f_sys_recv_x_common(args, &retval);
if (unlikely(res != PPM_SUCCESS))
return res;
if (retval >= 0) {
/*
* Get the fd
*/
if (!args->is_socketcall) {
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
fd = (int)val;
}
#ifndef UDIG
else
fd = (int)args->socketcall_args[0];
#endif
/*
* Get the address
*/
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 4, 1, &val);
#ifndef UDIG
else
val = args->socketcall_args[4];
#endif
usrsockaddr = (struct sockaddr __user *)val;
/*
* Get the address len
*/
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 5, 1, &val);
#ifndef UDIG
else
val = args->socketcall_args[5];
#endif
if (usrsockaddr != NULL && val != 0) {
#ifdef CONFIG_COMPAT
if (!args->compat) {
#endif
if (unlikely(ppm_copy_from_user(&addrlen, (const void __user *)val, sizeof(addrlen))))
return PPM_FAILURE_INVALID_USER_MEMORY;
#ifdef CONFIG_COMPAT
} else {
if (unlikely(ppm_copy_from_user(&addrlen, (const void __user *)compat_ptr(val), sizeof(addrlen))))
return PPM_FAILURE_INVALID_USER_MEMORY;
}
#endif
/*
* Copy the address
*/
err = addr_to_kernel(usrsockaddr, addrlen, (struct sockaddr *)&address);
if (likely(err >= 0)) {
/*
* Convert the fd into socket endpoint information
*/
size = fd_to_socktuple(fd,
(struct sockaddr *)&address,
addrlen,
true,
true,
targetbuf,
STR_STORAGE_SIZE);
}
}
}
/*
* Copy the endpoint info into the ring
*/
res = val_to_ring(args,
(uint64_t)(unsigned long)targetbuf,
size,
false,
0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_sendmsg_e(struct event_filler_arguments *args)
{
int res;
unsigned long val;
#ifndef UDIG
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
struct user_msghdr mh;
#else
struct msghdr mh;
#endif
#else /* UDIG */
struct msghdr mh;
#endif /* UDIG */
char *targetbuf = args->str_storage;
const struct iovec __user *iov;
#ifdef CONFIG_COMPAT
const struct compat_iovec __user *compat_iov;
struct compat_msghdr compat_mh;
#endif
unsigned long iovcnt;
int fd;
u16 size = 0;
int addrlen;
int err = 0;
struct sockaddr __user *usrsockaddr;
struct sockaddr_storage address;
/*
* fd
*/
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
#ifndef UDIG
else
val = args->socketcall_args[0];
#endif
fd = val;
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* Retrieve the message header
*/
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
#ifndef UDIG
else
val = args->socketcall_args[1];
#endif
#ifdef CONFIG_COMPAT
if (!args->compat) {
#endif
if (unlikely(ppm_copy_from_user(&mh, (const void __user *)val, sizeof(mh))))
return PPM_FAILURE_INVALID_USER_MEMORY;
/*
* size
*/
iov = (const struct iovec __user *)mh.msg_iov;
iovcnt = mh.msg_iovlen;
res = parse_readv_writev_bufs(args, iov, iovcnt, args->consumer->snaplen, PRB_FLAG_PUSH_SIZE | PRB_FLAG_IS_WRITE);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* tuple
*/
usrsockaddr = (struct sockaddr __user *)mh.msg_name;
addrlen = mh.msg_namelen;
#ifdef CONFIG_COMPAT
} else {
if (unlikely(ppm_copy_from_user(&compat_mh, (const void __user *)compat_ptr(val), sizeof(compat_mh))))
return PPM_FAILURE_INVALID_USER_MEMORY;
/*
* size
*/
compat_iov = (const struct compat_iovec __user *)compat_ptr(compat_mh.msg_iov);
iovcnt = compat_mh.msg_iovlen;
res = compat_parse_readv_writev_bufs(args, compat_iov, iovcnt, args->consumer->snaplen, PRB_FLAG_PUSH_SIZE | PRB_FLAG_IS_WRITE);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* tuple
*/
usrsockaddr = (struct sockaddr __user *)compat_ptr(compat_mh.msg_name);
addrlen = compat_mh.msg_namelen;
}
#endif
if (usrsockaddr != NULL && addrlen != 0) {
/*
* Copy the address
*/
err = addr_to_kernel(usrsockaddr, addrlen, (struct sockaddr *)&address);
if (likely(err >= 0)) {
/*
* Convert the fd into socket endpoint information
*/
size = fd_to_socktuple(fd,
(struct sockaddr *)&address,
addrlen,
true,
false,
targetbuf,
STR_STORAGE_SIZE);
}
}
/* Copy the endpoint info into the ring */
res = val_to_ring(args,
(uint64_t)(unsigned long)targetbuf,
size,
false,
0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_sendmsg_x(struct event_filler_arguments *args)
{
int res;
unsigned long val;
int64_t retval;
const struct iovec __user *iov;
#ifdef CONFIG_COMPAT
const struct compat_iovec __user *compat_iov;
struct compat_msghdr compat_mh;
#endif
unsigned long iovcnt;
#ifndef UDIG
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
struct user_msghdr mh;
#else
struct msghdr mh;
#endif
#else /* UDIG */
struct msghdr mh;
#endif /* UDIG */
/*
* res
*/
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* Retrieve the message header
*/
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
#ifndef UDIG
else
val = args->socketcall_args[1];
#endif
/*
* data
*/
#ifdef CONFIG_COMPAT
if (!args->compat) {
#endif
if (unlikely(ppm_copy_from_user(&mh, (const void __user *)val, sizeof(mh))))
return PPM_FAILURE_INVALID_USER_MEMORY;
iov = (const struct iovec __user *)mh.msg_iov;
iovcnt = mh.msg_iovlen;
res = parse_readv_writev_bufs(args, iov, iovcnt, args->consumer->snaplen, PRB_FLAG_PUSH_DATA | PRB_FLAG_IS_WRITE);
if (unlikely(res != PPM_SUCCESS))
return res;
#ifdef CONFIG_COMPAT
} else {
if (unlikely(ppm_copy_from_user(&compat_mh, (const void __user *)compat_ptr(val), sizeof(compat_mh))))
return PPM_FAILURE_INVALID_USER_MEMORY;
compat_iov = (const struct compat_iovec __user *)compat_ptr(compat_mh.msg_iov);
iovcnt = compat_mh.msg_iovlen;
res = compat_parse_readv_writev_bufs(args, compat_iov, iovcnt, args->consumer->snaplen, PRB_FLAG_PUSH_DATA | PRB_FLAG_IS_WRITE);
if (unlikely(res != PPM_SUCCESS))
return res;
}
#endif
return add_sentinel(args);
}
int f_sys_recvmsg_x(struct event_filler_arguments *args)
{
int res;
unsigned long val;
int64_t retval;
const struct iovec __user *iov;
#ifdef CONFIG_COMPAT
const struct compat_iovec __user *compat_iov;
struct compat_msghdr compat_mh;
#endif
unsigned long iovcnt;
#ifndef UDIG
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
struct user_msghdr mh;
#else
struct msghdr mh;
#endif
#else /* UDIG */
struct msghdr mh;
#endif /* UDIG */
char *targetbuf = args->str_storage;
int fd;
struct sockaddr __user *usrsockaddr;
struct sockaddr_storage address;
u16 size = 0;
int addrlen;
int err = 0;
/*
* res
*/
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* Retrieve the message header
*/
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
#ifndef UDIG
else
val = args->socketcall_args[1];
#endif
#ifdef CONFIG_COMPAT
if (!args->compat) {
#endif
if (unlikely(ppm_copy_from_user(&mh, (const void __user *)val, sizeof(mh))))
return PPM_FAILURE_INVALID_USER_MEMORY;
/*
* data and size
*/
iov = (const struct iovec __user *)mh.msg_iov;
iovcnt = mh.msg_iovlen;
res = parse_readv_writev_bufs(args, iov, iovcnt, retval, PRB_FLAG_PUSH_ALL);
#ifdef CONFIG_COMPAT
} else {
if (unlikely(ppm_copy_from_user(&compat_mh, (const void __user *)compat_ptr(val), sizeof(compat_mh))))
return PPM_FAILURE_INVALID_USER_MEMORY;
/*
* data and size
*/
compat_iov = (const struct compat_iovec __user *)compat_ptr(compat_mh.msg_iov);
iovcnt = compat_mh.msg_iovlen;
res = compat_parse_readv_writev_bufs(args, compat_iov, iovcnt, retval, PRB_FLAG_PUSH_ALL);
}
#endif
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* tuple
*/
if (retval >= 0) {
/*
* Get the fd
*/
if (!args->is_socketcall) {
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
fd = (int)val;
}
#ifndef UDIG
else
fd = (int)args->socketcall_args[0];
#endif
/*
* Get the address
*/
usrsockaddr = (struct sockaddr __user *)mh.msg_name;
addrlen = mh.msg_namelen;
if (usrsockaddr != NULL && addrlen != 0) {
/*
* Copy the address
*/
err = addr_to_kernel(usrsockaddr, addrlen, (struct sockaddr *)&address);
if (likely(err >= 0)) {
/*
* Convert the fd into socket endpoint information
*/
size = fd_to_socktuple(fd,
(struct sockaddr *)&address,
addrlen,
true,
true,
targetbuf,
STR_STORAGE_SIZE);
}
}
}
/* Copy the endpoint info into the ring */
res = val_to_ring(args,
(uint64_t)(unsigned long)targetbuf,
size,
false,
0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_creat_x(struct event_filler_arguments *args)
{
unsigned long val;
unsigned long modes;
int res;
int64_t retval;
/*
* fd
*/
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* name
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* mode
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &modes);
res = val_to_ring(args, open_modes_to_scap(O_CREAT, modes), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* dev
*/
res = val_to_ring(args, get_fd_dev(retval), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_pipe_x(struct event_filler_arguments *args)
{
int res;
int64_t retval;
unsigned long val;
int fds[2];
struct file *file;
/*
* retval
*/
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* fds
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
#ifdef CONFIG_COMPAT
if (!args->compat) {
#endif
if (unlikely(ppm_copy_from_user(fds, (const void __user *)val, sizeof(fds))))
return PPM_FAILURE_INVALID_USER_MEMORY;
#ifdef CONFIG_COMPAT
} else {
if (unlikely(ppm_copy_from_user(fds, (const void __user *)compat_ptr(val), sizeof(fds))))
return PPM_FAILURE_INVALID_USER_MEMORY;
}
#endif
res = val_to_ring(args, fds[0], 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
res = val_to_ring(args, fds[1], 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
val = 0;
#ifndef UDIG
file = fget(fds[0]);
if (likely(file != NULL)) {
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
val = file->f_path.dentry->d_inode->i_ino;
#else
val = file->f_dentry->d_inode->i_ino;
#endif
fput(file);
}
#endif
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_eventfd_e(struct event_filler_arguments *args)
{
int res;
unsigned long val;
/*
* initval
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* flags
* XXX not implemented yet
*/
/* syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val); */
val = 0;
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_shutdown_e(struct event_filler_arguments *args)
{
int res;
unsigned long val;
/*
* fd
*/
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
#ifndef UDIG
else
val = args->socketcall_args[0];
#endif
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* how
*/
if (!args->is_socketcall)
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
#ifndef UDIG
else
val = args->socketcall_args[1];
#endif
res = val_to_ring(args, (unsigned long)shutdown_how_to_scap(val), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_futex_e(struct event_filler_arguments *args)
{
int res;
unsigned long val;
/*
* addr
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* op
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
res = val_to_ring(args, (unsigned long)futex_op_to_scap(val), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* val
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_lseek_e(struct event_filler_arguments *args)
{
unsigned long val;
int res;
/*
* fd
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* offset
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* whence
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
res = val_to_ring(args, lseek_whence_to_scap(val), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_llseek_e(struct event_filler_arguments *args)
{
unsigned long val;
int res;
unsigned long oh;
unsigned long ol;
uint64_t offset;
/*
* fd
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* offset
* We build it by combining the offset_high and offset_low system call arguments
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &oh);
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &ol);
offset = (((uint64_t)oh) << 32) + ((uint64_t)ol);
res = val_to_ring(args, offset, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* whence
*/
syscall_get_arguments_deprecated(current, args->regs, 4, 1, &val);
res = val_to_ring(args, lseek_whence_to_scap(val), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
static int poll_parse_fds(struct event_filler_arguments *args, bool enter_event)
{
struct pollfd *fds;
char *targetbuf;
unsigned long val;
unsigned long nfds;
unsigned long fds_count;
u32 j;
u32 pos;
u16 flags;
/*
* fds
*
* Get the number of fds
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &nfds);
/*
* Check if we have enough space to store both the fd list
* from user space and the temporary buffer to serialize to the ring
*/
if (unlikely(sizeof(struct pollfd) * nfds + 2 + 10 * nfds > STR_STORAGE_SIZE))
return PPM_FAILURE_BUFFER_FULL;
/* Get the fds pointer */
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
fds = (struct pollfd *)args->str_storage;
#ifdef CONFIG_COMPAT
if (!args->compat) {
#endif
if (unlikely(ppm_copy_from_user(fds, (const void __user *)val, nfds * sizeof(struct pollfd))))
return PPM_FAILURE_INVALID_USER_MEMORY;
#ifdef CONFIG_COMPAT
} else {
if (unlikely(ppm_copy_from_user(fds, (const void __user *)compat_ptr(val), nfds * sizeof(struct pollfd))))
return PPM_FAILURE_INVALID_USER_MEMORY;
}
#endif
pos = 2;
targetbuf = args->str_storage + nfds * sizeof(struct pollfd) + pos;
fds_count = 0;
/* Copy each fd into the temporary buffer */
for (j = 0; j < nfds; j++) {
if (enter_event) {
flags = poll_events_to_scap(fds[j].events);
} else {
/*
* If it's an exit event, we copy only the fds that
* returned something
*/
if (!fds[j].revents)
continue;
flags = poll_events_to_scap(fds[j].revents);
}
*(int64_t *)(targetbuf + pos) = fds[j].fd;
*(int16_t *)(targetbuf + pos + 8) = flags;
pos += 10;
++fds_count;
}
*(u16 *)(targetbuf) = (u16)fds_count;
return val_to_ring(args, (uint64_t)(unsigned long)targetbuf, pos, false, 0);
}
int f_sys_poll_e(struct event_filler_arguments *args)
{
unsigned long val;
int res;
res = poll_parse_fds(args, true);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* timeout
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
static int timespec_parse(struct event_filler_arguments *args, unsigned long val)
{
uint64_t longtime;
char *targetbuf = args->str_storage;
struct timespec *tts = (struct timespec *)targetbuf;
#ifdef CONFIG_COMPAT
struct compat_timespec *compat_tts = (struct compat_timespec *)targetbuf;
#endif
int cfulen;
/*
* interval
* We copy the timespec structure and then convert it to a 64bit relative time
*/
#ifdef CONFIG_COMPAT
if (!args->compat) {
#endif
cfulen = (int)ppm_copy_from_user(targetbuf, (void __user *)val, sizeof(*tts));
if (unlikely(cfulen != 0))
return PPM_FAILURE_INVALID_USER_MEMORY;
longtime = ((uint64_t)tts->tv_sec) * 1000000000 + tts->tv_nsec;
#ifdef CONFIG_COMPAT
} else {
cfulen = (int)ppm_copy_from_user(targetbuf, (void __user *)compat_ptr(val), sizeof(struct compat_timespec));
if (unlikely(cfulen != 0))
return PPM_FAILURE_INVALID_USER_MEMORY;
longtime = ((uint64_t)compat_tts->tv_sec) * 1000000000 + compat_tts->tv_nsec;
}
#endif
return val_to_ring(args, longtime, 0, false, 0);
}
int f_sys_ppoll_e(struct event_filler_arguments *args)
{
unsigned long val;
int res;
res = poll_parse_fds(args, true);
if (res != PPM_SUCCESS)
return res;
/*
* timeout
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
/* NULL timeout specified as 0xFFFFFF.... */
if (val == (unsigned long)NULL)
res = val_to_ring(args, (uint64_t)(-1), 0, false, 0);
else
res = timespec_parse(args, val);
if (res != PPM_SUCCESS)
return res;
/*
* sigmask
*/
syscall_get_arguments_deprecated(current, args->regs, 3, 1, &val);
if (val != (unsigned long)NULL)
if (0 != ppm_copy_from_user(&val, (void __user *)val, sizeof(val)))
return PPM_FAILURE_INVALID_USER_MEMORY;
res = val_to_ring(args, val, 0, false, 0);
if (res != PPM_SUCCESS)
return res;
return add_sentinel(args);
}
/* This is the same for poll() and ppoll() */
int f_sys_poll_x(struct event_filler_arguments *args)
{
int64_t retval;
int res;
/*
* res
*/
retval = (int64_t)(long)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
res = poll_parse_fds(args, false);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_mount_e(struct event_filler_arguments *args)
{
unsigned long val;
int res;
/*
* Fix mount flags in arg 3.
* See http://lxr.free-electrons.com/source/fs/namespace.c?v=4.2#L2650
*/
syscall_get_arguments_deprecated(current, args->regs, 3, 1, &val);
if ((val & PPM_MS_MGC_MSK) == PPM_MS_MGC_VAL)
val &= ~PPM_MS_MGC_MSK;
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_openat_x(struct event_filler_arguments *args)
{
unsigned long val;
unsigned long flags;
unsigned long modes;
int res;
int64_t retval;
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* dirfd
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
if ((int)val == AT_FDCWD)
val = PPM_AT_FDCWD;
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* name
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* Flags
* Note that we convert them into the ppm portable representation before pushing them to the ring
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &flags);
res = val_to_ring(args, open_flags_to_scap(flags), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* mode
*/
syscall_get_arguments_deprecated(current, args->regs, 3, 1, &modes);
res = val_to_ring(args, open_modes_to_scap(flags, modes), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* dev
*/
res = val_to_ring(args, get_fd_dev(retval), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_unlinkat_x(struct event_filler_arguments *args)
{
unsigned long val;
int res;
int64_t retval;
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* dirfd
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
if ((int)val == AT_FDCWD)
val = PPM_AT_FDCWD;
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* name
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* flags
* Note that we convert them into the ppm portable representation before pushing them to the ring
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
res = val_to_ring(args, unlinkat_flags_to_scap(val), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_linkat_x(struct event_filler_arguments *args)
{
unsigned long val;
unsigned long flags;
int res;
int64_t retval;
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* olddir
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
if ((int)val == AT_FDCWD)
val = PPM_AT_FDCWD;
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* oldpath
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* newdir
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
if ((int)val == AT_FDCWD)
val = PPM_AT_FDCWD;
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* newpath
*/
syscall_get_arguments_deprecated(current, args->regs, 3, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* Flags
* Note that we convert them into the ppm portable representation before pushing them to the ring
*/
syscall_get_arguments_deprecated(current, args->regs, 4, 1, &flags);
res = val_to_ring(args, linkat_flags_to_scap(flags), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
#ifndef _64BIT_ARGS_SINGLE_REGISTER
int f_sys_pread64_e(struct event_filler_arguments *args)
{
unsigned long val;
unsigned long size;
int res;
unsigned long pos0;
unsigned long pos1;
uint64_t pos64;
/*
* fd
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* size
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &size);
res = val_to_ring(args, size, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* pos
*/
#if defined CONFIG_X86
syscall_get_arguments_deprecated(current, args->regs, 3, 1, &pos0);
syscall_get_arguments_deprecated(current, args->regs, 4, 1, &pos1);
#elif defined CONFIG_ARM && CONFIG_AEABI
syscall_get_arguments_deprecated(current, args->regs, 4, 1, &pos0);
syscall_get_arguments_deprecated(current, args->regs, 5, 1, &pos1);
#else
#error This architecture/abi not yet supported
#endif
pos64 = merge_64(pos1, pos0);
res = val_to_ring(args, pos64, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
#endif /* _64BIT_ARGS_SINGLE_REGISTER */
#ifndef _64BIT_ARGS_SINGLE_REGISTER
int f_sys_pwrite64_e(struct event_filler_arguments *args)
{
unsigned long val;
unsigned long size;
int res;
#ifndef _64BIT_ARGS_SINGLE_REGISTER
unsigned long pos0;
unsigned long pos1;
uint64_t pos64;
#endif
/*
* fd
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* size
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &size);
res = val_to_ring(args, size, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* pos
* NOTE: this is a 64bit value, which means that on 32bit systems it uses two
* separate registers that we need to merge.
*/
#ifdef _64BIT_ARGS_SINGLE_REGISTER
syscall_get_arguments_deprecated(current, args->regs, 3, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
#else
#if defined CONFIG_X86
syscall_get_arguments_deprecated(current, args->regs, 3, 1, &pos0);
syscall_get_arguments_deprecated(current, args->regs, 4, 1, &pos1);
#elif defined CONFIG_ARM && CONFIG_AEABI
syscall_get_arguments_deprecated(current, args->regs, 4, 1, &pos0);
syscall_get_arguments_deprecated(current, args->regs, 5, 1, &pos1);
#else
#error This architecture/abi not yet supported
#endif
pos64 = merge_64(pos1, pos0);
res = val_to_ring(args, pos64, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
#endif
return add_sentinel(args);
}
#endif
int f_sys_readv_preadv_x(struct event_filler_arguments *args)
{
unsigned long val;
int64_t retval;
int res;
#ifdef CONFIG_COMPAT
const struct compat_iovec __user *compat_iov;
#endif
const struct iovec __user *iov;
unsigned long iovcnt;
/*
* res
*/
retval = (int64_t)(long)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* data and size
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &iovcnt);
#ifdef CONFIG_COMPAT
if (unlikely(args->compat)) {
compat_iov = (const struct compat_iovec __user *)compat_ptr(val);
res = compat_parse_readv_writev_bufs(args, compat_iov, iovcnt, retval, PRB_FLAG_PUSH_ALL);
} else
#endif
{
iov = (const struct iovec __user *)val;
res = parse_readv_writev_bufs(args, iov, iovcnt, retval, PRB_FLAG_PUSH_ALL);
}
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_writev_e(struct event_filler_arguments *args)
{
unsigned long val;
int res;
#ifdef CONFIG_COMPAT
const struct compat_iovec __user *compat_iov;
#endif
const struct iovec __user *iov;
unsigned long iovcnt;
/*
* fd
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* size
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &iovcnt);
/*
* Copy the buffer
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
#ifdef CONFIG_COMPAT
if (unlikely(args->compat)) {
compat_iov = (const struct compat_iovec __user *)compat_ptr(val);
res = compat_parse_readv_writev_bufs(args, compat_iov, iovcnt,
args->consumer->snaplen,
PRB_FLAG_PUSH_SIZE | PRB_FLAG_IS_WRITE);
} else
#endif
{
iov = (const struct iovec __user *)val;
res = parse_readv_writev_bufs(args, iov, iovcnt, args->consumer->snaplen,
PRB_FLAG_PUSH_SIZE | PRB_FLAG_IS_WRITE);
}
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_writev_pwritev_x(struct event_filler_arguments *args)
{
unsigned long val;
int res;
int64_t retval;
#ifdef CONFIG_COMPAT
const struct compat_iovec __user *compat_iov;
#endif
const struct iovec __user *iov;
unsigned long iovcnt;
/*
* res
*/
retval = (int64_t)(long)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* data and size
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &iovcnt);
/*
* Copy the buffer
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
#ifdef CONFIG_COMPAT
if (unlikely(args->compat)) {
compat_iov = (const struct compat_iovec __user *)compat_ptr(val);
res = compat_parse_readv_writev_bufs(args, compat_iov, iovcnt, args->consumer->snaplen, PRB_FLAG_PUSH_DATA | PRB_FLAG_IS_WRITE);
} else
#endif
{
iov = (const struct iovec __user *)val;
res = parse_readv_writev_bufs(args, iov, iovcnt, args->consumer->snaplen, PRB_FLAG_PUSH_DATA | PRB_FLAG_IS_WRITE);
}
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
#ifndef _64BIT_ARGS_SINGLE_REGISTER
int f_sys_preadv64_e(struct event_filler_arguments *args)
{
unsigned long val;
int res;
unsigned long pos0;
unsigned long pos1;
uint64_t pos64;
/*
* fd
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* pos
*/
/*
* Note that in preadv and pwritev have NO 64-bit arguments in the
* syscall (despite having one in the userspace API), so no alignment
* requirements apply here. For an overly-detailed discussion about
* this, see https://lwn.net/Articles/311630/
*/
syscall_get_arguments_deprecated(current, args->regs, 3, 1, &pos0);
syscall_get_arguments_deprecated(current, args->regs, 4, 1, &pos1);
pos64 = merge_64(pos1, pos0);
res = val_to_ring(args, pos64, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
#endif /* _64BIT_ARGS_SINGLE_REGISTER */
int f_sys_pwritev_e(struct event_filler_arguments *args)
{
unsigned long val;
int res;
#ifndef _64BIT_ARGS_SINGLE_REGISTER
unsigned long pos0;
unsigned long pos1;
uint64_t pos64;
#endif
#ifdef CONFIG_COMPAT
const struct compat_iovec __user *compat_iov;
#endif
const struct iovec __user *iov;
unsigned long iovcnt;
/*
* fd
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* size
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &iovcnt);
/*
* Copy the buffer
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
#ifdef CONFIG_COMPAT
if (unlikely(args->compat)) {
compat_iov = (const struct compat_iovec __user *)compat_ptr(val);
res = compat_parse_readv_writev_bufs(args, compat_iov, iovcnt,
args->consumer->snaplen,
PRB_FLAG_PUSH_SIZE | PRB_FLAG_IS_WRITE);
} else
#endif
{
iov = (const struct iovec __user *)val;
res = parse_readv_writev_bufs(args, iov, iovcnt, args->consumer->snaplen,
PRB_FLAG_PUSH_SIZE | PRB_FLAG_IS_WRITE);
}
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* pos
* NOTE: this is a 64bit value, which means that on 32bit systems it uses two
* separate registers that we need to merge.
*/
#ifdef _64BIT_ARGS_SINGLE_REGISTER
syscall_get_arguments_deprecated(current, args->regs, 3, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
#else
/*
* Note that in preadv and pwritev have NO 64-bit arguments in the
* syscall (despite having one in the userspace API), so no alignment
* requirements apply here. For an overly-detailed discussion about
* this, see https://lwn.net/Articles/311630/
*/
syscall_get_arguments_deprecated(current, args->regs, 3, 1, &pos0);
syscall_get_arguments_deprecated(current, args->regs, 4, 1, &pos1);
pos64 = merge_64(pos1, pos0);
res = val_to_ring(args, pos64, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
#endif
return add_sentinel(args);
}
int f_sys_nanosleep_e(struct event_filler_arguments *args)
{
unsigned long val;
int res;
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = timespec_parse(args, val);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_getrlimit_setrlimit_e(struct event_filler_arguments *args)
{
u8 ppm_resource;
unsigned long val;
int res;
/*
* resource
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
ppm_resource = rlimit_resource_to_scap(val);
res = val_to_ring(args, (uint64_t)ppm_resource, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_getrlimit_setrlrimit_x(struct event_filler_arguments *args)
{
unsigned long val;
int res;
int64_t retval;
struct rlimit rl;
#ifdef CONFIG_COMPAT
struct compat_rlimit compat_rl;
#endif
int64_t cur;
int64_t max;
/*
* res
*/
retval = (int64_t)(long)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* Copy the user structure and extract cur and max
*/
if (retval >= 0 || args->event_type == PPME_SYSCALL_SETRLIMIT_X) {
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
#ifdef CONFIG_COMPAT
if (!args->compat) {
#endif
if (unlikely(ppm_copy_from_user(&rl, (const void __user *)val, sizeof(struct rlimit))))
return PPM_FAILURE_INVALID_USER_MEMORY;
cur = rl.rlim_cur;
max = rl.rlim_max;
#ifdef CONFIG_COMPAT
} else {
if (unlikely(ppm_copy_from_user(&compat_rl, (const void __user *)compat_ptr(val), sizeof(struct compat_rlimit))))
return PPM_FAILURE_INVALID_USER_MEMORY;
cur = compat_rl.rlim_cur;
max = compat_rl.rlim_max;
}
#endif
} else {
cur = -1;
max = -1;
}
/*
* cur
*/
res = val_to_ring(args, cur, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* max
*/
res = val_to_ring(args, max, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_prlimit_e(struct event_filler_arguments *args)
{
u8 ppm_resource;
unsigned long val;
int res;
/*
* pid
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* resource
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
ppm_resource = rlimit_resource_to_scap(val);
res = val_to_ring(args, (uint64_t)ppm_resource, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_prlimit_x(struct event_filler_arguments *args)
{
unsigned long val;
int res;
int64_t retval;
struct rlimit rl;
#ifdef CONFIG_COMPAT
struct compat_rlimit compat_rl;
#endif
int64_t newcur;
int64_t newmax;
int64_t oldcur;
int64_t oldmax;
/*
* res
*/
retval = (int64_t)(long)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* Copy the user structure and extract cur and max
*/
if (retval >= 0) {
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
#ifdef CONFIG_COMPAT
if (!args->compat) {
#endif
if (unlikely(ppm_copy_from_user(&rl, (const void __user *)val, sizeof(struct rlimit)))) {
newcur = -1;
newmax = -1;
} else {
newcur = rl.rlim_cur;
newmax = rl.rlim_max;
}
#ifdef CONFIG_COMPAT
} else {
if (unlikely(ppm_copy_from_user(&compat_rl, (const void __user *)val, sizeof(struct compat_rlimit)))) {
newcur = -1;
newmax = -1;
} else {
newcur = compat_rl.rlim_cur;
newmax = compat_rl.rlim_max;
}
}
#endif
} else {
newcur = -1;
newmax = -1;
}
syscall_get_arguments_deprecated(current, args->regs, 3, 1, &val);
#ifdef CONFIG_COMPAT
if (!args->compat) {
#endif
if (unlikely(ppm_copy_from_user(&rl, (const void __user *)val, sizeof(struct rlimit)))) {
oldcur = -1;
oldmax = -1;
} else {
oldcur = rl.rlim_cur;
oldmax = rl.rlim_max;
}
#ifdef CONFIG_COMPAT
} else {
if (unlikely(ppm_copy_from_user(&compat_rl, (const void __user *)val, sizeof(struct compat_rlimit)))) {
oldcur = -1;
oldmax = -1;
} else {
oldcur = compat_rl.rlim_cur;
oldmax = compat_rl.rlim_max;
}
}
#endif
/*
* newcur
*/
res = val_to_ring(args, newcur, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* newmax
*/
res = val_to_ring(args, newmax, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* oldcur
*/
res = val_to_ring(args, oldcur, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* oldmax
*/
res = val_to_ring(args, oldmax, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
#ifdef CAPTURE_CONTEXT_SWITCHES
int f_sched_switch_e(struct event_filler_arguments *args)
{
int res;
long total_vm = 0;
long total_rss = 0;
long swap = 0;
struct mm_struct *mm = NULL;
if (args->sched_prev == NULL || args->sched_next == NULL) {
ASSERT(false);
return -1;
}
/*
* next
*/
res = val_to_ring(args, args->sched_next->pid, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* pgft_maj
*/
res = val_to_ring(args, args->sched_prev->maj_flt, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* pgft_min
*/
res = val_to_ring(args, args->sched_prev->min_flt, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
mm = args->sched_prev->mm;
if (mm) {
total_vm = mm->total_vm << (PAGE_SHIFT-10);
total_rss = ppm_get_mm_rss(mm) << (PAGE_SHIFT-10);
swap = ppm_get_mm_swap(mm) << (PAGE_SHIFT-10);
}
/*
* vm_size
*/
res = val_to_ring(args, total_vm, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* vm_rss
*/
res = val_to_ring(args, total_rss, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* vm_swap
*/
res = val_to_ring(args, swap, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
#if 0
/*
* steal
*/
steal = cputime64_to_clock_t(kcpustat_this_cpu->cpustat[CPUTIME_STEAL]);
res = val_to_ring(args, steal, 0, false);
if (unlikely(res != PPM_SUCCESS))
return res;
#endif
return add_sentinel(args);
}
#endif /* CAPTURE_CONTEXT_SWITCHES */
int f_sched_drop(struct event_filler_arguments *args)
{
int res;
/*
* ratio
*/
res = val_to_ring(args, args->consumer->sampling_ratio, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_fcntl_e(struct event_filler_arguments *args)
{
unsigned long val;
int res;
/*
* fd
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* cmd
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
res = val_to_ring(args, fcntl_cmd_to_scap(val), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
static inline int parse_ptrace_addr(struct event_filler_arguments *args, u16 request)
{
unsigned long val;
uint64_t dst;
u8 idx;
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
switch (request) {
default:
idx = PPM_PTRACE_IDX_UINT64;
dst = (uint64_t)val;
}
return val_to_ring(args, dst, 0, false, idx);
}
static inline int parse_ptrace_data(struct event_filler_arguments *args, u16 request)
{
unsigned long val;
unsigned long len;
uint64_t dst;
u8 idx;
syscall_get_arguments_deprecated(current, args->regs, 3, 1, &val);
switch (request) {
case PPM_PTRACE_PEEKTEXT:
case PPM_PTRACE_PEEKDATA:
case PPM_PTRACE_PEEKUSR:
idx = PPM_PTRACE_IDX_UINT64;
#ifdef CONFIG_COMPAT
if (!args->compat) {
#endif
len = ppm_copy_from_user(&dst, (const void __user *)val, sizeof(long));
#ifdef CONFIG_COMPAT
} else {
len = ppm_copy_from_user(&dst, (const void __user *)compat_ptr(val), sizeof(compat_long_t));
}
#endif
if (unlikely(len != 0))
return PPM_FAILURE_INVALID_USER_MEMORY;
break;
case PPM_PTRACE_CONT:
case PPM_PTRACE_SINGLESTEP:
case PPM_PTRACE_DETACH:
case PPM_PTRACE_SYSCALL:
idx = PPM_PTRACE_IDX_SIGTYPE;
dst = (uint64_t)val;
break;
case PPM_PTRACE_ATTACH:
case PPM_PTRACE_TRACEME:
case PPM_PTRACE_POKETEXT:
case PPM_PTRACE_POKEDATA:
case PPM_PTRACE_POKEUSR:
default:
idx = PPM_PTRACE_IDX_UINT64;
dst = (uint64_t)val;
break;
}
return val_to_ring(args, dst, 0, false, idx);
}
int f_sys_ptrace_e(struct event_filler_arguments *args)
{
unsigned long val;
int res;
/*
* request
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, ptrace_requests_to_scap(val), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* pid
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_ptrace_x(struct event_filler_arguments *args)
{
unsigned long val;
int64_t retval;
u16 request;
int res;
/*
* res
*/
retval = (int64_t)(long)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
if (retval < 0) {
res = val_to_ring(args, 0, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
res = val_to_ring(args, 0, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
/*
* request
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
request = ptrace_requests_to_scap(val);
res = parse_ptrace_addr(args, request);
if (unlikely(res != PPM_SUCCESS))
return res;
res = parse_ptrace_data(args, request);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_brk_munmap_mmap_x(struct event_filler_arguments *args)
{
int64_t retval;
int res = 0;
#ifndef UDIG
struct mm_struct *mm = current->mm;
#endif
long total_vm = 0;
long total_rss = 0;
long swap = 0;
retval = (int64_t)(long)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
#ifndef UDIG
if (mm) {
total_vm = mm->total_vm << (PAGE_SHIFT-10);
total_rss = ppm_get_mm_rss(mm) << (PAGE_SHIFT-10);
swap = ppm_get_mm_swap(mm) << (PAGE_SHIFT-10);
}
#endif
/*
* vm_size
*/
res = val_to_ring(args, total_vm, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* vm_rss
*/
res = val_to_ring(args, total_rss, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* vm_swap
*/
res = val_to_ring(args, swap, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_mmap_e(struct event_filler_arguments *args)
{
unsigned long val;
int res;
/*
* addr
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* length
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* prot
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
res = val_to_ring(args, prot_flags_to_scap(val), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* flags
*/
syscall_get_arguments_deprecated(current, args->regs, 3, 1, &val);
res = val_to_ring(args, mmap_flags_to_scap(val), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* fd
*/
syscall_get_arguments_deprecated(current, args->regs, 4, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* offset/pgoffset
*/
syscall_get_arguments_deprecated(current, args->regs, 5, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_renameat_x(struct event_filler_arguments *args)
{
unsigned long val;
int res;
int64_t retval;
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* olddirfd
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
if ((int)val == AT_FDCWD)
val = PPM_AT_FDCWD;
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* oldpath
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* newdirfd
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
if ((int)val == AT_FDCWD)
val = PPM_AT_FDCWD;
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* newpath
*/
syscall_get_arguments_deprecated(current, args->regs, 3, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_renameat2_x(struct event_filler_arguments *args)
{
unsigned long val;
int res;
int64_t retval;
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* olddirfd
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
if ((int)val == AT_FDCWD)
val = PPM_AT_FDCWD;
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* oldpath
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* newdirfd
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
if ((int)val == AT_FDCWD)
val = PPM_AT_FDCWD;
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* newpath
*/
syscall_get_arguments_deprecated(current, args->regs, 3, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* flags
*/
syscall_get_arguments_deprecated(current, args->regs, 4, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_symlinkat_x(struct event_filler_arguments *args)
{
unsigned long val;
int res;
int64_t retval;
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* oldpath
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* newdirfd
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
if ((int)val == AT_FDCWD)
val = PPM_AT_FDCWD;
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* newpath
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_procexit_e(struct event_filler_arguments *args)
{
int res;
#ifndef UDIG
if (args->sched_prev == NULL) {
ASSERT(false);
return -1;
}
#endif
/*
* status
*/
#ifndef UDIG
res = val_to_ring(args, args->sched_prev->exit_code, 0, false, 0);
#else
res = val_to_ring(args, 0, 0, false, 0);
#endif
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_sendfile_e(struct event_filler_arguments *args)
{
unsigned long val;
int res;
off_t offset;
/*
* out_fd
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* in_fd
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* offset
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
if (val != 0) {
#ifdef CONFIG_COMPAT
if (!args->compat) {
#endif
res = ppm_copy_from_user(&offset, (void *)val, sizeof(off_t));
#ifdef CONFIG_COMPAT
} else {
res = ppm_copy_from_user(&offset, (void *)compat_ptr(val), sizeof(compat_off_t));
}
#endif
if (unlikely(res))
val = 0;
else
val = offset;
}
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* size
*/
syscall_get_arguments_deprecated(current, args->regs, 3, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_sendfile_x(struct event_filler_arguments *args)
{
unsigned long val;
int res;
int64_t retval;
off_t offset;
/*
* res
*/
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* offset
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
if (val != 0) {
#ifdef CONFIG_COMPAT
if (!args->compat) {
#endif
res = ppm_copy_from_user(&offset, (void *)val, sizeof(off_t));
#ifdef CONFIG_COMPAT
} else {
res = ppm_copy_from_user(&offset, (void *)compat_ptr(val), sizeof(compat_off_t));
}
#endif
if (unlikely(res))
val = 0;
else
val = offset;
}
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_quotactl_e(struct event_filler_arguments *args)
{
unsigned long val;
int res;
uint32_t id;
uint8_t quota_fmt;
uint16_t cmd;
/*
* extract cmd
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
cmd = quotactl_cmd_to_scap(val);
res = val_to_ring(args, cmd, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* extract type
*/
res = val_to_ring(args, quotactl_type_to_scap(val), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* extract id
*/
id = 0;
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
if ((cmd == PPM_Q_GETQUOTA) ||
(cmd == PPM_Q_SETQUOTA) ||
(cmd == PPM_Q_XGETQUOTA) ||
(cmd == PPM_Q_XSETQLIM)) {
/*
* in this case id represent an userid or groupid so add it
*/
id = val;
}
res = val_to_ring(args, id, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* extract quota_fmt from id
*/
quota_fmt = PPM_QFMT_NOT_USED;
if (cmd == PPM_Q_QUOTAON)
quota_fmt = quotactl_fmt_to_scap(val);
res = val_to_ring(args, quota_fmt, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_quotactl_x(struct event_filler_arguments *args)
{
unsigned long val, len;
int res;
int64_t retval;
uint16_t cmd;
struct if_dqblk dqblk;
struct if_dqinfo dqinfo;
uint32_t quota_fmt_out;
const char empty_string[] = "";
/*
* extract cmd
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
cmd = quotactl_cmd_to_scap(val);
/*
* return value
*/
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* Add special
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* get addr
*/
syscall_get_arguments_deprecated(current, args->regs, 3, 1, &val);
/*
* get quotafilepath only for QUOTAON
*/
if (cmd == PPM_Q_QUOTAON)
res = val_to_ring(args, val, 0, true, 0);
else
res = val_to_ring(args, (unsigned long)empty_string, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* dqblk fields if present
*/
dqblk.dqb_valid = 0;
if ((cmd == PPM_Q_GETQUOTA) || (cmd == PPM_Q_SETQUOTA)) {
len = ppm_copy_from_user(&dqblk, (void *)val, sizeof(struct if_dqblk));
if (unlikely(len != 0))
return PPM_FAILURE_INVALID_USER_MEMORY;
}
if (dqblk.dqb_valid & QIF_BLIMITS) {
res = val_to_ring(args, dqblk.dqb_bhardlimit, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
res = val_to_ring(args, dqblk.dqb_bsoftlimit, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
} else {
res = val_to_ring(args, 0, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
res = val_to_ring(args, 0, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
}
if (dqblk.dqb_valid & QIF_SPACE) {
res = val_to_ring(args, dqblk.dqb_curspace, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
} else {
res = val_to_ring(args, 0, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
}
if (dqblk.dqb_valid & QIF_ILIMITS) {
res = val_to_ring(args, dqblk.dqb_ihardlimit, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
res = val_to_ring(args, dqblk.dqb_isoftlimit, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
} else {
res = val_to_ring(args, 0, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
res = val_to_ring(args, 0, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
}
if (dqblk.dqb_valid & QIF_BTIME) {
res = val_to_ring(args, dqblk.dqb_btime, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
} else {
res = val_to_ring(args, 0, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
}
if (dqblk.dqb_valid & QIF_ITIME) {
res = val_to_ring(args, dqblk.dqb_itime, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
} else {
res = val_to_ring(args, 0, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
}
/*
* dqinfo fields if present
*/
dqinfo.dqi_valid = 0;
if ((cmd == PPM_Q_GETINFO) || (cmd == PPM_Q_SETINFO)) {
len = ppm_copy_from_user(&dqinfo, (void *)val, sizeof(struct if_dqinfo));
if (unlikely(len != 0))
return PPM_FAILURE_INVALID_USER_MEMORY;
}
if (dqinfo.dqi_valid & IIF_BGRACE) {
res = val_to_ring(args, dqinfo.dqi_bgrace, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
} else {
res = val_to_ring(args, 0, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
}
if (dqinfo.dqi_valid & IIF_IGRACE) {
res = val_to_ring(args, dqinfo.dqi_igrace, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
} else {
res = val_to_ring(args, 0, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
}
if (dqinfo.dqi_valid & IIF_FLAGS) {
res = val_to_ring(args, dqinfo.dqi_flags, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
} else {
res = val_to_ring(args, 0, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
}
quota_fmt_out = PPM_QFMT_NOT_USED;
if (cmd == PPM_Q_GETFMT) {
len = ppm_copy_from_user("a_fmt_out, (void *)val, sizeof(uint32_t));
if (unlikely(len != 0))
return PPM_FAILURE_INVALID_USER_MEMORY;
quota_fmt_out = quotactl_fmt_to_scap(quota_fmt_out);
}
res = val_to_ring(args, quota_fmt_out, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_sysdigevent_e(struct event_filler_arguments *args)
{
int res;
/*
* event_type
*/
res = val_to_ring(args, (unsigned long)args->sched_prev, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* event_data
*/
res = val_to_ring(args, (unsigned long)args->sched_next, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_getresuid_and_gid_x(struct event_filler_arguments *args)
{
int res;
unsigned long val, len;
uint32_t uid;
int16_t retval;
/*
* return value
*/
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* ruid
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
#ifdef CONFIG_COMPAT
if (!args->compat) {
#endif
len = ppm_copy_from_user(&uid, (void *)val, sizeof(uint32_t));
#ifdef CONFIG_COMPAT
} else {
len = ppm_copy_from_user(&uid, (void *)compat_ptr(val), sizeof(uint32_t));
}
#endif
if (unlikely(len != 0))
return PPM_FAILURE_INVALID_USER_MEMORY;
res = val_to_ring(args, uid, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* euid
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
len = ppm_copy_from_user(&uid, (void *)val, sizeof(uint32_t));
if (unlikely(len != 0))
return PPM_FAILURE_INVALID_USER_MEMORY;
res = val_to_ring(args, uid, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* suid
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
len = ppm_copy_from_user(&uid, (void *)val, sizeof(uint32_t));
if (unlikely(len != 0))
return PPM_FAILURE_INVALID_USER_MEMORY;
res = val_to_ring(args, uid, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_flock_e(struct event_filler_arguments *args)
{
unsigned long val;
int res;
u32 flags;
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
flags = flock_flags_to_scap(val);
res = val_to_ring(args, flags, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_setns_e(struct event_filler_arguments *args)
{
unsigned long val;
int res;
u32 flags;
/*
* parse fd
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* get type, parse as clone flags as it's a subset of it
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
flags = clone_flags_to_scap(val);
res = val_to_ring(args, flags, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_unshare_e(struct event_filler_arguments *args)
{
unsigned long val;
int res;
u32 flags;
/*
* get type, parse as clone flags as it's a subset of it
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
flags = clone_flags_to_scap(val);
res = val_to_ring(args, flags, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
#ifdef CAPTURE_SIGNAL_DELIVERIES
int f_sys_signaldeliver_e(struct event_filler_arguments *args)
{
int res;
/*
* source pid
*/
res = val_to_ring(args, args->spid, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* destination pid
*/
res = val_to_ring(args, args->dpid, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* signal number
*/
res = val_to_ring(args, args->signo, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
#endif
#ifdef CAPTURE_PAGE_FAULTS
int f_sys_pagefault_e(struct event_filler_arguments *args)
{
int res;
res = val_to_ring(args, args->fault_data.address, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
res = val_to_ring(args, args->fault_data.regs->ip, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
res = val_to_ring(args, pf_flags_to_scap(args->fault_data.error_code), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
#endif
int f_cpu_hotplug_e(struct event_filler_arguments *args)
{
int res;
/*
* cpu
*/
res = val_to_ring(args, (uint64_t)args->sched_prev, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* action
*/
res = val_to_ring(args, (uint64_t)args->sched_next, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_semop_x(struct event_filler_arguments *args)
{
unsigned long nsops;
int res;
int64_t retval;
struct sembuf *ptr;
/*
* return value
*/
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* nsops
* actually this could be read in the enter function but
* we also need to know the value to access the sembuf structs
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &nsops);
res = val_to_ring(args, nsops, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* sembuf
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, (unsigned long *) &ptr);
if (nsops && ptr) {
/* max length of sembuf array in g_event_info = 2 */
const unsigned max_nsops = 2;
unsigned j;
for (j = 0; j < max_nsops; j++) {
struct sembuf sops = {0, 0, 0};
if (nsops--)
if (unlikely(ppm_copy_from_user(&sops, (void *)&ptr[j], sizeof(struct sembuf))))
return PPM_FAILURE_INVALID_USER_MEMORY;
res = val_to_ring(args, sops.sem_num, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
res = val_to_ring(args, sops.sem_op, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
res = val_to_ring(args, semop_flags_to_scap(sops.sem_flg), 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
}
}
return add_sentinel(args);
}
int f_sys_semget_e(struct event_filler_arguments *args)
{
unsigned long val;
int res;
/*
* key
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* nsems
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* semflg
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
res = val_to_ring(args, semget_flags_to_scap(val), 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_semctl_e(struct event_filler_arguments *args)
{
unsigned long val;
int res;
/*
* semid
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* semnum
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* cmd
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
res = val_to_ring(args, semctl_cmd_to_scap(val), 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* optional argument semun/val
*/
if (val == SETVAL)
syscall_get_arguments_deprecated(current, args->regs, 3, 1, &val);
else
val = 0;
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_access_e(struct event_filler_arguments *args)
{
unsigned long val;
int res;
/*
* mode
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
res = val_to_ring(args, access_flags_to_scap(val), 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_bpf_x(struct event_filler_arguments *args)
{
int64_t retval;
unsigned long cmd;
int res;
/*
* res, if failure or depending on cmd
*/
retval = (int64_t)(long)syscall_get_return_value(current, args->regs);
if (retval < 0) {
res = val_to_ring(args, retval, 0, false, PPM_BPF_IDX_RES);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
/*
* fd, depending on cmd
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &cmd);
#ifdef UDIG
if(0)
#else /* UDIG */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
if(cmd == BPF_MAP_CREATE || cmd == BPF_PROG_LOAD)
#else
if(0)
#endif
#endif /* UDIG */
{
res = val_to_ring(args, retval, 0, false, PPM_BPF_IDX_FD);
}
else
{
res = val_to_ring(args, retval, 0, false, PPM_BPF_IDX_RES);
}
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_mkdirat_x(struct event_filler_arguments *args)
{
unsigned long val;
int res;
int64_t retval;
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* dirfd
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
if ((int)val == AT_FDCWD)
val = PPM_AT_FDCWD;
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* path
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* mode
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_fchmodat_x(struct event_filler_arguments *args)
{
unsigned long val;
int res;
int64_t retval;
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* dirfd
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
if ((int)val == AT_FDCWD)
val = PPM_AT_FDCWD;
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* filename
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* mode
*/
syscall_get_arguments_deprecated(current, args->regs, 2, 1, &val);
res = val_to_ring(args, chmod_mode_to_scap(val), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_chmod_x(struct event_filler_arguments *args)
{
unsigned long val;
int res;
int64_t retval;
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* filename
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, true, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* mode
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
res = val_to_ring(args, chmod_mode_to_scap(val), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}
int f_sys_fchmod_x(struct event_filler_arguments *args)
{
unsigned long val;
int res;
int64_t retval;
retval = (int64_t)syscall_get_return_value(current, args->regs);
res = val_to_ring(args, retval, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* fd
*/
syscall_get_arguments_deprecated(current, args->regs, 0, 1, &val);
res = val_to_ring(args, val, 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
/*
* mode
*/
syscall_get_arguments_deprecated(current, args->regs, 1, 1, &val);
res = val_to_ring(args, chmod_mode_to_scap(val), 0, false, 0);
if (unlikely(res != PPM_SUCCESS))
return res;
return add_sentinel(args);
}