Skip to content

Commit

Permalink
wrapper around perf_event socket to bind ebpf program to some linux e…
Browse files Browse the repository at this point in the history
…vent

Summary: Part of a linux `syscalls` tracing system, blueprint: [osquery#5218](osquery#5218)

Differential Revision: D13622999

fbshipit-source-id: 1e673cd7bafcd7d77b1bfe35866c05a379f4d5b0
  • Loading branch information
akindyakov authored and facebook-github-bot committed Jan 22, 2019
1 parent 7883237 commit 5694af7
Show file tree
Hide file tree
Showing 6 changed files with 274 additions and 0 deletions.
45 changes: 45 additions & 0 deletions osquery/events/linux/probes/BUCK
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.

load("//tools/build_defs/oss/osquery:cxx.bzl", "osquery_cxx_library")
load("//tools/build_defs/oss/osquery:native.bzl", "osquery_target")
load("//tools/build_defs/oss/osquery:platforms.bzl", "LINUX")
load("//tools/build_defs/oss/osquery:third_party.bzl", "osquery_tp_target")

osquery_cxx_library(
name = "probes_events",
header_namespace = "osquery/events/linux/probes",
exported_platform_headers = [
(
LINUX,
[
"ebpf_tracepoint.h",
],
),
],
platform_srcs = [
(
LINUX,
[
"ebpf_tracepoint.cpp",
],
),
],
tests = [
osquery_target("osquery/events/linux/probes/tests:ebpf_tracepoint_tests"),
],
visibility = ["PUBLIC"],
deps = [
osquery_target("osquery/logger:logger"),
osquery_target("osquery/utils/conversions:conversions"),
osquery_target("osquery/utils/expected:expected"),
osquery_target("osquery/utils/system/linux/ebpf:ebpf"),
osquery_target("osquery/utils/system/linux/tracing:tracing"),
osquery_tp_target("boost"),
],
)
115 changes: 115 additions & 0 deletions osquery/events/linux/probes/ebpf_tracepoint.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/**
* 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/probes/ebpf_tracepoint.h>

#include <osquery/utils/expected/expected.h>
#include <osquery/utils/system/linux/perf_event/perf_event.h>

#include <osquery/logger.h>

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

#include <sys/ioctl.h>

namespace osquery {
namespace events {

EbpfTracepoint::EbpfTracepoint(EbpfTracepoint&& other) : fd_(other.fd_) {
other.fd_ = -1;
}

EbpfTracepoint& EbpfTracepoint::operator=(EbpfTracepoint&& other) {
std::swap(fd_, other.fd_);
return *this;
}

EbpfTracepoint::~EbpfTracepoint() {
forceUnload();
}

Expected<EbpfTracepoint, EbpfTracepoint::Error> EbpfTracepoint::load(
tracing::SystemEventId system_event_id, int prog_fd) {
auto instance = EbpfTracepoint{};

struct perf_event_attr trace_attr;
memset(&trace_attr, 0, sizeof(struct perf_event_attr));
trace_attr.type = PERF_TYPE_TRACEPOINT;
trace_attr.size = sizeof(struct perf_event_attr);
trace_attr.config = system_event_id;
trace_attr.sample_period = 1;
trace_attr.sample_type = PERF_SAMPLE_RAW;
trace_attr.wakeup_events = 1;
trace_attr.disabled = 1;

pid_t const pid = -1;
int const cpu = 0;
int const group_fd = -1;
unsigned long const flags = PERF_FLAG_FD_CLOEXEC;
auto fd_exp =
perf_event_open::syscall(&trace_attr, pid, cpu, group_fd, flags);
if (fd_exp.isError()) {
return createError(Error::SystemError,
"Fail to create perf_event tracepoint",
fd_exp.takeError());
}
instance.fd_ = fd_exp.take();

if (ioctl(instance.fd_, PERF_EVENT_IOC_SET_BPF, prog_fd) < 0) {
return createError(Error::SystemError,
"Fail to attach perf event of EbpfTracepoint ")
<< boost::io::quoted(strerror(errno));
}
if (ioctl(instance.fd_, PERF_EVENT_IOC_ENABLE, 0) < 0) {
return createError(Error::SystemError,
"Fail to enable perf event of EbpfTracepoint ")
<< boost::io::quoted(strerror(errno));
}
return Expected<EbpfTracepoint, EbpfTracepoint::Error>(std::move(instance));
}

ExpectedSuccess<EbpfTracepoint::Error> EbpfTracepoint::unload() {
if (fd_ < 0) {
return Success{};
}
bool failed = false;
std::string err_msg;
int ret = ioctl(fd_, PERF_EVENT_IOC_DISABLE, 0);
if (ret < 0) {
failed = true;
err_msg += " perf event disabling failed: \"";
err_msg += strerror(errno);
err_msg += "\". ";
}
ret = close(fd_);
if (ret < 0) {
failed = true;
err_msg += " file descriptor closed with error: \"";
err_msg += strerror(errno);
err_msg += "\".";
}
fd_ = -1;
if (failed) {
return createError(Error::SystemError, "EbpfTracepoint unload failed ")
<< err_msg;
}
return Success{};
}

void EbpfTracepoint::forceUnload() {
auto const exp = unload();
if (exp.isError()) {
LOG(ERROR) << "Could not unload perf tracepoint "
<< boost::io::quoted(exp.getError().getFullMessage());
}
}

} // namespace events
} // namespace osquery
49 changes: 49 additions & 0 deletions osquery/events/linux/probes/ebpf_tracepoint.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* 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 <osquery/utils/system/linux/tracing/types.h>

namespace osquery {
namespace events {

class EbpfTracepoint final {
public:
EbpfTracepoint(EbpfTracepoint&&);
EbpfTracepoint& operator=(EbpfTracepoint&&);

EbpfTracepoint(EbpfTracepoint const&) = delete;
EbpfTracepoint& operator=(EbpfTracepoint const&) = delete;

enum class Error {
Unknown = 1,
SystemError = 2,
};

~EbpfTracepoint();

static Expected<EbpfTracepoint, Error> load(
tracing::SystemEventId system_event_id, int ebpf_prog_fd);

private:
explicit EbpfTracepoint() = default;

ExpectedSuccess<Error> unload();

void forceUnload();

private:
int fd_ = -1;
};

} // namespace events
} // namespace osquery
30 changes: 30 additions & 0 deletions osquery/events/linux/probes/tests/BUCK
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# 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.

load("//tools/build_defs/oss/osquery:cxx.bzl", "osquery_cxx_test")
load("//tools/build_defs/oss/osquery:native.bzl", "osquery_target")
load("//tools/build_defs/oss/osquery:platforms.bzl", "LINUX")

osquery_cxx_test(
name = "ebpf_tracepoint_tests",
srcs = [
"empty.cpp",
],
platform_srcs = [
(
LINUX,
[
"ebpf_tracepoint.cpp",
],
),
],
visibility = ["PUBLIC"],
deps = [
osquery_target("osquery/events/linux/probes:probes_events"),
],
)
26 changes: 26 additions & 0 deletions osquery/events/linux/probes/tests/ebpf_tracepoint.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* 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 <gtest/gtest.h>

#include <osquery/events/linux/probes/ebpf_tracepoint.h>

namespace osquery {
namespace {

class EbpfTracepointTests : public testing::Test {};

TEST_F(EbpfTracepointTests, invalid_args) {
auto ebpf_tracepoint_exp = events::EbpfTracepoint::load(-1, -1);
ASSERT_TRUE(ebpf_tracepoint_exp.isError());
}

} // namespace
} // namespace osquery
9 changes: 9 additions & 0 deletions osquery/events/linux/probes/tests/empty.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* 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.
*/

0 comments on commit 5694af7

Please sign in to comment.