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