FrauBSD / viosnoop

Snoop on Linux VFS I/O using bpftrace

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

kprobe:vfs_fstat and kretprobe:vfs_fstat unavailable on Ubuntu 20.04

kimono-koans opened this issue · comments

With bpftrace installed:

`$ sudo bpftrace -l | grep fstat

tracepoint:syscalls:sys_enter_fstatfs
tracepoint:syscalls:sys_exit_fstatfs
tracepoint:syscalls:sys_enter_newfstatat
tracepoint:syscalls:sys_exit_newfstatat
tracepoint:syscalls:sys_enter_newfstat
tracepoint:syscalls:sys_exit_newfstat
kprobe:__ia32_compat_sys_x86_fstatat
kprobe:__x32_compat_sys_x86_fstatat
kprobe:__ia32_compat_sys_x86_fstat64
kprobe:__x32_compat_sys_x86_fstat64
kprobe:__x64_sys_fstat
kprobe:__ia32_sys_fstat
kprobe:__x64_sys_newfstatat
kprobe:__ia32_sys_newfstatat
kprobe:__x64_sys_newfstat
kprobe:__ia32_sys_newfstat
kprobe:__ia32_compat_sys_newfstatat
kprobe:__x32_compat_sys_newfstatat
kprobe:__ia32_compat_sys_newfstat
kprobe:__x32_compat_sys_newfstat
kprobe:__x64_sys_fstatfs
kprobe:__ia32_sys_fstatfs
kprobe:__x64_sys_fstatfs64
kprobe:__ia32_sys_fstatfs64
kprobe:__ia32_compat_sys_fstatfs
kprobe:__x32_compat_sys_fstatfs
kprobe:kcompat_sys_fstatfs64
kprobe:__ia32_compat_sys_fstatfs64
kprobe:__x32_compat_sys_fstatfs64
kprobe:ifstat`

Was able to get the following to work:

`tracepoint:syscalls:sys_enter_fstatfs
/@trace[pid, args->fd] != ""/
{
$fd = args->fd;

            // Pass args to kretprobe
            @fstat_exit[tid] = 1;
            @fstat_fd[tid] = \$fd;
    }

    tracepoint:syscalls:sys_exit_fstatfs
    /@fstat_exit[pid]/
    {
            \$fd = @fstat_fd[tid];
            \$fstype = @trace[pid, \$fd];

            // Args from kprobe
            delete(@fstat_exit[tid]);
            delete(@fstat_fd[tid]);

            ${TIME_FMT:+time($RAW_TIME_FMT);
            }printf("|fstat|%d.%d|%s|%d|%s|",
                    uid, gid, comm, pid,
                    \$fstype);
            printf("%d\n", \$fd);
    }`

Thanks for the hard work!

Thank you for work necessary to make it work on Ubuntu 20.0.

Do you know the best way to detect Ubuntu 20+ so that I can write the necessary shell code to generate different bpftrace code on that OS? Preferably some way that doesn't involve forking a command -- for example, on RedHat and CentOS I can read /etc/redhat-release ... do you suggest reading /etc/os-release on Ubuntu or is there a better (more easily machine-parseable) source?

You could check /etc/os-release on Ubuntu but it might be better to check for the kprobes like below:

NAME="Ubuntu" VERSION="20.04.1 LTS (Focal Fossa)" ID=ubuntu ID_LIKE=debian PRETTY_NAME="Ubuntu 20.04.1 LTS" VERSION_ID="20.04" HOME_URL="https://www.ubuntu.com/" SUPPORT_URL="https://help.ubuntu.com/" BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/" PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy" VERSION_CODENAME=focal UBUNTU_CODENAME=focal

`#!/bin/sh
if [ $( bpftrace -l | grep -c -e "kprobe:vfs_fstat" -e "kprobe:vfs_fstat and kretprobe:vfs_fstat" ) -eq 0 ]; then
tracepoint:syscalls:sys_enter_fstatfs
/@trace[pid, args->fd] != ""/
{
$fd = args->fd;

            // Pass args to kretprobe
            @fstat_exit[tid] = 1;
            @fstat_fd[tid] = \$fd;
    }

    tracepoint:syscalls:sys_exit_fstatfs
    /@fstat_exit[pid]/
    {
            \$fd = @fstat_fd[tid];
            \$fstype = @trace[pid, \$fd];

            // Args from kprobe
            delete(@fstat_exit[tid]);
            delete(@fstat_fd[tid]);

            ${TIME_FMT:+time($RAW_TIME_FMT);
            }printf("|fstat|%d.%d|%s|%d|%s|",
                    uid, gid, comm, pid,
                    \$fstype);
            printf("%d\n", \$fd);
    }

else
kprobe:vfs_fstat
/@trace[pid, arg0] != ""/
{
$fd = arg0;
// Pass args to kretprobe
@fstat_exit[tid] = 1;
@fstat_fd[tid] = $fd;
}
kretprobe:vfs_fstat
/@fstat_exit[tid]/
{
$fd = @fstat_fd[tid];
$ret = retval;
$fstype = @trace[pid, $fd];
// Args from kprobe
delete(@fstat_exit[tid]);
delete(@fstat_fd[tid]);
${TIME_FMT:+time($RAW_TIME_FMT);
}printf("|fstat|%d.%d|%s|%d|%s|",
uid, gid, comm, pid,
$fstype);
printf("%d|%d\n", $fd, $ret);
}
fi`

if [ $( bpftrace -l | grep -c -e "kprobe:vfs_fstat" -e kretprobe:vfs_fstat" ) -eq 0 ]; then ... fi

After investigation, it turns out that the probe we want for kernels that are lacking vfs_fstat is instead vfs_statx_fd as seen by this change in the Linux kernel torvalds/linux@da9aa5d

I have seen 3.x kernels with vfs_fstat and 4.x kernels with vfs_statx_fd and it seems to be that the appropriate thing to do is to test for the particular probe and use the proper one -- irrespective of other probe decisions (implying that we should probably do a single "bpftrace -l" and run that through an evaluated awk expression to set probe decisions in the calling namespace, avoiding a multiplying factor)

@electricboogie should be fixed now. Will wait for verification before closing.

Seems to work!