1#!/usr/bin/env python
2# Copyright (c) PLUMgrid, Inc.
3# Licensed under the Apache License, Version 2.0 (the "License")
4
5from bcc import BPF
6import ctypes as ct
7from unittest import main, skipUnless, TestCase
8import os
9import sys
10import socket
11import struct
12from contextlib import contextmanager
13import distutils.version
14
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)
26
27def 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
38class 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) {
46  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);
50  return 0;
51}
52"""
53        b = BPF(text=text, debug=0)
54        fn = b.load_func("handle_packet", BPF.SCHED_CLS)
55
56    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
79    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
91    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
103    def test_probe_read_whitelist1(self):
104        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
121    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
139    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
161    def test_sscanf(self):
162        text = """
163BPF_HASH(stats, int, struct { u64 a; u64 b; u64 c:36; u64 d:28; struct { u32 a; u32 b; } s; }, 10);
164int foo(void *ctx) {
165    return 0;
166}
167"""
168        b = BPF(text=text, debug=0)
169        fn = b.load_func("foo", BPF.KPROBE)
170        t = b.get_table("stats")
171        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)
175        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)
181
182    def test_sscanf_array(self):
183        text = """
184BPF_HASH(stats, int, struct { u32 a[3]; u32 b; }, 10);
185"""
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")
190        s2 = t.leaf_sprintf(t.Leaf((ct.c_uint * 3)(1,2,3), 4))
191        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
198    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
230    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
239BPF_HASH(start, struct key_t, u64, 1024);
240int 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
251    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
263    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
271    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
306    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
319    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
326    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}
334static 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) {
338    print_file_name(file);
339    return 0;
340}
341int trace_entry2(struct pt_regs *ctx, int unused, struct file *file) {
342    print_file_name2(unused, file);
343    return 0;
344}
345""")
346        fn = b.load_func("trace_entry1", BPF.KPROBE)
347        fn = b.load_func("trace_entry2", BPF.KPROBE)
348
349    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
363    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};
371int do_sys_open(struct pt_regs *ctx, const char *filename,
372        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""")
381        b.attach_kprobe(event=b.get_syscall_fnname("open"),
382                        fn_name="do_sys_open")
383
384    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};
392BPF_HASH(stats, struct key_t, u64, 1024);
393int 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
405    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;
417}""")
418
419    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_deref(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
445    def test_probe_member_expr(self):
446        b = BPF(text="""
447#include <uapi/linux/ptrace.h>
448#include <linux/netdevice.h>
449struct leaf { struct sk_buff *ptr; };
450int test(struct pt_regs *ctx, struct sk_buff *skb) {
451    struct leaf l = {};
452    struct leaf *lp = &l;
453    lp->ptr = skb;
454    return l.ptr->priority;
455}""")
456        b.load_func("test", BPF.KPROBE)
457
458    def test_unop_probe_read(self):
459        text = """
460#include <linux/blkdev.h>
461int trace_entry(struct pt_regs *ctx, struct request *req) {
462    if (!(req->bio->bi_flags & 1))
463        return 1;
464    if (((req->bio->bi_flags)))
465        return 1;
466    return 0;
467}
468"""
469        b = BPF(text=text)
470        fn = b.load_func("trace_entry", BPF.KPROBE)
471
472    def test_probe_read_nested_deref(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    *ptr2 = sk;
479    return ((struct sock *)(*ptr2))->sk_daddr;
480}
481"""
482        b = BPF(text=text)
483        fn = b.load_func("test", BPF.KPROBE)
484
485    def test_probe_read_nested_deref2(self):
486        text = """
487#include <net/inet_sock.h>
488int test(struct pt_regs *ctx, struct sock *sk) {
489    struct sock *ptr1;
490    struct sock **ptr2 = &ptr1;
491    struct sock ***ptr3 = &ptr2;
492    *ptr2 = sk;
493    *ptr3 = ptr2;
494    return ((struct sock *)(**ptr3))->sk_daddr;
495}
496"""
497        b = BPF(text=text)
498        fn = b.load_func("test", BPF.KPROBE)
499
500    def test_probe_read_nested_deref_func(self):
501        text = """
502#include <net/inet_sock.h>
503static int subtest(struct sock ***skp) {
504    return ((struct sock *)(**skp))->sk_daddr;
505}
506int test(struct pt_regs *ctx, struct sock *sk) {
507    struct sock *ptr1;
508    struct sock **ptr2 = &ptr1;
509    struct sock ***ptr3 = &ptr2;
510    *ptr2 = sk;
511    *ptr3 = ptr2;
512    return subtest(ptr3);
513}
514"""
515        b = BPF(text=text)
516        fn = b.load_func("test", BPF.KPROBE)
517
518    def test_probe_read_nested_member1(self):
519        text = """
520#include <net/inet_sock.h>
521int test(struct pt_regs *ctx, struct sock *skp) {
522    u32 *daddr = &skp->sk_daddr;
523    return *daddr;
524}
525"""
526        b = BPF(text=text)
527        fn = b.load_func("test", BPF.KPROBE)
528
529    def test_probe_read_nested_member2(self):
530        text = """
531#include <uapi/linux/ptrace.h>
532struct sock {
533    u32 **sk_daddr;
534};
535int test(struct pt_regs *ctx, struct sock *skp) {
536    u32 *daddr = *(skp->sk_daddr);
537    return *daddr;
538}
539"""
540        b = BPF(text=text)
541        fn = b.load_func("test", BPF.KPROBE)
542
543    def test_probe_read_nested_member3(self):
544        text = """
545#include <uapi/linux/ptrace.h>
546struct sock {
547    u32 *sk_daddr;
548};
549int test(struct pt_regs *ctx, struct sock *skp) {
550    return *(&skp->sk_daddr);
551}
552"""
553        b = BPF(text=text)
554        fn = b.load_func("test", BPF.KPROBE)
555
556    def test_paren_probe_read(self):
557        text = """
558#include <net/inet_sock.h>
559int trace_entry(struct pt_regs *ctx, struct sock *sk) {
560    u16 sport = ((struct inet_sock *)sk)->inet_sport;
561    return sport;
562}
563"""
564        b = BPF(text=text)
565        fn = b.load_func("trace_entry", BPF.KPROBE)
566
567    def test_complex_leaf_types(self):
568        text = """
569struct list;
570struct list {
571  struct list *selfp;
572  struct list *another_selfp;
573  struct list *selfp_array[2];
574};
575struct empty {
576};
577union emptyu {
578  struct empty *em1;
579  struct empty em2;
580  struct empty em3;
581  struct empty em4;
582};
583BPF_ARRAY(t1, struct list, 1);
584BPF_ARRAY(t2, struct list *, 1);
585BPF_ARRAY(t3, union emptyu, 1);
586"""
587        b = BPF(text=text)
588        self.assertEqual(ct.sizeof(b["t3"].Leaf), 8)
589
590    def test_cflags(self):
591        text = """
592#ifndef MYFLAG
593#error "MYFLAG not set as expected"
594#endif
595"""
596        b = BPF(text=text, cflags=["-DMYFLAG"])
597
598    def test_exported_maps(self):
599        b1 = BPF(text="""BPF_TABLE_PUBLIC("hash", int, int, table1, 10);""")
600        b2 = BPF(text="""BPF_TABLE("extern", int, int, table1, 10);""")
601        t = b2["table1"]
602
603    def test_syntax_error(self):
604        with self.assertRaises(Exception):
605            b = BPF(text="""int failure(void *ctx) { if (); return 0; }""")
606
607    def test_nested_union(self):
608        text = """
609BPF_HASH(t1, struct bpf_tunnel_key, int, 1);
610"""
611        b = BPF(text=text)
612        t1 = b["t1"]
613        print(t1.Key().remote_ipv4)
614
615    def test_too_many_args(self):
616        text = """
617#include <uapi/linux/ptrace.h>
618int many(struct pt_regs *ctx, int a, int b, int c, int d, int e, int f, int g) {
619    return 0;
620}
621"""
622        with self.assertRaises(Exception):
623            b = BPF(text=text)
624
625    def test_call_macro_arg(self):
626        text = """
627BPF_PROG_ARRAY(jmp, 32);
628
629#define JMP_IDX_PIPE (1U << 1)
630
631enum action {
632    ACTION_PASS
633};
634
635int process(struct xdp_md *ctx) {
636    jmp.call((void *)ctx, ACTION_PASS);
637    jmp.call((void *)ctx, JMP_IDX_PIPE);
638    return XDP_PASS;
639}
640        """
641        b = BPF(text=text)
642        t = b["jmp"]
643        self.assertEqual(len(t), 32);
644
645    def test_update_macro_arg(self):
646        text = """
647BPF_ARRAY(act, u32, 32);
648
649#define JMP_IDX_PIPE (1U << 1)
650
651enum action {
652    ACTION_PASS
653};
654
655int process(struct xdp_md *ctx) {
656    act.increment(ACTION_PASS);
657    act.increment(JMP_IDX_PIPE);
658    return XDP_PASS;
659}
660        """
661        b = BPF(text=text)
662        t = b["act"]
663        self.assertEqual(len(t), 32);
664
665    def test_ext_ptr_maps1(self):
666        bpf_text = """
667#include <uapi/linux/ptrace.h>
668#include <net/sock.h>
669#include <bcc/proto.h>
670
671BPF_HASH(currsock, u32, struct sock *);
672
673int trace_entry(struct pt_regs *ctx, struct sock *sk,
674    struct sockaddr *uaddr, int addr_len) {
675    u32 pid = bpf_get_current_pid_tgid();
676    currsock.update(&pid, &sk);
677    return 0;
678};
679
680int trace_exit(struct pt_regs *ctx) {
681    u32 pid = bpf_get_current_pid_tgid();
682    struct sock **skpp;
683    skpp = currsock.lookup(&pid);
684    if (skpp) {
685        struct sock *skp = *skpp;
686        return skp->__sk_common.skc_dport;
687    }
688    return 0;
689}
690        """
691        b = BPF(text=bpf_text)
692        b.load_func("trace_entry", BPF.KPROBE)
693        b.load_func("trace_exit", BPF.KPROBE)
694
695    def test_ext_ptr_maps2(self):
696        bpf_text = """
697#include <uapi/linux/ptrace.h>
698#include <net/sock.h>
699#include <bcc/proto.h>
700
701BPF_HASH(currsock, u32, struct sock *);
702
703int trace_entry(struct pt_regs *ctx, struct sock *sk,
704    struct sockaddr *uaddr, int addr_len) {
705    u32 pid = bpf_get_current_pid_tgid();
706    currsock.update(&pid, &sk);
707    return 0;
708};
709
710int trace_exit(struct pt_regs *ctx) {
711    u32 pid = bpf_get_current_pid_tgid();
712    struct sock **skpp = currsock.lookup(&pid);
713    if (skpp) {
714        struct sock *skp = *skpp;
715        return skp->__sk_common.skc_dport;
716    }
717    return 0;
718}
719        """
720        b = BPF(text=bpf_text)
721        b.load_func("trace_entry", BPF.KPROBE)
722        b.load_func("trace_exit", BPF.KPROBE)
723
724    def test_ext_ptr_maps_reverse(self):
725        bpf_text = """
726#include <uapi/linux/ptrace.h>
727#include <net/sock.h>
728#include <bcc/proto.h>
729
730BPF_HASH(currsock, u32, struct sock *);
731
732int trace_exit(struct pt_regs *ctx) {
733    u32 pid = bpf_get_current_pid_tgid();
734    struct sock **skpp;
735    skpp = currsock.lookup(&pid);
736    if (skpp) {
737        struct sock *skp = *skpp;
738        return skp->__sk_common.skc_dport;
739    }
740    return 0;
741}
742
743int trace_entry(struct pt_regs *ctx, struct sock *sk) {
744    u32 pid = bpf_get_current_pid_tgid();
745    currsock.update(&pid, &sk);
746    return 0;
747};
748        """
749        b = BPF(text=bpf_text)
750        b.load_func("trace_entry", BPF.KPROBE)
751        b.load_func("trace_exit", BPF.KPROBE)
752
753    def test_ext_ptr_maps_indirect(self):
754        bpf_text = """
755#include <uapi/linux/ptrace.h>
756#include <net/sock.h>
757#include <bcc/proto.h>
758
759BPF_HASH(currsock, u32, struct sock *);
760
761int trace_entry(struct pt_regs *ctx, struct sock *sk) {
762    u32 pid = bpf_get_current_pid_tgid();
763    struct sock **skp = &sk;
764    currsock.update(&pid, skp);
765    return 0;
766};
767
768int trace_exit(struct pt_regs *ctx) {
769    u32 pid = bpf_get_current_pid_tgid();
770    struct sock **skpp;
771    skpp = currsock.lookup(&pid);
772    if (skpp) {
773        struct sock *skp = *skpp;
774        return skp->__sk_common.skc_dport;
775    }
776    return 0;
777}
778        """
779        b = BPF(text=bpf_text)
780        b.load_func("trace_entry", BPF.KPROBE)
781        b.load_func("trace_exit", BPF.KPROBE)
782
783    def test_bpf_dins_pkt_rewrite(self):
784        text = """
785#include <bcc/proto.h>
786int dns_test(struct __sk_buff *skb) {
787    u8 *cursor = 0;
788    struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
789    if(ethernet->type == ETH_P_IP) {
790        struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
791        ip->src = ip->dst;
792        return 0;
793    }
794    return -1;
795}
796        """
797        b = BPF(text=text)
798
799    @skipUnless(kernel_version_ge(4,8), "requires kernel >= 4.8")
800    def test_ext_ptr_from_helper(self):
801        text = """
802#include <linux/sched.h>
803int test(struct pt_regs *ctx) {
804    struct task_struct *task = (struct task_struct *)bpf_get_current_task();
805    return task->prio;
806}
807"""
808        b = BPF(text=text)
809        fn = b.load_func("test", BPF.KPROBE)
810
811    def test_unary_operator(self):
812        text = """
813#include <linux/fs.h>
814#include <uapi/linux/ptrace.h>
815int trace_read_entry(struct pt_regs *ctx, struct file *file) {
816    return !file->f_op->read_iter;
817}
818        """
819        b = BPF(text=text)
820        b.attach_kprobe(event="__vfs_read", fn_name="trace_read_entry")
821
822    def test_printk_f(self):
823        text = """
824#include <uapi/linux/ptrace.h>
825int trace_entry(struct pt_regs *ctx) {
826  bpf_trace_printk("%0.2f\\n", 1);
827  return 0;
828}
829"""
830        r, w = os.pipe()
831        with redirect_stderr(to=w):
832            BPF(text=text)
833        r = os.fdopen(r)
834        output = r.read()
835        expectedWarn = "warning: only %d %u %x %ld %lu %lx %lld %llu %llx %p %s conversion specifiers allowed"
836        self.assertIn(expectedWarn, output)
837        r.close()
838
839    def test_printk_lf(self):
840        text = """
841#include <uapi/linux/ptrace.h>
842int trace_entry(struct pt_regs *ctx) {
843  bpf_trace_printk("%lf\\n", 1);
844  return 0;
845}
846"""
847        r, w = os.pipe()
848        with redirect_stderr(to=w):
849            BPF(text=text)
850        r = os.fdopen(r)
851        output = r.read()
852        expectedWarn = "warning: only %d %u %x %ld %lu %lx %lld %llu %llx %p %s conversion specifiers allowed"
853        self.assertIn(expectedWarn, output)
854        r.close()
855
856    def test_printk_2s(self):
857        text = """
858#include <uapi/linux/ptrace.h>
859int trace_entry(struct pt_regs *ctx) {
860  char s1[] = "hello", s2[] = "world";
861  bpf_trace_printk("%s %s\\n", s1, s2);
862  return 0;
863}
864"""
865        r, w = os.pipe()
866        with redirect_stderr(to=w):
867            BPF(text=text)
868        r = os.fdopen(r)
869        output = r.read()
870        expectedWarn = "warning: cannot use several %s conversion specifiers"
871        self.assertIn(expectedWarn, output)
872        r.close()
873
874    def test_map_insert(self):
875        text = """
876BPF_HASH(dummy);
877void do_trace(struct pt_regs *ctx) {
878    u64 key = 0, val = 2;
879    dummy.insert(&key, &val);
880    key = 1;
881    dummy.update(&key, &val);
882}
883"""
884        b = BPF(text=text)
885        c_val = ct.c_ulong(1)
886        b["dummy"][ct.c_ulong(0)] = c_val
887        b["dummy"][ct.c_ulong(1)] = c_val
888        b.attach_kprobe(event=b.get_syscall_fnname("sync"), fn_name="do_trace")
889        libc = ct.CDLL("libc.so.6")
890        libc.sync()
891        self.assertEqual(1, b["dummy"][ct.c_ulong(0)].value)
892        self.assertEqual(2, b["dummy"][ct.c_ulong(1)].value)
893
894    def test_prog_array_delete(self):
895        text = """
896BPF_PROG_ARRAY(dummy, 256);
897"""
898        b1 = BPF(text=text)
899        text = """
900int do_next(struct pt_regs *ctx) {
901    return 0;
902}
903"""
904        b2 = BPF(text=text)
905        fn = b2.load_func("do_next", BPF.KPROBE)
906        c_key = ct.c_int(0)
907        b1["dummy"][c_key] = ct.c_int(fn.fd)
908        b1["dummy"].__delitem__(c_key);
909        with self.assertRaises(KeyError):
910            b1["dummy"][c_key]
911
912    def test_invalid_noninline_call(self):
913        text = """
914int bar(void) {
915    return 0;
916}
917int foo(struct pt_regs *ctx) {
918    return bar();
919}
920"""
921        with self.assertRaises(Exception):
922            b = BPF(text=text)
923
924    def test_incomplete_type(self):
925        text = """
926BPF_HASH(drops, struct key_t);
927struct key_t {
928    u64 location;
929};
930"""
931        with self.assertRaises(Exception):
932            b = BPF(text=text)
933
934    def test_enumerations(self):
935        text = """
936enum b {
937    CHOICE_A,
938};
939struct a {
940    enum b test;
941};
942BPF_HASH(drops, struct a);
943        """
944        b = BPF(text=text)
945
946    def test_int128_types(self):
947        text = """
948BPF_HASH(table1, unsigned __int128, __int128);
949"""
950        b = BPF(text=text)
951        table = b['table1']
952        self.assertEqual(ct.sizeof(table.Key), 16)
953        self.assertEqual(ct.sizeof(table.Leaf), 16)
954        table[
955            table.Key.from_buffer_copy(
956                socket.inet_pton(socket.AF_INET6, "2001:db8::"))
957        ] = table.Leaf.from_buffer_copy(struct.pack('LL', 42, 123456789))
958        for k, v in table.items():
959            self.assertEqual(v[0], 42)
960            self.assertEqual(v[1], 123456789)
961            self.assertEqual(socket.inet_ntop(socket.AF_INET6,
962                                              struct.pack('LL', k[0], k[1])),
963                             "2001:db8::")
964
965    def test_padding_types(self):
966        text = """
967struct key_t {
968  u32 f1_1;               /* offset 0 */
969  struct {
970    char f2_1;            /* offset 16 */
971    __int128 f2_2;        /* offset 32 */
972  };
973  u8 f1_3;                /* offset 48 */
974  unsigned __int128 f1_4; /* offset 64 */
975  char f1_5;              /* offset 80 */
976};
977struct value_t {
978  u8 src[4] __attribute__ ((aligned (8))); /* offset 0 */
979  u8 dst[4] __attribute__ ((aligned (8))); /* offset 8 */
980};
981BPF_HASH(table1, struct key_t, struct value_t);
982"""
983        b = BPF(text=text)
984        table = b['table1']
985        self.assertEqual(ct.sizeof(table.Key), 96)
986        self.assertEqual(ct.sizeof(table.Leaf), 16)
987
988    @skipUnless(kernel_version_ge(4,7), "requires kernel >= 4.7")
989    def test_probe_read_tracepoint_context(self):
990        text = """
991#include <linux/netdevice.h>
992TRACEPOINT_PROBE(skb, kfree_skb) {
993    struct sk_buff *skb = (struct sk_buff *)args->skbaddr;
994    return skb->protocol;
995}
996"""
997        b = BPF(text=text)
998
999    def test_probe_read_kprobe_ctx(self):
1000        text = """
1001#include <linux/sched.h>
1002#include <net/inet_sock.h>
1003int test(struct pt_regs *ctx) {
1004    struct sock *sk;
1005    sk = (struct sock *)PT_REGS_PARM1(ctx);
1006    return sk->sk_dport;
1007}
1008"""
1009        b = BPF(text=text)
1010        fn = b.load_func("test", BPF.KPROBE)
1011
1012    def test_probe_read_ctx_array(self):
1013        text = """
1014#include <linux/sched.h>
1015#include <net/inet_sock.h>
1016int test(struct pt_regs *ctx) {
1017    struct sock *newsk = (struct sock *)PT_REGS_RC(ctx);
1018    return newsk->__sk_common.skc_rcv_saddr;
1019}
1020"""
1021        b = BPF(text=text)
1022        fn = b.load_func("test", BPF.KPROBE)
1023
1024    @skipUnless(kernel_version_ge(4,7), "requires kernel >= 4.7")
1025    def test_probe_read_tc_ctx(self):
1026        text = """
1027#include <uapi/linux/pkt_cls.h>
1028#include <linux/if_ether.h>
1029int test(struct __sk_buff *ctx) {
1030    void* data_end = (void*)(long)ctx->data_end;
1031    void* data = (void*)(long)ctx->data;
1032    if (data + sizeof(struct ethhdr) > data_end)
1033        return TC_ACT_SHOT;
1034    struct ethhdr *eh = (struct ethhdr *)data;
1035    if (eh->h_proto == 0x1)
1036        return TC_ACT_SHOT;
1037    return TC_ACT_OK;
1038}
1039"""
1040        b = BPF(text=text)
1041        fn = b.load_func("test", BPF.SCHED_CLS)
1042
1043    def test_probe_read_return(self):
1044        text = """
1045#define KBUILD_MODNAME "foo"
1046#include <uapi/linux/ptrace.h>
1047#include <linux/tcp.h>
1048static inline unsigned char *my_skb_transport_header(struct sk_buff *skb) {
1049    return skb->head + skb->transport_header;
1050}
1051int test(struct pt_regs *ctx, struct sock *sk, struct sk_buff *skb) {
1052    struct tcphdr *th = (struct tcphdr *)my_skb_transport_header(skb);
1053    return th->seq;
1054}
1055"""
1056        b = BPF(text=text)
1057        fn = b.load_func("test", BPF.KPROBE)
1058
1059    def test_probe_read_multiple_return(self):
1060        text = """
1061#define KBUILD_MODNAME "foo"
1062#include <uapi/linux/ptrace.h>
1063#include <linux/tcp.h>
1064static inline u64 error_function() {
1065    return 0;
1066}
1067static inline unsigned char *my_skb_transport_header(struct sk_buff *skb) {
1068    if (skb)
1069        return skb->head + skb->transport_header;
1070    return (unsigned char *)error_function();
1071}
1072int test(struct pt_regs *ctx, struct sock *sk, struct sk_buff *skb) {
1073    struct tcphdr *th = (struct tcphdr *)my_skb_transport_header(skb);
1074    return th->seq;
1075}
1076"""
1077        b = BPF(text=text)
1078        fn = b.load_func("test", BPF.KPROBE)
1079
1080    def test_probe_read_return_expr(self):
1081        text = """
1082#define KBUILD_MODNAME "foo"
1083#include <uapi/linux/ptrace.h>
1084#include <linux/tcp.h>
1085static inline unsigned char *my_skb_transport_header(struct sk_buff *skb) {
1086    return skb->head + skb->transport_header;
1087}
1088int test(struct pt_regs *ctx, struct sock *sk, struct sk_buff *skb) {
1089    u32 *seq = (u32 *)my_skb_transport_header(skb) + offsetof(struct tcphdr, seq);
1090    return *seq;
1091}
1092"""
1093        b = BPF(text=text)
1094        fn = b.load_func("test", BPF.KPROBE)
1095
1096    def test_probe_read_return_call(self):
1097        text = """
1098#define KBUILD_MODNAME "foo"
1099#include <uapi/linux/ptrace.h>
1100#include <linux/tcp.h>
1101static inline struct tcphdr *my_skb_transport_header(struct sk_buff *skb) {
1102    return (struct tcphdr *)skb->head + skb->transport_header;
1103}
1104int test(struct pt_regs *ctx, struct sock *sk, struct sk_buff *skb) {
1105    return my_skb_transport_header(skb)->seq;
1106}
1107"""
1108        b = BPF(text=text)
1109        fn = b.load_func("test", BPF.KPROBE)
1110
1111    def test_no_probe_read_addrof(self):
1112        text = """
1113#include <linux/sched.h>
1114#include <net/inet_sock.h>
1115static inline int test_help(__be16 *addr) {
1116    __be16 val = 0;
1117    bpf_probe_read(&val, sizeof(val), addr);
1118    return val;
1119}
1120int test(struct pt_regs *ctx) {
1121    struct sock *sk;
1122    sk = (struct sock *)PT_REGS_PARM1(ctx);
1123    return test_help(&sk->sk_dport);
1124}
1125"""
1126        b = BPF(text=text)
1127        fn = b.load_func("test", BPF.KPROBE)
1128
1129    def test_probe_read_array_accesses1(self):
1130        text = """
1131#include <linux/ptrace.h>
1132#include <linux/dcache.h>
1133int test(struct pt_regs *ctx, const struct qstr *name) {
1134    return name->name[1];
1135}
1136"""
1137        b = BPF(text=text)
1138        fn = b.load_func("test", BPF.KPROBE)
1139
1140    def test_probe_read_array_accesses2(self):
1141        text = """
1142#include <linux/ptrace.h>
1143#include <linux/dcache.h>
1144int test(struct pt_regs *ctx, const struct qstr *name) {
1145    return name->name  [ 1];
1146}
1147"""
1148        b = BPF(text=text)
1149        fn = b.load_func("test", BPF.KPROBE)
1150
1151    def test_probe_read_array_accesses3(self):
1152        text = """
1153#include <linux/ptrace.h>
1154#include <linux/dcache.h>
1155int test(struct pt_regs *ctx, const struct qstr *name) {
1156    return (name->name)[1];
1157}
1158"""
1159        b = BPF(text=text)
1160        fn = b.load_func("test", BPF.KPROBE)
1161
1162    def test_probe_read_array_accesses4(self):
1163        text = """
1164#include <linux/ptrace.h>
1165int test(struct pt_regs *ctx, char *name) {
1166    return name[1];
1167}
1168"""
1169        b = BPF(text=text)
1170        fn = b.load_func("test", BPF.KPROBE)
1171
1172    def test_probe_read_array_accesses5(self):
1173        text = """
1174#include <linux/ptrace.h>
1175int test(struct pt_regs *ctx, char **name) {
1176    return (*name)[1];
1177}
1178"""
1179        b = BPF(text=text)
1180        fn = b.load_func("test", BPF.KPROBE)
1181
1182    def test_probe_read_array_accesses6(self):
1183        text = """
1184#include <linux/ptrace.h>
1185struct test_t {
1186    int tab[5];
1187};
1188int test(struct pt_regs *ctx, struct test_t *t) {
1189    return *(&t->tab[1]);
1190}
1191"""
1192        b = BPF(text=text)
1193        fn = b.load_func("test", BPF.KPROBE)
1194
1195    def test_probe_read_array_accesses7(self):
1196        text = """
1197#include <net/inet_sock.h>
1198int test(struct pt_regs *ctx, struct sock *sk) {
1199    return sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32[0];
1200}
1201"""
1202        b = BPF(text=text)
1203        fn = b.load_func("test", BPF.KPROBE)
1204
1205    def test_probe_read_array_accesses8(self):
1206        text = """
1207#include <linux/mm_types.h>
1208int test(struct pt_regs *ctx, struct mm_struct *mm) {
1209    return mm->rss_stat.count[MM_ANONPAGES].counter;
1210}
1211"""
1212        b = BPF(text=text)
1213        fn = b.load_func("test", BPF.KPROBE)
1214
1215    def test_arbitrary_increment_simple(self):
1216        b = BPF(text=b"""
1217#include <uapi/linux/ptrace.h>
1218struct bpf_map;
1219BPF_HASH(map);
1220int map_delete(struct pt_regs *ctx, struct bpf_map *bpfmap, u64 *k) {
1221    map.increment(42, 10);
1222    return 0;
1223}
1224""")
1225        b.attach_kprobe(event=b"htab_map_delete_elem", fn_name=b"map_delete")
1226        b.cleanup()
1227
1228    @skipUnless(kernel_version_ge(4,7), "requires kernel >= 4.7")
1229    def test_packed_structure(self):
1230        b = BPF(text=b"""
1231struct test {
1232    u16 a;
1233    u32 b;
1234} __packed;
1235BPF_TABLE("hash", u32, struct test, testing, 2);
1236TRACEPOINT_PROBE(kmem, kmalloc) {
1237    u32 key = 0;
1238    struct test info, *entry;
1239    entry = testing.lookup(&key);
1240    if (entry == NULL) {
1241        info.a = 10;
1242        info.b = 20;
1243        testing.update(&key, &info);
1244    }
1245    return 0;
1246}
1247""")
1248        if len(b["testing"].items()):
1249            st = b["testing"][ct.c_uint(0)]
1250            self.assertEqual(st.a, 10)
1251            self.assertEqual(st.b, 20)
1252
1253if __name__ == "__main__":
1254    main()
1255