Skip to content

Commit

Permalink
eBPF program loader class (osquery#5355)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: osquery#5355

C++ wrapper to load and keep track of eBPF program in order to close if afterwards.

Blueprint: [osquery#5218](osquery#5218)

Reviewed By: guliashvili

Differential Revision: D13609628

fbshipit-source-id: 536d908da8f9a55961aee4e04864d2c1da704f3d
  • Loading branch information
akindyakov authored and facebook-github-bot committed Jan 16, 2019
1 parent 966c971 commit 8127730
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 0 deletions.
2 changes: 2 additions & 0 deletions osquery/utils/system/linux/ebpf/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ osquery_cxx_library(
[
"ebpf.h",
"map.h",
"program.h",
],
),
],
Expand All @@ -29,6 +30,7 @@ osquery_cxx_library(
[
"ebpf.cpp",
"map.cpp",
"program.cpp",
],
),
],
Expand Down
78 changes: 78 additions & 0 deletions osquery/utils/system/linux/ebpf/program.cpp
Original file line number Diff line number Diff line change
@@ -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/utils/system/linux/ebpf/program.h>
#include <osquery/utils/system/linux/ebpf/ebpf.h>

#include <boost/io/detail/quoted_manip.hpp>

#include <linux/version.h>

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, Program::Error> Program::load(
std::vector<struct bpf_insn> 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<char, kLogBufSize>{};
union bpf_attr attr = {
.prog_type = program_type,
.insns = reinterpret_cast<__aligned_u64>(prog.data()),
.insn_cnt = static_cast<std::uint32_t>(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<std::uint64_t>(bpf_log_buf.data());
attr.log_size = reinterpret_cast<std::uint32_t>(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<Program, Program::Error>(std::move(instance));
}

int Program::fd() const {
return fd_;
}

} // namespace ebpf
} // namespace osquery
50 changes: 50 additions & 0 deletions osquery/utils/system/linux/ebpf/program.h
Original file line number Diff line number Diff line change
@@ -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 <osquery/utils/expected/expected.h>

#include <linux/bpf.h>

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<Program, Program::Error> load(
std::vector<struct bpf_insn> 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
1 change: 1 addition & 0 deletions osquery/utils/system/linux/ebpf/tests/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ osquery_cxx_test(
[
"ebpf.cpp",
"map.cpp",
"program.cpp",
],
),
],
Expand Down
45 changes: 45 additions & 0 deletions osquery/utils/system/linux/ebpf/tests/program.cpp
Original file line number Diff line number Diff line change
@@ -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 <osquery/utils/system/linux/ebpf/program.h>
#include <osquery/utils/system/linux/ebpf/ebpf.h>

#include <osquery/logger.h>

#include <gtest/gtest.h>

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

0 comments on commit 8127730

Please sign in to comment.