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