diff --git a/osquery/utils/system/linux/ebpf/BUCK b/osquery/utils/system/linux/ebpf/BUCK index 80c05d99717..28f32df28a0 100644 --- a/osquery/utils/system/linux/ebpf/BUCK +++ b/osquery/utils/system/linux/ebpf/BUCK @@ -20,6 +20,7 @@ osquery_cxx_library( [ "ebpf.h", "map.h", + "program.h", ], ), ], @@ -29,6 +30,7 @@ osquery_cxx_library( [ "ebpf.cpp", "map.cpp", + "program.cpp", ], ), ], diff --git a/osquery/utils/system/linux/ebpf/program.cpp b/osquery/utils/system/linux/ebpf/program.cpp new file mode 100644 index 00000000000..46dbdafe2a5 --- /dev/null +++ b/osquery/utils/system/linux/ebpf/program.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 +#include + +#include + +#include + +namespace osquery { +namespace ebpf { + +Program::Program(Program&& other) : fd_(other.fd_) { + other.fd_ = -1; +} + +Program& Program::operator=(Program&& other) { + std::swap(fd_, other.fd_); + return *this; +} + +Program::~Program() { + if (fd_ > 0) { + close(fd_); + fd_ = -1; + } +} + +Expected Program::load( + std::vector const prog, + enum bpf_prog_type const program_type, + bool const debug) { + static char const* kLicense = "GPL"; + constexpr auto kLogBufSize = std::uint32_t{1 << 16}; + + auto bpf_log_buf = std::array{}; + union bpf_attr attr = { + .prog_type = program_type, + .insns = reinterpret_cast<__aligned_u64>(prog.data()), + .insn_cnt = static_cast(prog.size()), + .license = reinterpret_cast<__aligned_u64>(kLicense), + .log_buf = 0u, + .log_size = 0u, + .log_level = 0u, + .kern_version = LINUX_VERSION_CODE, + }; + if (debug) { + bpf_log_buf.fill('\0'); + attr.log_buf = reinterpret_cast(bpf_log_buf.data()); + attr.log_size = reinterpret_cast(kLogBufSize); + attr.log_level = 1; + } + auto instance = Program{}; + auto fd_exp = syscall(BPF_PROG_LOAD, &attr); + if (fd_exp.isError()) { + return createError(Program::Error::Unknown, + "eBPF program load failed ", + fd_exp.takeError()) + << " bpf log: " << boost::io::quoted(bpf_log_buf.data()); + } + instance.fd_ = fd_exp.take(); + return Expected(std::move(instance)); +} + +int Program::fd() const { + return fd_; +} + +} // namespace ebpf +} // namespace osquery diff --git a/osquery/utils/system/linux/ebpf/program.h b/osquery/utils/system/linux/ebpf/program.h new file mode 100644 index 00000000000..f9360149c26 --- /dev/null +++ b/osquery/utils/system/linux/ebpf/program.h @@ -0,0 +1,50 @@ +/** + * 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 + +namespace osquery { +namespace ebpf { + +class Program final { + public: + Program(Program&& other); + Program& operator=(Program&& other); + + Program(Program const&) = delete; + Program& operator=(Program const&) = delete; + + ~Program(); + + enum class Error { + Unknown = 1, + NotSupportedBySystem = 2, + }; + + static Expected load( + std::vector prog, + enum bpf_prog_type const program_type = BPF_PROG_TYPE_KPROBE, + bool const debug = false); + + int fd() const; + + private: + Program() = default; + + private: + int fd_ = -1; +}; + +} // namespace ebpf +} // namespace osquery diff --git a/osquery/utils/system/linux/ebpf/tests/BUCK b/osquery/utils/system/linux/ebpf/tests/BUCK index 55ae54680e3..faab562984c 100644 --- a/osquery/utils/system/linux/ebpf/tests/BUCK +++ b/osquery/utils/system/linux/ebpf/tests/BUCK @@ -21,6 +21,7 @@ osquery_cxx_test( [ "ebpf.cpp", "map.cpp", + "program.cpp", ], ), ], diff --git a/osquery/utils/system/linux/ebpf/tests/program.cpp b/osquery/utils/system/linux/ebpf/tests/program.cpp new file mode 100644 index 00000000000..560b501f36b --- /dev/null +++ b/osquery/utils/system/linux/ebpf/tests/program.cpp @@ -0,0 +1,45 @@ +/** + * 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 +#include + +#include + +#include + +namespace osquery { +namespace { + +class EbpfProgramTests : public testing::Test {}; + +bool const kDebug = +#ifndef NDEBUG + true; +#else + false; +#endif + +TEST_F(EbpfProgramTests, empty_debug) { + auto const ebpf_exp = ebpf::isSupportedBySystem(); + EXPECT_TRUE(ebpf_exp.isValue()) + << ebpf_exp.getError().getFullMessageRecursive(); + if (!ebpf_exp.get()) { + LOG(WARNING) << "This system does not support eBPF of required vesion, " + "test will be skipped"; + return; + } + auto program_exp = ebpf::Program::load({}, BPF_PROG_TYPE_KPROBE, kDebug); + ASSERT_TRUE(program_exp.isError()); + ASSERT_EQ(program_exp.getErrorCode(), ebpf::Program::Error::Unknown); +} + +} // namespace +} // namespace osquery