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 "bpf_kfuncs.h" 9 #include "errno.h" 10 11 char _license[] SEC("license") = "GPL"; 12 13 int pid, err, val; 14 15 struct sample { 16 int pid; 17 int seq; 18 long value; 19 char comm[16]; 20 }; 21 22 struct { 23 __uint(type, BPF_MAP_TYPE_RINGBUF); 24 __uint(max_entries, 4096); 25 } ringbuf SEC(".maps"); 26 27 struct { 28 __uint(type, BPF_MAP_TYPE_ARRAY); 29 __uint(max_entries, 1); 30 __type(key, __u32); 31 __type(value, __u32); 32 } array_map SEC(".maps"); 33 34 SEC("?tp/syscalls/sys_enter_nanosleep") 35 int test_read_write(void *ctx) 36 { 37 char write_data[64] = "hello there, world!!"; 38 char read_data[64] = {}; 39 struct bpf_dynptr ptr; 40 int i; 41 42 if (bpf_get_current_pid_tgid() >> 32 != pid) 43 return 0; 44 45 bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(write_data), 0, &ptr); 46 47 /* Write data into the dynptr */ 48 err = bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0); 49 50 /* Read the data that was written into the dynptr */ 51 err = err ?: bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0); 52 53 /* Ensure the data we read matches the data we wrote */ 54 for (i = 0; i < sizeof(read_data); i++) { 55 if (read_data[i] != write_data[i]) { 56 err = 1; 57 break; 58 } 59 } 60 61 bpf_ringbuf_discard_dynptr(&ptr, 0); 62 return 0; 63 } 64 65 SEC("?tp/syscalls/sys_enter_nanosleep") 66 int test_dynptr_data(void *ctx) 67 { 68 __u32 key = 0, val = 235, *map_val; 69 struct bpf_dynptr ptr; 70 __u32 map_val_size; 71 void *data; 72 73 map_val_size = sizeof(*map_val); 74 75 if (bpf_get_current_pid_tgid() >> 32 != pid) 76 return 0; 77 78 bpf_map_update_elem(&array_map, &key, &val, 0); 79 80 map_val = bpf_map_lookup_elem(&array_map, &key); 81 if (!map_val) { 82 err = 1; 83 return 0; 84 } 85 86 bpf_dynptr_from_mem(map_val, map_val_size, 0, &ptr); 87 88 /* Try getting a data slice that is out of range */ 89 data = bpf_dynptr_data(&ptr, map_val_size + 1, 1); 90 if (data) { 91 err = 2; 92 return 0; 93 } 94 95 /* Try getting more bytes than available */ 96 data = bpf_dynptr_data(&ptr, 0, map_val_size + 1); 97 if (data) { 98 err = 3; 99 return 0; 100 } 101 102 data = bpf_dynptr_data(&ptr, 0, sizeof(__u32)); 103 if (!data) { 104 err = 4; 105 return 0; 106 } 107 108 *(__u32 *)data = 999; 109 110 err = bpf_probe_read_kernel(&val, sizeof(val), data); 111 if (err) 112 return 0; 113 114 if (val != *(int *)data) 115 err = 5; 116 117 return 0; 118 } 119 120 static int ringbuf_callback(__u32 index, void *data) 121 { 122 struct sample *sample; 123 124 struct bpf_dynptr *ptr = (struct bpf_dynptr *)data; 125 126 sample = bpf_dynptr_data(ptr, 0, sizeof(*sample)); 127 if (!sample) 128 err = 2; 129 else 130 sample->pid += index; 131 132 return 0; 133 } 134 135 SEC("?tp/syscalls/sys_enter_nanosleep") 136 int test_ringbuf(void *ctx) 137 { 138 struct bpf_dynptr ptr; 139 struct sample *sample; 140 141 if (bpf_get_current_pid_tgid() >> 32 != pid) 142 return 0; 143 144 val = 100; 145 146 /* check that you can reserve a dynamic size reservation */ 147 err = bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); 148 149 sample = err ? NULL : bpf_dynptr_data(&ptr, 0, sizeof(*sample)); 150 if (!sample) { 151 err = 1; 152 goto done; 153 } 154 155 sample->pid = 10; 156 157 /* Can pass dynptr to callback functions */ 158 bpf_loop(10, ringbuf_callback, &ptr, 0); 159 160 if (sample->pid != 55) 161 err = 2; 162 163 done: 164 bpf_ringbuf_discard_dynptr(&ptr, 0); 165 return 0; 166 } 167 168 SEC("?cgroup_skb/egress") 169 int test_skb_readonly(struct __sk_buff *skb) 170 { 171 __u8 write_data[2] = {1, 2}; 172 struct bpf_dynptr ptr; 173 int ret; 174 175 if (bpf_dynptr_from_skb(skb, 0, &ptr)) { 176 err = 1; 177 return 1; 178 } 179 180 /* since cgroup skbs are read only, writes should fail */ 181 ret = bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0); 182 if (ret != -EINVAL) { 183 err = 2; 184 return 1; 185 } 186 187 return 1; 188 } 189 190 SEC("?cgroup_skb/egress") 191 int test_dynptr_skb_data(struct __sk_buff *skb) 192 { 193 struct bpf_dynptr ptr; 194 __u64 *data; 195 196 if (bpf_dynptr_from_skb(skb, 0, &ptr)) { 197 err = 1; 198 return 1; 199 } 200 201 /* This should return NULL. Must use bpf_dynptr_slice API */ 202 data = bpf_dynptr_data(&ptr, 0, 1); 203 if (data) { 204 err = 2; 205 return 1; 206 } 207 208 return 1; 209 } 210