Skip to content

Commit

Permalink
fix bug for 24-hide (#111)
Browse files Browse the repository at this point in the history
  • Loading branch information
tanjunchen authored Feb 27, 2024
1 parent f67b347 commit 3a67878
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 45 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,5 @@ src/12-profile/profile
ecli-server
ecc
ecli

.vscode/
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,18 @@ TIME COMM TID LAT(us)

![docker](imgs/docker.png)

## build

The example of local compilation is shown as follows:

```shell
$ git clone https://github.com/eunomia-bpf/bpf-developer-tutorial.git
$ cd bpf-developer-tutorial
$ git submodule update --init --recursive # Synchronize submodule
$ cd src/24-hide
$ make
```

## Why do we need tutorials based on libbpf and BPF CO-RE?

> In history, when it comes to developing a BPF application, one could choose the BCC framework to load the BPF program into the kernel when implementing various BPF programs for Tracepoints. BCC provides a built-in Clang compiler that can compile BPF code at runtime and customize it into a program that conforms to a specific host kernel. This is the only way to develop maintainable BPF applications under the constantly changing internal kernel environment. The portability of BPF and the introduction of CO-RE are detailed in the article "BPF Portability and CO-RE", explaining why BCC was the only viable option before and why libbpf is now considered a better choice. Last year, Libbpf saw significant improvements in functionality and complexity, eliminating many differences with BCC (especially for Tracepoints applications) and adding many new and powerful features that BCC does not support (such as global variables and BPF skeletons)
Expand Down
12 changes: 12 additions & 0 deletions README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,18 @@ TIME COMM TID LAT(us)

![docker](imgs/docker.png)

## 本地编译

本地编译示例如下所示:

```shell
$ git clone https://github.com/eunomia-bpf/bpf-developer-tutorial.git
$ cd bpf-developer-tutorial
$ git submodule update --init --recursive # 同步 submodule 子模块
$ cd src/24-hide
$ make
```

## 为什么需要基于 libbpf 和 BPF CO-RE 的教程?

> 历史上,当需要开发一个BPF应用时可以选择BCC 框架,在实现各种用于Tracepoints的BPF程序时需要将BPF程序加载到内核中。BCC提供了内置的Clang编译器,可以在运行时编译BPF代码,并将其定制为符合特定主机内核的程序。这是在不断变化的内核内部下开发可维护的BPF应用程序的唯一方法。在BPF的可移植性和CO-RE一文中详细介绍了为什么会这样,以及为什么BCC是之前唯一的可行方式,此外还解释了为什么 libbpf 是目前比较好的选择。去年,Libbpf的功能和复杂性得到了重大提升,消除了与BCC之间的很多差异(特别是对Tracepoints应用来说),并增加了很多BCC不支持的新的且强大的特性(如全局变量和BPF skeletons)。
Expand Down
6 changes: 3 additions & 3 deletions src/24-hide/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ const volatile int target_ppid = 0;
// of the PID to hide. This becomes the name
// of the folder in /proc/
const volatile int pid_to_hide_len = 0;
const volatile char pid_to_hide[max_pid_len];
const volatile char pid_to_hide[MAX_PID_LEN];
// struct linux_dirent64 {
// u64 d_ino; /* 64-bit inode number */
Expand Down Expand Up @@ -177,7 +177,7 @@ int handle_getdents_exit(struct trace_event_raw_sys_exit *ctx)
struct linux_dirent64 *dirp = 0;
int pid = pid_tgid >> 32;
short unsigned int d_reclen = 0;
char filename[max_pid_len];
char filename[MAX_PID_LEN];

unsigned int bpos = 0;
unsigned int *pBPOS = bpf_map_lookup_elem(&map_bytes_read, &pid_tgid);
Expand Down Expand Up @@ -256,7 +256,7 @@ int handle_getdents_patch(struct trace_event_raw_sys_exit *ctx)
bpf_probe_read_user(&d_reclen, sizeof(d_reclen), &dirp->d_reclen);
// Debug print
char filename[max_pid_len];
char filename[MAX_PID_LEN];
bpf_probe_read_user_str(&filename, pid_to_hide_len, dirp_previous->d_name);
filename[pid_to_hide_len-1] = 0x00;
bpf_printk("[PID_HIDE] filename previous %s\n", filename);
Expand Down
6 changes: 3 additions & 3 deletions src/24-hide/README_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ const volatile int target_ppid = 0;
// of the PID to hide. This becomes the name
// of the folder in /proc/
const volatile int pid_to_hide_len = 0;
const volatile char pid_to_hide[max_pid_len];
const volatile char pid_to_hide[MAX_PID_LEN];
// struct linux_dirent64 {
// u64 d_ino; /* 64-bit inode number */
Expand Down Expand Up @@ -177,7 +177,7 @@ int handle_getdents_exit(struct trace_event_raw_sys_exit *ctx)
struct linux_dirent64 *dirp = 0;
int pid = pid_tgid >> 32;
short unsigned int d_reclen = 0;
char filename[max_pid_len];
char filename[MAX_PID_LEN];

unsigned int bpos = 0;
unsigned int *pBPOS = bpf_map_lookup_elem(&map_bytes_read, &pid_tgid);
Expand Down Expand Up @@ -256,7 +256,7 @@ int handle_getdents_patch(struct trace_event_raw_sys_exit *ctx)
bpf_probe_read_user(&d_reclen, sizeof(d_reclen), &dirp->d_reclen);
// Debug print
char filename[max_pid_len];
char filename[MAX_PID_LEN];
bpf_probe_read_user_str(&filename, pid_to_hide_len, dirp_previous->d_name);
filename[pid_to_hide_len-1] = 0x00;
bpf_printk("[PID_HIDE] filename previous %s\n", filename);
Expand Down
76 changes: 47 additions & 29 deletions src/24-hide/pidhide.bpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
#include "common.h"
#include "pidhide.h"

char LICENSE[] SEC("license") = "Dual BSD/GPL";

// Ringbuffer Map to pass messages from kernel to user
struct {
struct
{
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 256 * 1024);
} rb SEC(".maps");

// Map to fold the dents buffer addresses
struct {
struct
{
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 8192);
__type(key, size_t);
Expand All @@ -23,23 +25,26 @@ struct {

// Map used to enable searching through the
// data in a loop
struct {
struct
{
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 8192);
__type(key, size_t);
__type(value, int);
} map_bytes_read SEC(".maps");

// Map with address of actual
struct {
struct
{
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 8192);
__type(key, size_t);
__type(value, long unsigned int);
} map_to_patch SEC(".maps");

// Map to hold program tail calls
struct {
struct
{
__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
__uint(max_entries, 5);
__type(key, __u32);
Expand All @@ -53,25 +58,27 @@ const volatile int target_ppid = 0;
// of the PID to hide. This becomes the name
// of the folder in /proc/
const volatile int pid_to_hide_len = 0;
const volatile char pid_to_hide[max_pid_len];
const volatile char pid_to_hide[MAX_PID_LEN];

// struct linux_dirent64 {
// u64 d_ino; /* 64-bit inode number */
// u64 d_off; /* 64-bit offset to next structure */
// unsigned short d_reclen; /* Size of this dirent */
// unsigned char d_type; /* File type */
// char d_name[]; /* Filename (null-terminated) */ };
// char d_name[]; /* Filename (null-terminated) */ };
// int getdents64(unsigned int fd, struct linux_dirent64 *dirp, unsigned int count);
SEC("tp/syscalls/sys_enter_getdents64")
int handle_getdents_enter(struct trace_event_raw_sys_enter *ctx)
{
size_t pid_tgid = bpf_get_current_pid_tgid();
// Check if we're a process thread of interest
// if target_ppid is 0 then we target all pids
if (target_ppid != 0) {
if (target_ppid != 0)
{
struct task_struct *task = (struct task_struct *)bpf_get_current_task();
int ppid = BPF_CORE_READ(task, real_parent, tgid);
if (ppid != target_ppid) {
if (ppid != target_ppid)
{
return 0;
}
}
Expand All @@ -92,13 +99,15 @@ int handle_getdents_exit(struct trace_event_raw_sys_exit *ctx)
size_t pid_tgid = bpf_get_current_pid_tgid();
int total_bytes_read = ctx->ret;
// if bytes_read is 0, everything's been read
if (total_bytes_read <= 0) {
if (total_bytes_read <= 0)
{
return 0;
}

// Check we stored the address of the buffer from the syscall entry
long unsigned int* pbuff_addr = bpf_map_lookup_elem(&map_buffs, &pid_tgid);
if (pbuff_addr == 0) {
long unsigned int *pbuff_addr = bpf_map_lookup_elem(&map_buffs, &pid_tgid);
if (pbuff_addr == 0)
{
return 0;
}

Expand All @@ -111,29 +120,35 @@ int handle_getdents_exit(struct trace_event_raw_sys_exit *ctx)
struct linux_dirent64 *dirp = 0;
int pid = pid_tgid >> 32;
short unsigned int d_reclen = 0;
char filename[max_pid_len];
char filename[MAX_PID_LEN];

unsigned int bpos = 0;
unsigned int *pBPOS = bpf_map_lookup_elem(&map_bytes_read, &pid_tgid);
if (pBPOS != 0) {
if (pBPOS != 0)
{
bpos = *pBPOS;
}

for (int i = 0; i < 200; i ++) {
if (bpos >= total_bytes_read) {
for (int i = 0; i < 200; i++)
{
if (bpos >= total_bytes_read)
{
break;
}
dirp = (struct linux_dirent64 *)(buff_addr+bpos);
dirp = (struct linux_dirent64 *)(buff_addr + bpos);
bpf_probe_read_user(&d_reclen, sizeof(d_reclen), &dirp->d_reclen);
bpf_probe_read_user_str(&filename, pid_to_hide_len, dirp->d_name);

int j = 0;
for (j = 0; j < pid_to_hide_len; j++) {
if (filename[j] != pid_to_hide[j]) {
for (j = 0; j < pid_to_hide_len; j++)
{
if (filename[j] != pid_to_hide[j])
{
break;
}
}
if (j == pid_to_hide_len) {
if (j == pid_to_hide_len)
{
// ***********
// We've found the folder!!!
// Jump to handle_getdents_patch so we can remove it!
Expand All @@ -148,7 +163,8 @@ int handle_getdents_exit(struct trace_event_raw_sys_exit *ctx)

// If we didn't find it, but there's still more to read,
// jump back the start of this function and keep looking
if (bpos < total_bytes_read) {
if (bpos < total_bytes_read)
{
bpf_map_update_elem(&map_bytes_read, &pid_tgid, &bpos, BPF_ANY);
bpf_tail_call(ctx, &map_prog_array, PROG_01);
}
Expand All @@ -163,8 +179,9 @@ int handle_getdents_patch(struct trace_event_raw_sys_exit *ctx)
{
// Only patch if we've already checked and found our pid's folder to hide
size_t pid_tgid = bpf_get_current_pid_tgid();
long unsigned int* pbuff_addr = bpf_map_lookup_elem(&map_to_patch, &pid_tgid);
if (pbuff_addr == 0) {
long unsigned int *pbuff_addr = bpf_map_lookup_elem(&map_to_patch, &pid_tgid);
if (pbuff_addr == 0)
{
return 0;
}

Expand All @@ -176,17 +193,17 @@ int handle_getdents_patch(struct trace_event_raw_sys_exit *ctx)
short unsigned int d_reclen_previous = 0;
bpf_probe_read_user(&d_reclen_previous, sizeof(d_reclen_previous), &dirp_previous->d_reclen);

struct linux_dirent64 *dirp = (struct linux_dirent64 *)(buff_addr+d_reclen_previous);
struct linux_dirent64 *dirp = (struct linux_dirent64 *)(buff_addr + d_reclen_previous);
short unsigned int d_reclen = 0;
bpf_probe_read_user(&d_reclen, sizeof(d_reclen), &dirp->d_reclen);

// Debug print
char filename[max_pid_len];
char filename[MAX_PID_LEN];
bpf_probe_read_user_str(&filename, pid_to_hide_len, dirp_previous->d_name);
filename[pid_to_hide_len-1] = 0x00;
filename[pid_to_hide_len - 1] = 0x00;
bpf_printk("[PID_HIDE] filename previous %s\n", filename);
bpf_probe_read_user_str(&filename, pid_to_hide_len, dirp->d_name);
filename[pid_to_hide_len-1] = 0x00;
filename[pid_to_hide_len - 1] = 0x00;
bpf_printk("[PID_HIDE] filename next one %s\n", filename);

// Attempt to overwrite
Expand All @@ -196,7 +213,8 @@ int handle_getdents_patch(struct trace_event_raw_sys_exit *ctx)
// Send an event
struct event *e;
e = bpf_ringbuf_reserve(&rb, sizeof(*e), 0);
if (e) {
if (e)
{
e->success = (ret == 0);
e->pid = (pid_tgid >> 32);
bpf_get_current_comm(&e->comm, sizeof(e->comm));
Expand Down
11 changes: 3 additions & 8 deletions src/24-hide/pidhide.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,7 @@
#include <fcntl.h>

#include "pidhide.skel.h"
#include "common.h"

// These are used by a number of
// different programs to sync eBPF Tail Call
// login between user space and kernel
#define PROG_00 0
#define PROG_01 1
#define PROG_02 2
#include "pidhide.h"

// Setup Argument stuff
static struct env
Expand All @@ -44,6 +37,7 @@ static const struct argp_option opts[] = {
{"target-ppid", 't', "TARGET-PPID", 0, "Optional Parent PID, will only affect its children."},
{},
};

static error_t parse_arg(int key, char *arg, struct argp_state *state)
{
switch (key)
Expand Down Expand Up @@ -74,6 +68,7 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state)
}
return 0;
}

static const struct argp argp = {
.options = opts,
.parser = parse_arg,
Expand Down
14 changes: 12 additions & 2 deletions src/24-hide/common.h → src/24-hide/pidhide.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,20 @@
// Simple message structure to get events from eBPF Programs
// in the kernel to user spcae
#define TASK_COMM_LEN 16
struct event {
#define MAX_PID_LEN 16

// These are used by a number of
// different programs to sync eBPF Tail Call
// login between user space and kernel
#define PROG_00 0
#define PROG_01 1
#define PROG_02 2

struct event
{
int pid;
char comm[TASK_COMM_LEN];
bool success;
};

#endif // BAD_BPF_COMMON_H
#endif // BAD_BPF_COMMON_H

0 comments on commit 3a67878

Please sign in to comment.