From e12494bd304046d826ea976afefe5d1c88b7e97a Mon Sep 17 00:00:00 2001 From: akindyakov Date: Fri, 14 Sep 2018 09:33:57 +0000 Subject: [PATCH] Initial commit to implement kprobes+ebpf event source - Platform dependent `perf_event_open` and `bpf` syscalls definitions - `isSupportedBySystem` function definition to determine if current system supports required eBPF features Issue: #5218 --- osquery/events/CMakeLists.txt | 4 + osquery/events/linux/ebpf/ebpf.h | 13 ++++ osquery/events/linux/ebpf/system.cpp | 78 +++++++++++++++++++ osquery/events/linux/ebpf/system.h | 62 +++++++++++++++ .../events/linux/ebpf/tests/system_tests.cpp | 29 +++++++ 5 files changed, 186 insertions(+) create mode 100644 osquery/events/linux/ebpf/ebpf.h create mode 100644 osquery/events/linux/ebpf/system.cpp create mode 100644 osquery/events/linux/ebpf/system.h create mode 100644 osquery/events/linux/ebpf/tests/system_tests.cpp diff --git a/osquery/events/CMakeLists.txt b/osquery/events/CMakeLists.txt index 3c5df07a03a..93816e21d0b 100644 --- a/osquery/events/CMakeLists.txt +++ b/osquery/events/CMakeLists.txt @@ -44,6 +44,9 @@ else() "${CMAKE_CURRENT_LIST_DIR}/linux/auditdnetlink.h" "${CMAKE_CURRENT_LIST_DIR}/linux/auditeventpublisher.cpp" "${CMAKE_CURRENT_LIST_DIR}/linux/auditeventpublisher.h" + "${CMAKE_CURRENT_LIST_DIR}/linux/ebpf/ebpf.h" + "${CMAKE_CURRENT_LIST_DIR}/linux/ebpf/system.h" + "${CMAKE_CURRENT_LIST_DIR}/linux/ebpf/system.cpp" "${CMAKE_CURRENT_LIST_DIR}/linux/inotify.cpp" "${CMAKE_CURRENT_LIST_DIR}/linux/inotify.h" "${CMAKE_CURRENT_LIST_DIR}/linux/syslog.cpp" @@ -80,6 +83,7 @@ elseif(LINUX) "${CMAKE_CURRENT_LIST_DIR}/linux/tests/inotify_tests.cpp" "${CMAKE_CURRENT_LIST_DIR}/linux/tests/process_file_events_tests.cpp" "${CMAKE_CURRENT_LIST_DIR}/linux/tests/syslog_tests.cpp" + "${CMAKE_CURRENT_LIST_DIR}/linux/ebpf/tests/system_tests.cpp" ) elseif(WINDOWS) ADD_OSQUERY_TEST_ADDITIONAL( diff --git a/osquery/events/linux/ebpf/ebpf.h b/osquery/events/linux/ebpf/ebpf.h new file mode 100644 index 00000000000..1754e5a890f --- /dev/null +++ b/osquery/events/linux/ebpf/ebpf.h @@ -0,0 +1,13 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the Apache 2.0 license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#pragma once + +#include "osquery/events/linux/ebpf/system.h" diff --git a/osquery/events/linux/ebpf/system.cpp b/osquery/events/linux/ebpf/system.cpp new file mode 100644 index 00000000000..29a0dc60b21 --- /dev/null +++ b/osquery/events/linux/ebpf/system.cpp @@ -0,0 +1,78 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the Apache 2.0 license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#include "osquery/events/linux/ebpf/system.h" + +#include +#include + +#include + +#include + +namespace osquery { +namespace ebpf { + +namespace impl { + +using boost::io::quoted; + +KernelReleaseVersion getKernelReleaseVersion() { + auto version = KernelReleaseVersion{}; + struct utsname utsbuf; + if (uname(&utsbuf) == -1) { + LOG(WARNING) << "syscall uname() failed: " << quoted(strerror(errno)); + debug_only::fail("syscall uname() failed"); + return version; + } + auto release = std::string(utsbuf.release); + auto const major_number_pos = release.find('.'); + if (major_number_pos == std::string::npos) { + LOG(WARNING) << "Wrong major version field: " << quoted(utsbuf.release); + debug_only::fail("Wrong major version field"); + return version; + } + version.major = tryTo(release.substr(0, major_number_pos)).takeOr(0); + + auto const minor_number_pos = release.find('.', major_number_pos + 1); + if (minor_number_pos == std::string::npos) { + LOG(WARNING) << "Wrong minor version field: " << quoted(utsbuf.release); + debug_only::fail("Wrong release minor version field"); + return version; + } + version.minor = + tryTo(release.substr(major_number_pos + 1, + minor_number_pos - major_number_pos)) + .takeOr(0); + + auto const patch_number_pos = release.find('-', minor_number_pos + 1); + if (patch_number_pos == std::string::npos) { + LOG(WARNING) << "Wrong patches field: " << quoted(utsbuf.release); + debug_only::fail("Wrong release patches field"); + return version; + } + version.patches = + tryTo(release.substr(minor_number_pos + 1, + patch_number_pos - minor_number_pos)) + .takeOr(0); + return version; +} + +} // namespace impl + +bool isSupportedBySystem() { + constexpr int kMinimalLinuxVersionCode = KERNEL_VERSION(4, 9, 0); + auto const version = impl::getKernelReleaseVersion(); + return kMinimalLinuxVersionCode <= + KERNEL_VERSION(version.major, version.minor, version.patches); +} + +} // namespace ebpf +} // namespace osquery diff --git a/osquery/events/linux/ebpf/system.h b/osquery/events/linux/ebpf/system.h new file mode 100644 index 00000000000..9f72da12882 --- /dev/null +++ b/osquery/events/linux/ebpf/system.h @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the Apache 2.0 license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#pragma once + +#include +#include + +#ifndef __NR_perf_event_open +#if defined(__PPC__) +#define __NR_perf_event_open 319 +#elif defined(__i386__) +#define __NR_perf_event_open 336 +#elif defined(__x86_64__) +#define __NR_perf_event_open 298 +#else +#error __NR_perf_event_open is undefined, probably this arch is not supported. +#endif +#endif + +#ifndef __NR_bpf +#if defined(__i386__) +#define __NR_bpf 357 +#elif defined(__x86_64__) +#define __NR_bpf 321 +#elif defined(__aarch64__) +#define __NR_bpf 280 +#elif defined(__sparc__) +#define __NR_bpf 349 +#elif defined(__s390__) +#define __NR_bpf 351 +#else +#error __NR_bpf is undefined, probably this arch is not supported. +#endif +#endif + +namespace osquery { +namespace ebpf { + +bool isSupportedBySystem(); + +namespace impl { + +struct KernelReleaseVersion { + int major = 0; + int minor = 0; + int patches = 0; +}; + +KernelReleaseVersion getKernelReleaseVersion(); + +} + +} // namespace ebpf +} // namespace osquery diff --git a/osquery/events/linux/ebpf/tests/system_tests.cpp b/osquery/events/linux/ebpf/tests/system_tests.cpp new file mode 100644 index 00000000000..6ab5bbd1e16 --- /dev/null +++ b/osquery/events/linux/ebpf/tests/system_tests.cpp @@ -0,0 +1,29 @@ + +/** + * Copyright (c) 2014-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under both the Apache 2.0 license (found in the + * LICENSE file in the root directory of this source tree) and the GPLv2 (found + * in the COPYING file in the root directory of this source tree). + * You may select, at your option, one of the above-listed licenses. + */ + +#include "osquery/events/linux/ebpf/system.h" + +#include + +#include + +namespace osquery { +namespace { + +class EbpfSystemTests : public testing::Test {}; + +TEST_F(EbpfSystemTests, getKernelReleaseVersion) { + auto const version = ebpf::impl::getKernelReleaseVersion(); + EXPECT_GE(version.major, 2); +} + +} // namespace +} // namespace osquery