blob: b7302daf0c7ce73d878b7f85a7a8cf5fe042126c [file] [log] [blame]
Brenden Blanco561dafc2015-06-29 11:09:00 -07001#!/usr/bin/env python
2# Copyright (c) PLUMgrid, Inc.
3# Licensed under the Apache License, Version 2.0 (the "License")
4
Brenden Blancoc35989d2015-09-02 18:04:07 -07005from bcc import BPF
Paul Chaignon6ceb3292017-04-01 18:23:58 +02006import ctypes as ct
Paul Chaignon719e1002017-08-06 14:33:20 +02007from unittest import main, skipUnless, TestCase
Paul Chaignon93419422017-03-12 14:49:01 +01008import os
9import sys
Olivier Tilmansa1962c62017-11-24 01:54:26 +010010import socket
11import struct
Paul Chaignon93419422017-03-12 14:49:01 +010012from contextlib import contextmanager
Paul Chaignon719e1002017-08-06 14:33:20 +020013import distutils.version
Paul Chaignon93419422017-03-12 14:49:01 +010014
15@contextmanager
16def redirect_stderr(to):
17 stderr_fd = sys.stderr.fileno()
18 with os.fdopen(os.dup(stderr_fd), 'wb') as copied, os.fdopen(to, 'w') as to:
19 sys.stderr.flush()
20 os.dup2(to.fileno(), stderr_fd)
21 try:
22 yield sys.stderr
23 finally:
24 sys.stderr.flush()
25 os.dup2(copied.fileno(), stderr_fd)
Brenden Blanco561dafc2015-06-29 11:09:00 -070026
Paul Chaignon719e1002017-08-06 14:33:20 +020027def kernel_version_ge(major, minor):
28 # True if running kernel is >= X.Y
29 version = distutils.version.LooseVersion(os.uname()[2]).version
30 if version[0] > major:
31 return True
32 if version[0] < major:
33 return False
34 if minor and version[1] < minor:
35 return False
36 return True
37
Brenden Blanco561dafc2015-06-29 11:09:00 -070038class TestClang(TestCase):
39 def test_complex(self):
40 b = BPF(src_file="test_clang_complex.c", debug=0)
41 fn = b.load_func("handle_packet", BPF.SCHED_CLS)
42 def test_printk(self):
43 text = """
44#include <bcc/proto.h>
45int handle_packet(void *ctx) {
Brenden Blanco6ec65e42015-07-02 10:02:04 -070046 u8 *cursor = 0;
47 struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
48 bpf_trace_printk("ethernet->dst = %llx, ethernet->src = %llx\\n",
49 ethernet->dst, ethernet->src);
Brenden Blanco561dafc2015-06-29 11:09:00 -070050 return 0;
51}
52"""
53 b = BPF(text=text, debug=0)
54 fn = b.load_func("handle_packet", BPF.SCHED_CLS)
55
Brenden Blancob711d452015-07-01 15:23:18 -070056 def test_probe_read1(self):
57 text = """
58#include <linux/sched.h>
59#include <uapi/linux/ptrace.h>
60int count_sched(struct pt_regs *ctx, struct task_struct *prev) {
61 pid_t p = prev->pid;
62 return (p != -1);
63}
64"""
65 b = BPF(text=text, debug=0)
66 fn = b.load_func("count_sched", BPF.KPROBE)
67
68 def test_probe_read2(self):
69 text = """
70#include <linux/sched.h>
71#include <uapi/linux/ptrace.h>
72int count_foo(struct pt_regs *ctx, unsigned long a, unsigned long b) {
73 return (a != b);
74}
75"""
76 b = BPF(text=text, debug=0)
77 fn = b.load_func("count_foo", BPF.KPROBE)
78
yonghong-song66d28632018-06-14 07:11:42 -070079 def test_probe_read3(self):
80 text = """
81#define KBUILD_MODNAME "foo"
82#include <net/tcp.h>
83#define _(P) ({typeof(P) val = 0; bpf_probe_read(&val, sizeof(val), &P); val;})
84int count_tcp(struct pt_regs *ctx, struct sk_buff *skb) {
85 return _(TCP_SKB_CB(skb)->tcp_gso_size);
86}
87"""
88 b = BPF(text=text)
89 fn = b.load_func("count_tcp", BPF.KPROBE)
90
Paul Chaignona9f96c02018-06-15 00:27:08 +020091 def test_probe_read4(self):
92 text = """
93#define KBUILD_MODNAME "foo"
94#include <net/tcp.h>
95#define _(P) ({typeof(P) val = 0; bpf_probe_read(&val, sizeof(val), &P); val;})
96int test(struct pt_regs *ctx, struct sk_buff *skb) {
97 return _(TCP_SKB_CB(skb)->tcp_gso_size) + skb->protocol;
98}
99"""
100 b = BPF(text=text)
101 fn = b.load_func("test", BPF.KPROBE)
102
Paul Chaignoneebd4852018-06-13 03:55:52 +0200103 def test_probe_read_whitelist1(self):
Yonghong Song20fb64c2018-06-02 00:28:38 -0700104 text = """
105#define KBUILD_MODNAME "foo"
106#include <net/tcp.h>
107int count_tcp(struct pt_regs *ctx, struct sk_buff *skb) {
108 // The below define is in net/tcp.h:
109 // #define TCP_SKB_CB(__skb) ((struct tcp_skb_cb *)&((__skb)->cb[0]))
110 // Note that it has AddrOf in the macro, which will cause current rewriter
111 // failing below statement
112 // return TCP_SKB_CB(skb)->tcp_gso_size;
113 u16 val = 0;
114 bpf_probe_read(&val, sizeof(val), &(TCP_SKB_CB(skb)->tcp_gso_size));
115 return val;
116}
117"""
118 b = BPF(text=text)
119 fn = b.load_func("count_tcp", BPF.KPROBE)
120
Paul Chaignoneebd4852018-06-13 03:55:52 +0200121 def test_probe_read_whitelist2(self):
122 text = """
123#define KBUILD_MODNAME "foo"
124#include <net/tcp.h>
125int count_tcp(struct pt_regs *ctx, struct sk_buff *skb) {
126 // The below define is in net/tcp.h:
127 // #define TCP_SKB_CB(__skb) ((struct tcp_skb_cb *)&((__skb)->cb[0]))
128 // Note that it has AddrOf in the macro, which will cause current rewriter
129 // failing below statement
130 // return TCP_SKB_CB(skb)->tcp_gso_size;
131 u16 val = 0;
132 bpf_probe_read(&val, sizeof(val), &(TCP_SKB_CB(skb)->tcp_gso_size));
133 return val + skb->protocol;
134}
135"""
136 b = BPF(text=text)
137 fn = b.load_func("count_tcp", BPF.KPROBE)
138
Brenden Blanco3c4a29c2015-09-08 22:16:10 -0700139 def test_probe_read_keys(self):
140 text = """
141#include <uapi/linux/ptrace.h>
142#include <linux/blkdev.h>
143BPF_HASH(start, struct request *);
144int do_request(struct pt_regs *ctx, struct request *req) {
145 u64 ts = bpf_ktime_get_ns();
146 start.update(&req, &ts);
147 return 0;
148}
149
150int do_completion(struct pt_regs *ctx, struct request *req) {
151 u64 *tsp = start.lookup(&req);
152 if (tsp != 0) {
153 start.delete(&req);
154 }
155 return 0;
156}
157"""
158 b = BPF(text=text, debug=0)
159 fns = b.load_funcs(BPF.KPROBE)
160
Brenden Blanco00ee4fe2015-08-07 21:04:35 -0700161 def test_sscanf(self):
Brenden Blanco52b0a902015-08-07 08:28:02 -0700162 text = """
Teng Qin7a3e5bc2017-03-29 13:39:17 -0700163BPF_HASH(stats, int, struct { u64 a; u64 b; u64 c:36; u64 d:28; struct { u32 a; u32 b; } s; }, 10);
Brenden Blanco52b0a902015-08-07 08:28:02 -0700164int foo(void *ctx) {
165 return 0;
166}
167"""
168 b = BPF(text=text, debug=0)
169 fn = b.load_func("foo", BPF.KPROBE)
Brenden Blanco985adf62015-08-08 21:00:59 -0700170 t = b.get_table("stats")
Brenden Blanco2582ecf2015-08-12 12:08:00 -0700171 s1 = t.key_sprintf(t.Key(2))
172 self.assertEqual(s1, b"0x2")
173 s2 = t.leaf_sprintf(t.Leaf(2, 3, 4, 1, (5, 6)))
174 l = t.leaf_scanf(s2)
Brenden Blanco985adf62015-08-08 21:00:59 -0700175 self.assertEqual(l.a, 2)
176 self.assertEqual(l.b, 3)
177 self.assertEqual(l.c, 4)
178 self.assertEqual(l.d, 1)
179 self.assertEqual(l.s.a, 5)
180 self.assertEqual(l.s.b, 6)
Brenden Blanco52b0a902015-08-07 08:28:02 -0700181
Brenden Blanco39354092016-02-06 20:59:10 -0800182 def test_sscanf_array(self):
183 text = """
Teng Qin7a3e5bc2017-03-29 13:39:17 -0700184BPF_HASH(stats, int, struct { u32 a[3]; u32 b; }, 10);
Brenden Blanco39354092016-02-06 20:59:10 -0800185"""
186 b = BPF(text=text, debug=0)
187 t = b.get_table("stats")
188 s1 = t.key_sprintf(t.Key(2))
189 self.assertEqual(s1, b"0x2")
Paul Chaignon6ceb3292017-04-01 18:23:58 +0200190 s2 = t.leaf_sprintf(t.Leaf((ct.c_uint * 3)(1,2,3), 4))
Brenden Blanco39354092016-02-06 20:59:10 -0800191 self.assertEqual(s2, b"{ [ 0x1 0x2 0x3 ] 0x4 }")
192 l = t.leaf_scanf(s2)
193 self.assertEqual(l.a[0], 1)
194 self.assertEqual(l.a[1], 2)
195 self.assertEqual(l.a[2], 3)
196 self.assertEqual(l.b, 4)
197
Brenden Blancodaee97e2017-05-09 13:52:42 -0700198 def test_sscanf_string(self):
199 text = """
200struct Symbol {
201 char name[128];
202 char path[128];
203};
204struct Event {
205 uint32_t pid;
206 uint32_t tid;
207 struct Symbol stack[64];
208};
209BPF_TABLE("array", int, struct Event, comms, 1);
210"""
211 b = BPF(text=text)
212 t = b.get_table("comms")
213 s1 = t.leaf_sprintf(t[0])
214 fill = b' { "" "" }' * 63
215 self.assertEqual(s1, b'{ 0x0 0x0 [ { "" "" }%s ] }' % fill)
216 l = t.Leaf(1, 2)
217 name = b"libxyz"
218 path = b"/usr/lib/libxyz.so"
219 l.stack[0].name = name
220 l.stack[0].path = path
221 s2 = t.leaf_sprintf(l)
222 self.assertEqual(s2,
223 b'{ 0x1 0x2 [ { "%s" "%s" }%s ] }' % (name, path, fill))
224 l = t.leaf_scanf(s2)
225 self.assertEqual(l.pid, 1)
226 self.assertEqual(l.tid, 2)
227 self.assertEqual(l.stack[0].name, name)
228 self.assertEqual(l.stack[0].path, path)
229
Brenden Blancodfcdf0a2015-08-11 12:45:00 -0700230 def test_iosnoop(self):
231 text = """
232#include <linux/blkdev.h>
233#include <uapi/linux/ptrace.h>
234
235struct key_t {
236 struct request *req;
237};
238
Teng Qin7a3e5bc2017-03-29 13:39:17 -0700239BPF_HASH(start, struct key_t, u64, 1024);
Brenden Blancodfcdf0a2015-08-11 12:45:00 -0700240int do_request(struct pt_regs *ctx, struct request *req) {
241 struct key_t key = {};
242
243 bpf_trace_printk("traced start %d\\n", req->__data_len);
244
245 return 0;
246}
247"""
248 b = BPF(text=text, debug=0)
249 fn = b.load_func("do_request", BPF.KPROBE)
250
Brenden Blancoa328d232015-08-11 18:33:49 -0700251 def test_blk_start_request(self):
252 text = """
253#include <linux/blkdev.h>
254#include <uapi/linux/ptrace.h>
255int do_request(struct pt_regs *ctx, int req) {
256 bpf_trace_printk("req ptr: 0x%x\\n", req);
257 return 0;
258}
259"""
260 b = BPF(text=text, debug=0)
261 fn = b.load_func("do_request", BPF.KPROBE)
262
Brenden Blanco7b9e5f12015-09-05 21:54:59 -0700263 def test_bpf_hash(self):
264 text = """
265BPF_HASH(table1);
266BPF_HASH(table2, u32);
267BPF_HASH(table3, u32, int);
268"""
269 b = BPF(text=text, debug=0)
270
Brenden Blanco70fa0a12015-09-15 15:46:26 -0700271 def test_consecutive_probe_read(self):
272 text = """
273#include <linux/fs.h>
274#include <linux/mount.h>
275BPF_HASH(table1, struct super_block *);
276int trace_entry(struct pt_regs *ctx, struct file *file) {
277 if (!file) return 0;
278 struct vfsmount *mnt = file->f_path.mnt;
279 if (mnt) {
280 struct super_block *k = mnt->mnt_sb;
281 u64 zero = 0;
282 table1.update(&k, &zero);
283 k = mnt->mnt_sb;
284 table1.update(&k, &zero);
285 }
286
287 return 0;
288}
289"""
290 b = BPF(text=text, debug=0)
291 fn = b.load_func("trace_entry", BPF.KPROBE)
292
293 def test_nested_probe_read(self):
294 text = """
295#include <linux/fs.h>
296int trace_entry(struct pt_regs *ctx, struct file *file) {
297 if (!file) return 0;
298 const char *name = file->f_path.dentry->d_name.name;
299 bpf_trace_printk("%s\\n", name);
300 return 0;
301}
302"""
303 b = BPF(text=text, debug=0)
304 fn = b.load_func("trace_entry", BPF.KPROBE)
305
Paul Chaignonfa7508d2018-06-17 17:47:18 +0200306 def test_nested_probe_read_deref(self):
307 text = """
308#include <uapi/linux/ptrace.h>
309struct sock {
310 u32 *sk_daddr;
311};
312int test(struct pt_regs *ctx, struct sock *skp) {
313 return *(skp->sk_daddr);
314}
315"""
316 b = BPF(text=text)
317 fn = b.load_func("test", BPF.KPROBE)
318
Brenden Blanco9518e742015-09-16 14:06:06 -0700319 def test_char_array_probe(self):
320 BPF(text="""#include <linux/blkdev.h>
321int kprobe__blk_update_request(struct pt_regs *ctx, struct request *req) {
322 bpf_trace_printk("%s\\n", req->rq_disk->disk_name);
323 return 0;
324}""")
325
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700326 def test_probe_read_helper(self):
327 b = BPF(text="""
328#include <linux/fs.h>
329static void print_file_name(struct file *file) {
330 if (!file) return;
331 const char *name = file->f_path.dentry->d_name.name;
332 bpf_trace_printk("%s\\n", name);
333}
Brenden Blanco05f60a82015-09-17 14:23:34 -0700334static void print_file_name2(int unused, struct file *file) {
335 print_file_name(file);
336}
337int trace_entry1(struct pt_regs *ctx, struct file *file) {
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700338 print_file_name(file);
339 return 0;
340}
Brenden Blanco05f60a82015-09-17 14:23:34 -0700341int trace_entry2(struct pt_regs *ctx, int unused, struct file *file) {
342 print_file_name2(unused, file);
343 return 0;
344}
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700345""")
Brenden Blanco05f60a82015-09-17 14:23:34 -0700346 fn = b.load_func("trace_entry1", BPF.KPROBE)
347 fn = b.load_func("trace_entry2", BPF.KPROBE)
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700348
Brenden Blanco545008a2016-08-18 14:33:29 -0700349 def test_probe_unnamed_union_deref(self):
350 text = """
351#include <linux/mm_types.h>
352int trace(struct pt_regs *ctx, struct page *page) {
353 void *p = page->mapping;
354 return p != NULL;
355}
356"""
357 # depending on llvm, compile may pass/fail, but at least shouldn't crash
358 try:
359 b = BPF(text=text)
360 except:
361 pass
362
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700363 def test_probe_struct_assign(self):
364 b = BPF(text = """
365#include <uapi/linux/ptrace.h>
366struct args_t {
367 const char *filename;
368 int flags;
369 int mode;
370};
Yonghong Song83b49ad2018-04-24 10:15:24 -0700371int do_sys_open(struct pt_regs *ctx, const char *filename,
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700372 int flags, int mode) {
373 struct args_t args = {};
374 args.filename = filename;
375 args.flags = flags;
376 args.mode = mode;
377 bpf_trace_printk("%s\\n", args.filename);
378 return 0;
379};
380""")
Yonghong Song83b49ad2018-04-24 10:15:24 -0700381 b.attach_kprobe(event=b.get_syscall_fnname("open"),
382 fn_name="do_sys_open")
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700383
Brenden Blanco74adb732015-09-29 13:44:19 -0700384 def test_task_switch(self):
385 b = BPF(text="""
386#include <uapi/linux/ptrace.h>
387#include <linux/sched.h>
388struct key_t {
389 u32 prev_pid;
390 u32 curr_pid;
391};
Teng Qin7a3e5bc2017-03-29 13:39:17 -0700392BPF_HASH(stats, struct key_t, u64, 1024);
Brenden Blanco74adb732015-09-29 13:44:19 -0700393int kprobe__finish_task_switch(struct pt_regs *ctx, struct task_struct *prev) {
394 struct key_t key = {};
395 u64 zero = 0, *val;
396 key.curr_pid = bpf_get_current_pid_tgid();
397 key.prev_pid = prev->pid;
398
399 val = stats.lookup_or_init(&key, &zero);
400 (*val)++;
401 return 0;
402}
403""")
404
Brenden Blancoc48ab4b2015-10-01 11:18:07 -0700405 def test_probe_simple_assign(self):
406 b = BPF(text="""
407#include <uapi/linux/ptrace.h>
408#include <linux/gfp.h>
409struct leaf { size_t size; };
410BPF_HASH(simple_map, u32, struct leaf);
411int kprobe____kmalloc(struct pt_regs *ctx, size_t size) {
412 u32 pid = bpf_get_current_pid_tgid();
413 struct leaf* leaf = simple_map.lookup(&pid);
414 if (leaf)
415 leaf->size += size;
416 return 0;
Brenden Blancofe88e5a2015-12-06 19:58:38 -0800417}""")
Brenden Blanco8ed57a22015-09-16 14:59:35 -0700418
Paul Chaignonb341d8f2018-05-05 10:45:58 +0200419 def test_probe_simple_member_assign(self):
420 b = BPF(text="""
421#include <uapi/linux/ptrace.h>
422#include <linux/netdevice.h>
423struct leaf { void *ptr; };
424int test(struct pt_regs *ctx, struct sk_buff *skb) {
425 struct leaf l = {};
426 struct leaf *lp = &l;
427 lp->ptr = skb;
428 return 0;
429}""")
430 b.load_func("test", BPF.KPROBE)
431
432 def test_probe_member_expr(self):
433 b = BPF(text="""
434#include <uapi/linux/ptrace.h>
435#include <linux/netdevice.h>
436struct leaf { struct sk_buff *ptr; };
437int test(struct pt_regs *ctx, struct sk_buff *skb) {
438 struct leaf l = {};
439 struct leaf *lp = &l;
440 lp->ptr = skb;
441 return lp->ptr->priority;
442}""")
443 b.load_func("test", BPF.KPROBE)
444
Brenden Blanco80667b72015-11-12 10:17:53 -0800445 def test_unop_probe_read(self):
446 text = """
447#include <linux/blkdev.h>
448int trace_entry(struct pt_regs *ctx, struct request *req) {
Brenden Blanco35c72252016-11-23 16:26:01 -0800449 if (!(req->bio->bi_flags & 1))
Brenden Blanco80667b72015-11-12 10:17:53 -0800450 return 1;
Brenden Blanco35c72252016-11-23 16:26:01 -0800451 if (((req->bio->bi_flags)))
Brenden Blanco80667b72015-11-12 10:17:53 -0800452 return 1;
453 return 0;
454}
455"""
456 b = BPF(text=text)
457 fn = b.load_func("trace_entry", BPF.KPROBE)
458
Paul Chaignon55299112018-05-11 09:37:33 +0200459 def test_probe_read_nested_deref(self):
460 text = """
461#include <net/inet_sock.h>
462int test(struct pt_regs *ctx, struct sock *sk) {
463 struct sock *ptr1;
464 struct sock **ptr2 = &ptr1;
465 *ptr2 = sk;
466 return ((struct sock *)(*ptr2))->sk_daddr;
467}
468"""
469 b = BPF(text=text)
470 fn = b.load_func("test", BPF.KPROBE)
471
472 def test_probe_read_nested_deref2(self):
473 text = """
474#include <net/inet_sock.h>
475int test(struct pt_regs *ctx, struct sock *sk) {
476 struct sock *ptr1;
477 struct sock **ptr2 = &ptr1;
478 struct sock ***ptr3 = &ptr2;
479 *ptr2 = sk;
480 *ptr3 = ptr2;
481 return ((struct sock *)(**ptr3))->sk_daddr;
482}
483"""
484 b = BPF(text=text)
485 fn = b.load_func("test", BPF.KPROBE)
486
487 def test_probe_read_nested_deref_func(self):
488 text = """
489#include <net/inet_sock.h>
490static int subtest(struct sock ***skp) {
491 return ((struct sock *)(**skp))->sk_daddr;
492}
493int test(struct pt_regs *ctx, struct sock *sk) {
494 struct sock *ptr1;
495 struct sock **ptr2 = &ptr1;
496 struct sock ***ptr3 = &ptr2;
497 *ptr2 = sk;
498 *ptr3 = ptr2;
499 return subtest(ptr3);
500}
501"""
502 b = BPF(text=text)
503 fn = b.load_func("test", BPF.KPROBE)
504
Paul Chaignonc5ca2a62017-08-06 15:39:10 +0200505 def test_paren_probe_read(self):
506 text = """
507#include <net/inet_sock.h>
508int trace_entry(struct pt_regs *ctx, struct sock *sk) {
509 u16 sport = ((struct inet_sock *)sk)->inet_sport;
510 return sport;
511}
512"""
513 b = BPF(text=text)
514 fn = b.load_func("trace_entry", BPF.KPROBE)
515
Brenden Blancofe88e5a2015-12-06 19:58:38 -0800516 def test_complex_leaf_types(self):
517 text = """
518struct list;
519struct list {
520 struct list *selfp;
521 struct list *another_selfp;
522 struct list *selfp_array[2];
523};
524struct empty {
525};
526union emptyu {
527 struct empty *em1;
528 struct empty em2;
529 struct empty em3;
530 struct empty em4;
531};
Teng Qin7a3e5bc2017-03-29 13:39:17 -0700532BPF_ARRAY(t1, struct list, 1);
533BPF_ARRAY(t2, struct list *, 1);
534BPF_ARRAY(t3, union emptyu, 1);
Brenden Blancofe88e5a2015-12-06 19:58:38 -0800535"""
536 b = BPF(text=text)
Paul Chaignon6ceb3292017-04-01 18:23:58 +0200537 self.assertEqual(ct.sizeof(b["t3"].Leaf), 8)
Brenden Blancofe88e5a2015-12-06 19:58:38 -0800538
Brenden Blanco93588502016-01-06 08:45:42 -0800539 def test_cflags(self):
540 text = """
541#ifndef MYFLAG
542#error "MYFLAG not set as expected"
543#endif
544"""
545 b = BPF(text=text, cflags=["-DMYFLAG"])
546
Brenden Blancoab81ef22016-01-08 08:30:13 -0800547 def test_exported_maps(self):
548 b1 = BPF(text="""BPF_TABLE_PUBLIC("hash", int, int, table1, 10);""")
549 b2 = BPF(text="""BPF_TABLE("extern", int, int, table1, 10);""")
Yonghong Song96354c62018-01-28 22:39:48 -0800550 t = b2["table1"]
Brenden Blancoab81ef22016-01-08 08:30:13 -0800551
Brenden Blanco856b1772016-02-05 14:49:10 -0800552 def test_syntax_error(self):
553 with self.assertRaises(Exception):
554 b = BPF(text="""int failure(void *ctx) { if (); return 0; }""")
555
Brenden Blanco4a195222016-05-01 21:27:19 -0700556 def test_nested_union(self):
557 text = """
Teng Qin7a3e5bc2017-03-29 13:39:17 -0700558BPF_HASH(t1, struct bpf_tunnel_key, int, 1);
Brenden Blanco4a195222016-05-01 21:27:19 -0700559"""
560 b = BPF(text=text)
561 t1 = b["t1"]
562 print(t1.Key().remote_ipv4)
563
Brenden Blanco977091e2016-05-05 11:37:59 -0700564 def test_too_many_args(self):
565 text = """
566#include <uapi/linux/ptrace.h>
567int many(struct pt_regs *ctx, int a, int b, int c, int d, int e, int f, int g) {
568 return 0;
569}
570"""
571 with self.assertRaises(Exception):
572 b = BPF(text=text)
573
Huapeng Zhou98b90972016-12-17 20:50:55 -0800574 def test_call_macro_arg(self):
575 text = """
Gary Lin87218142018-02-05 17:03:44 +0800576BPF_PROG_ARRAY(jmp, 32);
Huapeng Zhou98b90972016-12-17 20:50:55 -0800577
578#define JMP_IDX_PIPE (1U << 1)
579
580enum action {
581 ACTION_PASS
582};
583
584int process(struct xdp_md *ctx) {
585 jmp.call((void *)ctx, ACTION_PASS);
586 jmp.call((void *)ctx, JMP_IDX_PIPE);
587 return XDP_PASS;
588}
589 """
590 b = BPF(text=text)
591 t = b["jmp"]
Olivier Tilmansa1962c62017-11-24 01:54:26 +0100592 self.assertEqual(len(t), 32);
Huapeng Zhou98b90972016-12-17 20:50:55 -0800593
594 def test_update_macro_arg(self):
595 text = """
Teng Qin7a3e5bc2017-03-29 13:39:17 -0700596BPF_ARRAY(act, u32, 32);
Huapeng Zhou98b90972016-12-17 20:50:55 -0800597
598#define JMP_IDX_PIPE (1U << 1)
599
600enum action {
601 ACTION_PASS
602};
603
604int process(struct xdp_md *ctx) {
605 act.increment(ACTION_PASS);
606 act.increment(JMP_IDX_PIPE);
607 return XDP_PASS;
608}
609 """
610 b = BPF(text=text)
611 t = b["act"]
Olivier Tilmansa1962c62017-11-24 01:54:26 +0100612 self.assertEqual(len(t), 32);
Huapeng Zhou98b90972016-12-17 20:50:55 -0800613
Paul Chaignon44d34732018-05-31 12:37:28 +0200614 def test_ext_ptr_maps1(self):
Paul Chaignoneae0acf2017-08-05 23:04:41 +0200615 bpf_text = """
616#include <uapi/linux/ptrace.h>
617#include <net/sock.h>
618#include <bcc/proto.h>
619
620BPF_HASH(currsock, u32, struct sock *);
621
622int trace_entry(struct pt_regs *ctx, struct sock *sk,
623 struct sockaddr *uaddr, int addr_len) {
624 u32 pid = bpf_get_current_pid_tgid();
625 currsock.update(&pid, &sk);
626 return 0;
627};
628
629int trace_exit(struct pt_regs *ctx) {
630 u32 pid = bpf_get_current_pid_tgid();
631 struct sock **skpp;
632 skpp = currsock.lookup(&pid);
633 if (skpp) {
634 struct sock *skp = *skpp;
635 return skp->__sk_common.skc_dport;
636 }
637 return 0;
638}
639 """
640 b = BPF(text=bpf_text)
641 b.load_func("trace_entry", BPF.KPROBE)
642 b.load_func("trace_exit", BPF.KPROBE)
643
Paul Chaignon44d34732018-05-31 12:37:28 +0200644 def test_ext_ptr_maps2(self):
645 bpf_text = """
646#include <uapi/linux/ptrace.h>
647#include <net/sock.h>
648#include <bcc/proto.h>
649
650BPF_HASH(currsock, u32, struct sock *);
651
652int trace_entry(struct pt_regs *ctx, struct sock *sk,
653 struct sockaddr *uaddr, int addr_len) {
654 u32 pid = bpf_get_current_pid_tgid();
655 currsock.update(&pid, &sk);
656 return 0;
657};
658
659int trace_exit(struct pt_regs *ctx) {
660 u32 pid = bpf_get_current_pid_tgid();
661 struct sock **skpp = currsock.lookup(&pid);
662 if (skpp) {
663 struct sock *skp = *skpp;
664 return skp->__sk_common.skc_dport;
665 }
666 return 0;
667}
668 """
669 b = BPF(text=bpf_text)
670 b.load_func("trace_entry", BPF.KPROBE)
671 b.load_func("trace_exit", BPF.KPROBE)
672
Paul Chaignonad2d0d92018-05-08 22:02:55 +0200673 def test_ext_ptr_maps_reverse(self):
674 bpf_text = """
675#include <uapi/linux/ptrace.h>
676#include <net/sock.h>
677#include <bcc/proto.h>
678
679BPF_HASH(currsock, u32, struct sock *);
680
681int trace_exit(struct pt_regs *ctx) {
682 u32 pid = bpf_get_current_pid_tgid();
683 struct sock **skpp;
684 skpp = currsock.lookup(&pid);
685 if (skpp) {
686 struct sock *skp = *skpp;
687 return skp->__sk_common.skc_dport;
688 }
689 return 0;
690}
691
692int trace_entry(struct pt_regs *ctx, struct sock *sk) {
693 u32 pid = bpf_get_current_pid_tgid();
694 currsock.update(&pid, &sk);
695 return 0;
696};
697 """
698 b = BPF(text=bpf_text)
699 b.load_func("trace_entry", BPF.KPROBE)
700 b.load_func("trace_exit", BPF.KPROBE)
701
702 def test_ext_ptr_maps_indirect(self):
703 bpf_text = """
704#include <uapi/linux/ptrace.h>
705#include <net/sock.h>
706#include <bcc/proto.h>
707
708BPF_HASH(currsock, u32, struct sock *);
709
710int trace_entry(struct pt_regs *ctx, struct sock *sk) {
711 u32 pid = bpf_get_current_pid_tgid();
712 struct sock **skp = &sk;
713 currsock.update(&pid, skp);
714 return 0;
715};
716
717int trace_exit(struct pt_regs *ctx) {
718 u32 pid = bpf_get_current_pid_tgid();
719 struct sock **skpp;
720 skpp = currsock.lookup(&pid);
721 if (skpp) {
722 struct sock *skp = *skpp;
723 return skp->__sk_common.skc_dport;
724 }
725 return 0;
726}
727 """
728 b = BPF(text=bpf_text)
729 b.load_func("trace_entry", BPF.KPROBE)
730 b.load_func("trace_exit", BPF.KPROBE)
731
Paul Chaignon47b74fe2017-02-23 20:06:03 +0100732 def test_bpf_dins_pkt_rewrite(self):
733 text = """
734#include <bcc/proto.h>
735int dns_test(struct __sk_buff *skb) {
736 u8 *cursor = 0;
737 struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
738 if(ethernet->type == ETH_P_IP) {
739 struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
740 ip->src = ip->dst;
741 return 0;
742 }
743 return -1;
744}
745 """
746 b = BPF(text=text)
747
Paul Chaignon719e1002017-08-06 14:33:20 +0200748 @skipUnless(kernel_version_ge(4,8), "requires kernel >= 4.8")
749 def test_ext_ptr_from_helper(self):
750 text = """
751#include <linux/sched.h>
752int test(struct pt_regs *ctx) {
753 struct task_struct *task = (struct task_struct *)bpf_get_current_task();
754 return task->prio;
755}
756"""
757 b = BPF(text=text)
758 fn = b.load_func("test", BPF.KPROBE)
759
Paul Chaignon4c6ecb42017-02-23 10:03:58 +0100760 def test_unary_operator(self):
761 text = """
762#include <linux/fs.h>
763#include <uapi/linux/ptrace.h>
764int trace_read_entry(struct pt_regs *ctx, struct file *file) {
765 return !file->f_op->read_iter;
766}
767 """
768 b = BPF(text=text)
769 b.attach_kprobe(event="__vfs_read", fn_name="trace_read_entry")
770
Paul Chaignon93419422017-03-12 14:49:01 +0100771 def test_printk_f(self):
772 text = """
773#include <uapi/linux/ptrace.h>
774int trace_entry(struct pt_regs *ctx) {
775 bpf_trace_printk("%0.2f\\n", 1);
776 return 0;
777}
778"""
779 r, w = os.pipe()
780 with redirect_stderr(to=w):
781 BPF(text=text)
782 r = os.fdopen(r)
783 output = r.read()
784 expectedWarn = "warning: only %d %u %x %ld %lu %lx %lld %llu %llx %p %s conversion specifiers allowed"
785 self.assertIn(expectedWarn, output)
786 r.close()
787
788 def test_printk_lf(self):
789 text = """
790#include <uapi/linux/ptrace.h>
791int trace_entry(struct pt_regs *ctx) {
792 bpf_trace_printk("%lf\\n", 1);
793 return 0;
794}
795"""
796 r, w = os.pipe()
797 with redirect_stderr(to=w):
798 BPF(text=text)
799 r = os.fdopen(r)
800 output = r.read()
801 expectedWarn = "warning: only %d %u %x %ld %lu %lx %lld %llu %llx %p %s conversion specifiers allowed"
802 self.assertIn(expectedWarn, output)
803 r.close()
804
805 def test_printk_2s(self):
806 text = """
807#include <uapi/linux/ptrace.h>
808int trace_entry(struct pt_regs *ctx) {
Brenden Blanco9bcad322017-04-20 17:26:53 -0700809 char s1[] = "hello", s2[] = "world";
810 bpf_trace_printk("%s %s\\n", s1, s2);
Paul Chaignon93419422017-03-12 14:49:01 +0100811 return 0;
812}
813"""
814 r, w = os.pipe()
815 with redirect_stderr(to=w):
816 BPF(text=text)
817 r = os.fdopen(r)
818 output = r.read()
819 expectedWarn = "warning: cannot use several %s conversion specifiers"
820 self.assertIn(expectedWarn, output)
821 r.close()
822
Paul Chaignon6ceb3292017-04-01 18:23:58 +0200823 def test_map_insert(self):
824 text = """
825BPF_HASH(dummy);
826void do_trace(struct pt_regs *ctx) {
827 u64 key = 0, val = 2;
828 dummy.insert(&key, &val);
829 key = 1;
830 dummy.update(&key, &val);
831}
832"""
833 b = BPF(text=text)
834 c_val = ct.c_ulong(1)
835 b["dummy"][ct.c_ulong(0)] = c_val
836 b["dummy"][ct.c_ulong(1)] = c_val
Yonghong Song83b49ad2018-04-24 10:15:24 -0700837 b.attach_kprobe(event=b.get_syscall_fnname("sync"), fn_name="do_trace")
Paul Chaignon6ceb3292017-04-01 18:23:58 +0200838 libc = ct.CDLL("libc.so.6")
839 libc.sync()
840 self.assertEqual(1, b["dummy"][ct.c_ulong(0)].value)
841 self.assertEqual(2, b["dummy"][ct.c_ulong(1)].value)
842
Paul Chaignon76f5a322017-04-14 08:33:05 +0200843 def test_prog_array_delete(self):
844 text = """
Gary Lin87218142018-02-05 17:03:44 +0800845BPF_PROG_ARRAY(dummy, 256);
Paul Chaignon76f5a322017-04-14 08:33:05 +0200846"""
847 b1 = BPF(text=text)
848 text = """
849int do_next(struct pt_regs *ctx) {
850 return 0;
851}
852"""
853 b2 = BPF(text=text)
854 fn = b2.load_func("do_next", BPF.KPROBE)
855 c_key = ct.c_int(0)
856 b1["dummy"][c_key] = ct.c_int(fn.fd)
857 b1["dummy"].__delitem__(c_key);
858 with self.assertRaises(KeyError):
859 b1["dummy"][c_key]
860
Brenden Blanco3f28e7b2017-04-20 09:33:44 -0700861 def test_invalid_noninline_call(self):
862 text = """
863int bar(void) {
864 return 0;
865}
866int foo(struct pt_regs *ctx) {
867 return bar();
868}
869"""
870 with self.assertRaises(Exception):
871 b = BPF(text=text)
Paul Chaignon76f5a322017-04-14 08:33:05 +0200872
Paul Chaignon574c3eb2017-08-22 23:00:08 +0200873 def test_incomplete_type(self):
874 text = """
875BPF_HASH(drops, struct key_t);
876struct key_t {
877 u64 location;
878};
879"""
880 with self.assertRaises(Exception):
881 b = BPF(text=text)
882
Paul Chaignonf7f873a2017-10-08 15:24:37 +0200883 def test_enumerations(self):
884 text = """
885enum b {
886 CHOICE_A,
887};
888struct a {
889 enum b test;
890};
891BPF_HASH(drops, struct a);
892 """
893 b = BPF(text=text)
894
Olivier Tilmansa1962c62017-11-24 01:54:26 +0100895 def test_int128_types(self):
896 text = """
897BPF_HASH(table1, unsigned __int128, __int128);
898"""
899 b = BPF(text=text)
900 table = b['table1']
901 self.assertEqual(ct.sizeof(table.Key), 16)
902 self.assertEqual(ct.sizeof(table.Leaf), 16)
903 table[
904 table.Key.from_buffer_copy(
905 socket.inet_pton(socket.AF_INET6, "2001:db8::"))
906 ] = table.Leaf.from_buffer_copy(struct.pack('LL', 42, 123456789))
907 for k, v in table.items():
908 self.assertEqual(v[0], 42)
909 self.assertEqual(v[1], 123456789)
910 self.assertEqual(socket.inet_ntop(socket.AF_INET6,
911 struct.pack('LL', k[0], k[1])),
912 "2001:db8::")
913
Yonghong Song538a84e2017-12-05 00:18:48 -0800914 def test_padding_types(self):
915 text = """
916struct key_t {
917 u32 f1_1; /* offset 0 */
918 struct {
919 char f2_1; /* offset 16 */
920 __int128 f2_2; /* offset 32 */
921 };
922 u8 f1_3; /* offset 48 */
923 unsigned __int128 f1_4; /* offset 64 */
Yonghong Songb32b4a52017-12-11 20:26:38 -0800924 char f1_5; /* offset 80 */
Yonghong Song538a84e2017-12-05 00:18:48 -0800925};
926struct value_t {
927 u8 src[4] __attribute__ ((aligned (8))); /* offset 0 */
928 u8 dst[4] __attribute__ ((aligned (8))); /* offset 8 */
929};
930BPF_HASH(table1, struct key_t, struct value_t);
931"""
932 b = BPF(text=text)
933 table = b['table1']
Yonghong Songb32b4a52017-12-11 20:26:38 -0800934 self.assertEqual(ct.sizeof(table.Key), 96)
935 self.assertEqual(ct.sizeof(table.Leaf), 16)
Yonghong Song538a84e2017-12-05 00:18:48 -0800936
Paul Chaignon18c8c142018-05-01 20:07:28 +0200937 @skipUnless(kernel_version_ge(4,7), "requires kernel >= 4.7")
938 def test_probe_read_tracepoint_context(self):
939 text = """
Paul Chaignona8b4cee2018-05-02 08:05:49 +0200940#include <linux/netdevice.h>
941TRACEPOINT_PROBE(skb, kfree_skb) {
942 struct sk_buff *skb = (struct sk_buff *)args->skbaddr;
943 return skb->protocol;
Paul Chaignon18c8c142018-05-01 20:07:28 +0200944}
945"""
946 b = BPF(text=text)
947
948 def test_probe_read_kprobe_ctx(self):
949 text = """
950#include <linux/sched.h>
951#include <net/inet_sock.h>
952int test(struct pt_regs *ctx) {
953 struct sock *sk;
yonghong-song24581962018-06-17 15:55:12 -0700954 sk = (struct sock *)PT_REGS_PARM1(ctx);
Paul Chaignon18c8c142018-05-01 20:07:28 +0200955 return sk->sk_dport;
956}
957"""
958 b = BPF(text=text)
959 fn = b.load_func("test", BPF.KPROBE)
960
Paul Chaignona9f96c02018-06-15 00:27:08 +0200961 def test_probe_read_ctx_array(self):
962 text = """
963#include <linux/sched.h>
964#include <net/inet_sock.h>
965int test(struct pt_regs *ctx) {
966 struct sock *newsk = (struct sock *)PT_REGS_RC(ctx);
967 return newsk->__sk_common.skc_rcv_saddr;
968}
969"""
970 b = BPF(text=text)
971 fn = b.load_func("test", BPF.KPROBE)
972
Paul Chaignon05b20832018-05-19 14:31:13 +0200973 @skipUnless(kernel_version_ge(4,7), "requires kernel >= 4.7")
974 def test_probe_read_tc_ctx(self):
975 text = """
976#include <uapi/linux/pkt_cls.h>
977#include <linux/if_ether.h>
978int test(struct __sk_buff *ctx) {
979 void* data_end = (void*)(long)ctx->data_end;
980 void* data = (void*)(long)ctx->data;
981 if (data + sizeof(struct ethhdr) > data_end)
982 return TC_ACT_SHOT;
983 struct ethhdr *eh = (struct ethhdr *)data;
984 if (eh->h_proto == 0x1)
985 return TC_ACT_SHOT;
986 return TC_ACT_OK;
987}
988"""
989 b = BPF(text=text)
990 fn = b.load_func("test", BPF.SCHED_CLS)
991
Paul Chaignonfe779f32018-06-14 03:51:55 +0200992 def test_probe_read_return(self):
993 text = """
994#define KBUILD_MODNAME "foo"
995#include <uapi/linux/ptrace.h>
996#include <linux/tcp.h>
997static inline unsigned char *my_skb_transport_header(struct sk_buff *skb) {
998 return skb->head + skb->transport_header;
999}
1000int test(struct pt_regs *ctx, struct sock *sk, struct sk_buff *skb) {
1001 struct tcphdr *th = (struct tcphdr *)my_skb_transport_header(skb);
1002 return th->seq;
1003}
1004"""
1005 b = BPF(text=text)
1006 fn = b.load_func("test", BPF.KPROBE)
1007
1008 def test_probe_read_multiple_return(self):
1009 text = """
1010#define KBUILD_MODNAME "foo"
1011#include <uapi/linux/ptrace.h>
1012#include <linux/tcp.h>
1013static inline u64 error_function() {
1014 return 0;
1015}
1016static inline unsigned char *my_skb_transport_header(struct sk_buff *skb) {
1017 if (skb)
1018 return skb->head + skb->transport_header;
1019 return (unsigned char *)error_function();
1020}
1021int test(struct pt_regs *ctx, struct sock *sk, struct sk_buff *skb) {
1022 struct tcphdr *th = (struct tcphdr *)my_skb_transport_header(skb);
1023 return th->seq;
1024}
1025"""
1026 b = BPF(text=text)
1027 fn = b.load_func("test", BPF.KPROBE)
1028
1029 def test_probe_read_return_expr(self):
1030 text = """
1031#define KBUILD_MODNAME "foo"
1032#include <uapi/linux/ptrace.h>
1033#include <linux/tcp.h>
1034static inline unsigned char *my_skb_transport_header(struct sk_buff *skb) {
1035 return skb->head + skb->transport_header;
1036}
1037int test(struct pt_regs *ctx, struct sock *sk, struct sk_buff *skb) {
1038 u32 *seq = (u32 *)my_skb_transport_header(skb) + offsetof(struct tcphdr, seq);
1039 return *seq;
1040}
1041"""
1042 b = BPF(text=text)
1043 fn = b.load_func("test", BPF.KPROBE)
1044
1045 def test_probe_read_return_call(self):
1046 text = """
1047#define KBUILD_MODNAME "foo"
1048#include <uapi/linux/ptrace.h>
1049#include <linux/tcp.h>
1050static inline struct tcphdr *my_skb_transport_header(struct sk_buff *skb) {
1051 return (struct tcphdr *)skb->head + skb->transport_header;
1052}
1053int test(struct pt_regs *ctx, struct sock *sk, struct sk_buff *skb) {
1054 return my_skb_transport_header(skb)->seq;
1055}
1056"""
1057 b = BPF(text=text)
1058 fn = b.load_func("test", BPF.KPROBE)
1059
yonghong-song24581962018-06-17 15:55:12 -07001060 def test_no_probe_read_addrof(self):
1061 text = """
1062#include <linux/sched.h>
1063#include <net/inet_sock.h>
1064static inline int test_help(__be16 *addr) {
1065 __be16 val = 0;
1066 bpf_probe_read(&val, sizeof(val), addr);
1067 return val;
1068}
1069int test(struct pt_regs *ctx) {
1070 struct sock *sk;
1071 sk = (struct sock *)PT_REGS_PARM1(ctx);
1072 return test_help(&sk->sk_dport);
1073}
1074"""
1075 b = BPF(text=text)
1076 fn = b.load_func("test", BPF.KPROBE)
1077
Paul Chaignon76f5a322017-04-14 08:33:05 +02001078
Brenden Blanco561dafc2015-06-29 11:09:00 -07001079if __name__ == "__main__":
1080 main()