Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 13 additions & 28 deletions MODULE.bazel.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 46 additions & 14 deletions ebpf_ffi/ebpf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

#include "ebpf_ffi/ebpf.h"

#include <vector>

namespace ebpf_ffi {

// This constant was determined arbitrarily, the number of 0's has incremented
Expand Down Expand Up @@ -44,9 +46,29 @@ int btf_load(void *btf_buff, size_t btf_size, std::string &error) {
return btf_fd;
}

int load_ebpf_program(EncodedProgram program, size_t size,
std::string &verifier_log, std::string &error) {
uint64_t setup_bpf_maps(std::vector<ebpf::EbpfMap> maps) {
size_t fd_array_size = sizeof(int) * maps.size();
int *fd_array = (int *)malloc(fd_array_size);
if (!fd_array) return 0;
int i = 0;
for (ebpf::EbpfMap map : maps) {
int map_fd =
bpf_create_map(static_cast<bpf_map_type>(map.type()), map.key_size(),
map.value_size(), map.max_entries());
if (map_fd > 0) {
int j = 0;
for (uint64_t element : map.values()) {
ffi_update_map_element(map_fd, j++, element);
}
}
fd_array[i++] = map_fd;
}
return reinterpret_cast<uint64_t>(fd_array);
}

ValidationResult load_ebpf_program(EncodedProgram program, std::string &error) {
struct bpf_insn *insn;
ValidationResult res;
union bpf_attr attr = {};

// For the verifier log.
Expand All @@ -73,22 +95,30 @@ int load_ebpf_program(EncodedProgram program, size_t size,
attr.log_buf = (uint64_t)log_buf;
attr.log_level = 2;

if (program.maps().size() > 0) {
uint64_t fd_array = setup_bpf_maps(std::vector<ebpf::EbpfMap>(
program.maps().begin(), program.maps().end()));
attr.fd_array = fd_array;
res.set_fd_array_addr(fd_array);
}

int program_fd = syscall(SYS_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
if (program_fd < 0) {
error = strerror(errno);
}
res.set_program_fd(program_fd);

verifier_log =
std::string((const char *)log_buf, strlen((const char *)log_buf));
res.set_verifier_log(
std::string((const char *)log_buf, strlen((const char *)log_buf)));

free(log_buf);
return program_fd;
return res;
}

struct bpf_result ffi_load_ebpf_program(void *serialized_proto, size_t size,
int coverage_enabled,
uint64_t coverage_size) {
std::string verifier_log, error_message;
std::string error_message;

struct coverage_data cover;
memset(&cover, 0, sizeof(struct coverage_data));
Expand All @@ -102,15 +132,9 @@ struct bpf_result ffi_load_ebpf_program(void *serialized_proto, size_t size,
if (!program.ParseFromString(serialized_proto_string)) {
error_message = "Could not parse EncodedProgram proto";
}
int program_fd =
load_ebpf_program(program, size, verifier_log, error_message);
ValidationResult vres;
ValidationResult vres = load_ebpf_program(program, error_message);
if (coverage_enabled) get_coverage_and_free_resources(&cover, &vres);

// Start building the validation result proto.
vres.set_verifier_log(verifier_log);
vres.set_program_fd(program_fd);

if (cover.fd != -1) {
vres.set_did_collect_coverage(true);
vres.set_coverage_size(cover.coverage_size);
Expand All @@ -119,7 +143,7 @@ struct bpf_result ffi_load_ebpf_program(void *serialized_proto, size_t size,
vres.set_did_collect_coverage(false);
}

if (program_fd < 0) {
if (vres.program_fd() < 0) {
// Return why we failed to load the program.
vres.set_bpf_error(error_message);
vres.set_is_valid(false);
Expand Down Expand Up @@ -240,3 +264,11 @@ struct bpf_result ffi_execute_ebpf_program(void *serialized_proto,
execution_result.set_did_succeed(true);
return serialize_proto(execution_result);
}

void ffi_clean_fd_array(unsigned long long int addr, int size) {
int *fd_array = reinterpret_cast<int *>(addr);
for (int i = 0; i < size; i++) {
close(fd_array[size]);
}
free(fd_array);
}
6 changes: 4 additions & 2 deletions ebpf_ffi/ebpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ extern "C" {
// Actual implementation of load program. The split between ffi and
// implementation is done so the impl code can be shared with other parts of the
// codebase also written in C++.
int load_ebpf_program(EncodedProgram program, size_t size,
std::string &verifier_log, std::string &error);
ValidationResult load_ebpf_program(EncodedProgram program, std::string &error);

// Loads a bpf program specified by |prog_buff| with |size| and returns struct
// with a serialized ValidationResult proto.
Expand Down Expand Up @@ -62,5 +61,8 @@ bool execute_ebpf_program(int prog_fd, uint8_t *input, int input_length,
// Serialized proto is of type ExecutionRequest.
struct bpf_result ffi_execute_ebpf_program(void *serialized_proto,
size_t length);

// Helps clean up any setup map fd array for a program.
void ffi_clean_fd_array(unsigned long long int addr, int size);
}
#endif // EBPF_FUZZER_EBPF_FFI_EBPF_H_
3 changes: 2 additions & 1 deletion pkg/ebpf/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ const (
)

const (
PseudoMapFD = pb.Reg_R1
PseudoMapFD = pb.Reg_R1
PseudoMapIdx = pb.Reg_R5
)

const (
Expand Down
20 changes: 20 additions & 0 deletions pkg/ebpf/st_ld_instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,26 @@ func LdMapByFd(dst pb.Reg, fd int) *pb.Instruction {
return newLoadImmOperation(pb.StLdSize_StLdSizeDW, dst, PseudoMapFD, UnusedField, int32(fd), pseudoIns)
}

func LdMapByIdx(dst pb.Reg, idx int) *pb.Instruction {
pseudoIns := &pb.Instruction{
Opcode: &pb.Instruction_MemOpcode{
MemOpcode: &pb.MemOpcode{
Mode: 0,
Size: 0,
InstructionClass: 0,
},
},
DstReg: 0,
SrcReg: 0,
Offset: 0,
Immediate: 0,
PseudoInstruction: &pb.Instruction_Empty{
Empty: &pb.Empty{},
},
}
return newLoadImmOperation(pb.StLdSize_StLdSizeDW, dst, PseudoMapIdx, UnusedField, int32(idx), pseudoIns)
}

func newAtomicInstruction(dst, src pb.Reg, size pb.StLdSize, offset int16, operation int32) *pb.Instruction {
class := pb.InsClass_InsClassStx

Expand Down
4 changes: 4 additions & 0 deletions pkg/units/control.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,12 @@ func (cu *Control) runEbpf(prog *epb.Program) error {
Program: encodedProg,
Btf: prog.Btf,
Function: encodedFuncInfo,
Maps: prog.Maps,
}
validationResult, err := cu.ffi.ValidateEbpfProgram(encodedProgram)
defer func() {
cu.ffi.CleanFdArray(validationResult.FdArrayAddr, len(prog.Maps))
}()
if err != nil {
fmt.Printf("Validation error: %v\n", err)
if !cu.strat.OnError(err) {
Expand Down
10 changes: 10 additions & 0 deletions pkg/units/ffi.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ package units
//int ffi_create_bpf_map(size_t size);
//void ffi_close_fd(int fd);
//int ffi_update_map_element(int map_fd, int key, uint64_t value);
//void ffi_clean_fd_array(unsigned long long int addr, int size);
import "C"

import (
Expand Down Expand Up @@ -132,6 +133,15 @@ func (e *FFI) SetMapElement(fd int, key uint32, value uint64) int {
return int(C.ffi_update_map_element(C.int(fd), C.int(key), C.ulong(value)))
}

// SetMapElement sets the elemnt specified by `key` to `value` in the map
// described by `fd`
func (e *FFI) CleanFdArray(fd_array uint64, size int) {
if fd_array == 0 {
return
}
C.ffi_clean_fd_array(C.ulonglong(fd_array), C.int(size))
}

// ----------- eBPF --------------
// ValidateProgram passes the program through the bpf verifier without executing
// it. Returns feedback to the generator so it can adjust the generation
Expand Down
4 changes: 2 additions & 2 deletions proto/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ cc_proto_library(
proto_library(
name = "ffi_proto",
srcs = ["ffi.proto"],
deps = [],
deps = [":ebpf_proto"],
)

go_proto_library(
name = "ffi_go_proto",
importpath = "buzzer/proto/ffi_go_proto",
protos = [":ffi_proto"],
deps = [],
deps = [":ebpf_go_proto"],
)

cc_proto_library(
Expand Down
2 changes: 2 additions & 0 deletions proto/btf.proto
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ syntax = "proto3";
// https://docs.kernel.org/bpf/btf.html
package btf;

option go_package = "buzzer/proto/btf_go_proto";

message Empty {}

// List of Supported Types
Expand Down
50 changes: 50 additions & 0 deletions proto/ebpf.proto
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import "proto/btf.proto";
// https://www.kernel.org/doc/html/v5.17/bpf/instruction-set.html
package ebpf;

option go_package = "buzzer/proto/ebpf_go_proto";

message Empty {}

// Reg each value corresponds to an ebpf register.
Expand Down Expand Up @@ -165,7 +167,55 @@ message Functions {
btf.FuncInfo func_info = 2;
}

enum BpfMapType {
UNSPEC = 0;
HASH = 1;
ARRAY = 2;
PROG_ARRAY = 3;
PERF_EVENT_ARRAY = 4;
PERCPU_HASH = 5;
PERCPU_ARRAY = 6;
STACK_TRACE = 7;
CGROUP_ARRAY = 8;
LRU_HASH = 9;
LRU_PERCPU_HASH = 10;
LPM_TRIE = 11;
ARRAY_OF_MAPS = 12;
HASH_OF_MAPS = 13;
DEVMAP = 14;
SOCKMAP = 15;
CPUMAP = 16;
XSKMAP = 17;
SOCKHASH = 18;
CGROUP_STORAGE_DEPRECATED = 19;
CGROUP_STORAGE = 20;
REUSEPORT_SOCKARRAY = 21;
PERCPU_CGROUP_STORAGE_DEPRECATED = 22;
PERCPU_CGROUP_STORAGE = 23;
QUEUE = 24;
STACK = 25;
SK_STORAGE = 26;
DEVMAP_HASH = 27;
STRUCT_OPS = 28;
RINGBUF = 29;
INODE_STORAGE = 30;
TASK_STORAGE = 31;
BLOOM_FILTER = 32;
USER_RINGBUF = 33;
CGRP_STORAGE = 34;
ARENA = 35;
}

message EbpfMap {
BpfMapType type = 1;
uint32 key_size = 2;
uint32 value_size = 3;
uint32 max_entries = 4;
repeated uint64 values = 5;
}

message Program {
bytes btf = 1;
repeated Functions functions = 2;
repeated EbpfMap maps = 3;
}
Loading
Loading