Skip to content

Commit

Permalink
Fix kmod build on Linux 5.8 (#1672)
Browse files Browse the repository at this point in the history
* Fix kmod build on Linux 5.8
* Moved kernel hacks into their own file.
* probe-builder: Use CONFIG_GCC_VERSION if available

Kernel 5.8 changed the format of the compiler version string
so rather than chasing it, use CONFIG_GCC_VERSION if we have it
(5.8.0 does support it, so we use it there, for older versions
we fall back to parsing LINUX_COMPILER)

Co-authored-by: Grzegorz Nosek <[email protected]>
  • Loading branch information
nathan-b and gnosek authored Aug 4, 2020
1 parent 3193643 commit 2691cbc
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 81 deletions.
1 change: 1 addition & 0 deletions driver/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ set(DRIVER_SOURCES
event_table.c
fillers_table.c
flags_table.c
kernel_hacks.h
main.c
ppm.h
ppm_events.c
Expand Down
83 changes: 83 additions & 0 deletions driver/kernel_hacks.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2020 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.
*/

/**
* @file kernel_hacks.h
*
* This file contains kernel-version-dependent preprocessor instructions to
* help the driver compile on as many kernel versions as possible.
*/

#include <linux/version.h>

/* probe_kernel_read() only added in kernel 2.6.26, name changed in 5.8.0 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
static inline long copy_from_kernel_nofault(void *dst, const void *src, size_t size)
{
long ret;
mm_segment_t old_fs = get_fs();

set_fs(KERNEL_DS);
pagefault_disable();
ret = __copy_from_user_inatomic(dst, (__force const void __user *)src, size);
pagefault_enable();
set_fs(old_fs);

return ret ? -EFAULT : 0;
}
#elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0)
#define copy_from_kernel_nofault probe_kernel_read
#endif


/*
* Linux 5.6 kernels no longer include the old 32-bit timeval
* structures. But the syscalls (might) still use them.
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
#include <linux/time64.h>
struct compat_timespec {
int32_t tv_sec;
int32_t tv_nsec;
};

struct timespec {
int32_t tv_sec;
int32_t tv_nsec;
};

struct timeval {
int32_t tv_sec;
int32_t tv_usec;
};
#else
#define timeval64 timeval
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
static inline struct inode *file_inode(struct file *f)
{
return f->f_path.dentry->d_inode;
}
#endif

/*
* Linux 5.1 kernels modify the syscall_get_arguments function to always
* return all arguments rather than allowing the caller to select which
* arguments are desired. This wrapper replicates the original
* functionality.
*/
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 1, 0))
#define syscall_get_arguments_deprecated syscall_get_arguments
#else
#define syscall_get_arguments_deprecated(_task, _reg, _start, _len, _args) \
do { \
unsigned long _sga_args[6] = {}; \
syscall_get_arguments(_task, _reg, _sga_args); \
memcpy(_args, &_sga_args[_start], _len * sizeof(unsigned long)); \
} while(0)
#endif
77 changes: 6 additions & 71 deletions driver/ppm_fillers.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,59 +84,11 @@ or GPL2.txt for full copies of the license.
#include <linux/bpf.h>
#endif

/*
* Linux 5.6 kernels no longer include the old 32-bit timeval
* structures. But the syscalls (might) still use them.
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
#include <linux/time64.h>
struct compat_timespec {
int32_t tv_sec;
int32_t tv_nsec;
};

struct timespec {
int32_t tv_sec;
int32_t tv_nsec;
};

struct timeval {
int32_t tv_sec;
int32_t tv_usec;
};
#else
#define timeval64 timeval
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
static inline struct inode *file_inode(struct file *f)
{
return f->f_path.dentry->d_inode;
}
#endif
#include "kernel_hacks.h"
#endif /* UDIG */

#define merge_64(hi, lo) ((((unsigned long long)(hi)) << 32) + ((lo) & 0xffffffffUL))

/*
* Linux 5.1 kernels modify the syscall_get_arguments function to always
* return all arguments rather than allowing the caller to select which
* arguments are desired. This wrapper replicates the original
* functionality.
*/
#ifndef UDIG
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 1, 0))
#define syscall_get_arguments_deprecated syscall_get_arguments
#else
#define syscall_get_arguments_deprecated(_task, _reg, _start, _len, _args) \
do { \
unsigned long _sga_args[6] = {}; \
syscall_get_arguments(_task, _reg, _sga_args); \
memcpy(_args, &_sga_args[_start], _len * sizeof(unsigned long)); \
} while(0)
#endif
#endif /* UDIG */

#ifndef UDIG
static inline struct pid_namespace *pid_ns_for_children(struct task_struct *task)
{
Expand Down Expand Up @@ -701,23 +653,6 @@ static int compat_accumulate_argv_or_env(compat_uptr_t argv,

#endif

// probe_kernel_read() only added in kernel 2.6.26
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
long probe_kernel_read(void *dst, const void *src, size_t size)
{
long ret;
mm_segment_t old_fs = get_fs();

set_fs(KERNEL_DS);
pagefault_disable();
ret = __copy_from_user_inatomic(dst, (__force const void __user *)src, size);
pagefault_enable();
set_fs(old_fs);

return ret ? -EFAULT : 0;
}
#endif

static int ppm_get_tty(void)
{
/* Locking of the signal structures seems too complicated across
Expand All @@ -738,25 +673,25 @@ static int ppm_get_tty(void)
if (!sig)
return 0;

if (unlikely(probe_kernel_read(&tty, &sig->tty, sizeof(tty))))
if (unlikely(copy_from_kernel_nofault(&tty, &sig->tty, sizeof(tty))))
return 0;

if (!tty)
return 0;

if (unlikely(probe_kernel_read(&index, &tty->index, sizeof(index))))
if (unlikely(copy_from_kernel_nofault(&index, &tty->index, sizeof(index))))
return 0;

if (unlikely(probe_kernel_read(&driver, &tty->driver, sizeof(driver))))
if (unlikely(copy_from_kernel_nofault(&driver, &tty->driver, sizeof(driver))))
return 0;

if (!driver)
return 0;

if (unlikely(probe_kernel_read(&major, &driver->major, sizeof(major))))
if (unlikely(copy_from_kernel_nofault(&major, &driver->major, sizeof(major))))
return 0;

if (unlikely(probe_kernel_read(&minor_start, &driver->minor_start, sizeof(minor_start))))
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);
Expand Down
30 changes: 20 additions & 10 deletions probe-builder/build-probe-binaries
Original file line number Diff line number Diff line change
Expand Up @@ -296,18 +296,28 @@ function build_probe {
elif [ -n "${BUILDER_DISTRO:-}" ]
then
# Try to find the gcc version used to build this particular kernel
# There is CONFIG_GCC_VERSION=90201 in the kernel config but it's
# too new for us to depend on
if [ -e $KERNELDIR/include/generated/compile.h ]
# Check CONFIG_GCC_VERSION=90201 in the kernel config first
# as 5.8.0 seems to have a different format for the LINUX_COMPILER string
if [ -e $KERNELDIR/include/generated/autoconf.h ]
then
BUILDER_GCC_VERSION=$(grep -Po '(?<=^#define LINUX_COMPILER "gcc version )[0-9.]+' $KERNELDIR/include/generated/compile.h)
elif [ -e $KERNELDIR/include/linux/compile.h ]
then
# RHEL6
BUILDER_GCC_VERSION=$(grep -Po '(?<=^#define LINUX_COMPILER "gcc version )[0-9.]+' $KERNELDIR/include/linux/compile.h)
BUILDER_GCC_VERSION=$(grep -Po '(?<=^#define CONFIG_GCC_VERSION ).*' $KERNELDIR/include/generated/autoconf.h | sed '-res@(.*)(..)(..)$@\1\.\2\.\3@' '-es@\.0@\.@g')
else
# ancient Ubuntu gets and ancient compiler
BUILDER_GCC_VERSION=4.8.0
BUILDER_GCC_VERSION=
fi

if [ -z "$BUILDER_GCC_VERSION" ]
then
if [ -e $KERNELDIR/include/generated/compile.h ]
then
BUILDER_GCC_VERSION=$(grep -Po '(?<=^#define LINUX_COMPILER "gcc version )[0-9.]+' $KERNELDIR/include/generated/compile.h)
elif [ -e $KERNELDIR/include/linux/compile.h ]
then
# RHEL6
BUILDER_GCC_VERSION=$(grep -Po '(?<=^#define LINUX_COMPILER "gcc version )[0-9.]+' $KERNELDIR/include/linux/compile.h)
else
# ancient Ubuntu gets and ancient compiler
BUILDER_GCC_VERSION=4.8.0
fi
fi

# We don't really care about the compiler patch levels, only the major/minor version
Expand Down

0 comments on commit 2691cbc

Please sign in to comment.