1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2022 Facebook */ 3 4 #include <string.h> 5 #include <linux/bpf.h> 6 #include <bpf/bpf_helpers.h> 7 #include "bpf_misc.h" 8 #include "errno.h" 9 10 char _license[] SEC("license") = "GPL"; 11 12 int pid, err, val; 13 14 struct sample { 15 int pid; 16 int seq; 17 long value; 18 char comm[16]; 19 }; 20 21 struct { 22 __uint(type, BPF_MAP_TYPE_RINGBUF); 23 } ringbuf SEC(".maps"); 24 25 struct { 26 __uint(type, BPF_MAP_TYPE_ARRAY); 27 __uint(max_entries, 1); 28 __type(key, __u32); 29 __type(value, __u32); 30 } array_map SEC(".maps"); 31 32 SEC("tp/syscalls/sys_enter_nanosleep") 33 int test_read_write(void *ctx) 34 { 35 char write_data[64] = "hello there, world!!"; 36 char read_data[64] = {}, buf[64] = {}; 37 struct bpf_dynptr ptr; 38 int i; 39 40 if (bpf_get_current_pid_tgid() >> 32 != pid) 41 return 0; 42 43 bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(write_data), 0, &ptr); 44 45 /* Write data into the dynptr */ 46 err = bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0); 47 48 /* Read the data that was written into the dynptr */ 49 err = err ?: bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0); 50 51 /* Ensure the data we read matches the data we wrote */ 52 for (i = 0; i < sizeof(read_data); i++) { 53 if (read_data[i] != write_data[i]) { 54 err = 1; 55 break; 56 } 57 } 58 59 bpf_ringbuf_discard_dynptr(&ptr, 0); 60 return 0; 61 } 62 63 SEC("tp/syscalls/sys_enter_nanosleep") 64 int test_data_slice(void *ctx) 65 { 66 __u32 key = 0, val = 235, *map_val; 67 struct bpf_dynptr ptr; 68 __u32 map_val_size; 69 void *data; 70 71 map_val_size = sizeof(*map_val); 72 73 if (bpf_get_current_pid_tgid() >> 32 != pid) 74 return 0; 75 76 bpf_map_update_elem(&array_map, &key, &val, 0); 77 78 map_val = bpf_map_lookup_elem(&array_map, &key); 79 if (!map_val) { 80 err = 1; 81 return 0; 82 } 83 84 bpf_dynptr_from_mem(map_val, map_val_size, 0, &ptr); 85 86 /* Try getting a data slice that is out of range */ 87 data = bpf_dynptr_data(&ptr, map_val_size + 1, 1); 88 if (data) { 89 err = 2; 90 return 0; 91 } 92 93 /* Try getting more bytes than available */ 94 data = bpf_dynptr_data(&ptr, 0, map_val_size + 1); 95 if (data) { 96 err = 3; 97 return 0; 98 } 99 100 data = bpf_dynptr_data(&ptr, 0, sizeof(__u32)); 101 if (!data) { 102 err = 4; 103 return 0; 104 } 105 106 *(__u32 *)data = 999; 107 108 err = bpf_probe_read_kernel(&val, sizeof(val), data); 109 if (err) 110 return 0; 111 112 if (val != *(int *)data) 113 err = 5; 114 115 return 0; 116 } 117 118 static int ringbuf_callback(__u32 index, void *data) 119 { 120 struct sample *sample; 121 122 struct bpf_dynptr *ptr = (struct bpf_dynptr *)data; 123 124 sample = bpf_dynptr_data(ptr, 0, sizeof(*sample)); 125 if (!sample) 126 err = 2; 127 else 128 sample->pid += index; 129 130 return 0; 131 } 132 133 SEC("tp/syscalls/sys_enter_nanosleep") 134 int test_ringbuf(void *ctx) 135 { 136 struct bpf_dynptr ptr; 137 struct sample *sample; 138 139 if (bpf_get_current_pid_tgid() >> 32 != pid) 140 return 0; 141 142 val = 100; 143 144 /* check that you can reserve a dynamic size reservation */ 145 err = bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); 146 147 sample = err ? NULL : bpf_dynptr_data(&ptr, 0, sizeof(*sample)); 148 if (!sample) { 149 err = 1; 150 goto done; 151 } 152 153 sample->pid = 10; 154 155 /* Can pass dynptr to callback functions */ 156 bpf_loop(10, ringbuf_callback, &ptr, 0); 157 158 if (sample->pid != 55) 159 err = 2; 160 161 done: 162 bpf_ringbuf_discard_dynptr(&ptr, 0); 163 return 0; 164 } 165