// SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2022 Facebook */ #include #include #include #include "bpf_misc.h" #include "errno.h" char _license[] SEC("license") = "GPL"; int pid, err, val; struct sample { int pid; int seq; long value; char comm[16]; }; struct { __uint(type, BPF_MAP_TYPE_RINGBUF); } ringbuf SEC(".maps"); struct { __uint(type, BPF_MAP_TYPE_ARRAY); __uint(max_entries, 1); __type(key, __u32); __type(value, __u32); } array_map SEC(".maps"); SEC("tp/syscalls/sys_enter_nanosleep") int test_read_write(void *ctx) { char write_data[64] = "hello there, world!!"; char read_data[64] = {}, buf[64] = {}; struct bpf_dynptr ptr; int i; if (bpf_get_current_pid_tgid() >> 32 != pid) return 0; bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(write_data), 0, &ptr); /* Write data into the dynptr */ err = bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0); /* Read the data that was written into the dynptr */ err = err ?: bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0); /* Ensure the data we read matches the data we wrote */ for (i = 0; i < sizeof(read_data); i++) { if (read_data[i] != write_data[i]) { err = 1; break; } } bpf_ringbuf_discard_dynptr(&ptr, 0); return 0; } SEC("tp/syscalls/sys_enter_nanosleep") int test_data_slice(void *ctx) { __u32 key = 0, val = 235, *map_val; struct bpf_dynptr ptr; __u32 map_val_size; void *data; map_val_size = sizeof(*map_val); if (bpf_get_current_pid_tgid() >> 32 != pid) return 0; bpf_map_update_elem(&array_map, &key, &val, 0); map_val = bpf_map_lookup_elem(&array_map, &key); if (!map_val) { err = 1; return 0; } bpf_dynptr_from_mem(map_val, map_val_size, 0, &ptr); /* Try getting a data slice that is out of range */ data = bpf_dynptr_data(&ptr, map_val_size + 1, 1); if (data) { err = 2; return 0; } /* Try getting more bytes than available */ data = bpf_dynptr_data(&ptr, 0, map_val_size + 1); if (data) { err = 3; return 0; } data = bpf_dynptr_data(&ptr, 0, sizeof(__u32)); if (!data) { err = 4; return 0; } *(__u32 *)data = 999; err = bpf_probe_read_kernel(&val, sizeof(val), data); if (err) return 0; if (val != *(int *)data) err = 5; return 0; } static int ringbuf_callback(__u32 index, void *data) { struct sample *sample; struct bpf_dynptr *ptr = (struct bpf_dynptr *)data; sample = bpf_dynptr_data(ptr, 0, sizeof(*sample)); if (!sample) err = 2; else sample->pid += index; return 0; } SEC("tp/syscalls/sys_enter_nanosleep") int test_ringbuf(void *ctx) { struct bpf_dynptr ptr; struct sample *sample; if (bpf_get_current_pid_tgid() >> 32 != pid) return 0; val = 100; /* check that you can reserve a dynamic size reservation */ err = bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr); sample = err ? NULL : bpf_dynptr_data(&ptr, 0, sizeof(*sample)); if (!sample) { err = 1; goto done; } sample->pid = 10; /* Can pass dynptr to callback functions */ bpf_loop(10, ringbuf_callback, &ptr, 0); if (sample->pid != 55) err = 2; done: bpf_ringbuf_discard_dynptr(&ptr, 0); return 0; }