brintos

brintos / linux-shallow public Read only

0
0
Text · 10.5 KiB · bfcc856 Raw
570 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2022 Facebook */3 4#include <string.h>5#include <stdbool.h>6#include <linux/bpf.h>7#include <bpf/bpf_helpers.h>8#include <bpf/bpf_tracing.h>9#include "bpf_misc.h"10#include "bpf_kfuncs.h"11#include "errno.h"12 13char _license[] SEC("license") = "GPL";14 15int pid, err, val;16 17struct sample {18	int pid;19	int seq;20	long value;21	char comm[16];22};23 24struct {25	__uint(type, BPF_MAP_TYPE_RINGBUF);26	__uint(max_entries, 4096);27} ringbuf SEC(".maps");28 29struct {30	__uint(type, BPF_MAP_TYPE_ARRAY);31	__uint(max_entries, 1);32	__type(key, __u32);33	__type(value, __u32);34} array_map SEC(".maps");35 36SEC("?tp/syscalls/sys_enter_nanosleep")37int test_read_write(void *ctx)38{39	char write_data[64] = "hello there, world!!";40	char read_data[64] = {};41	struct bpf_dynptr ptr;42	int i;43 44	if (bpf_get_current_pid_tgid() >> 32 != pid)45		return 0;46 47	bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(write_data), 0, &ptr);48 49	/* Write data into the dynptr */50	err = bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0);51 52	/* Read the data that was written into the dynptr */53	err = err ?: bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);54 55	/* Ensure the data we read matches the data we wrote */56	for (i = 0; i < sizeof(read_data); i++) {57		if (read_data[i] != write_data[i]) {58			err = 1;59			break;60		}61	}62 63	bpf_ringbuf_discard_dynptr(&ptr, 0);64	return 0;65}66 67SEC("?tp/syscalls/sys_enter_nanosleep")68int test_dynptr_data(void *ctx)69{70	__u32 key = 0, val = 235, *map_val;71	struct bpf_dynptr ptr;72	__u32 map_val_size;73	void *data;74 75	map_val_size = sizeof(*map_val);76 77	if (bpf_get_current_pid_tgid() >> 32 != pid)78		return 0;79 80	bpf_map_update_elem(&array_map, &key, &val, 0);81 82	map_val = bpf_map_lookup_elem(&array_map, &key);83	if (!map_val) {84		err = 1;85		return 0;86	}87 88	bpf_dynptr_from_mem(map_val, map_val_size, 0, &ptr);89 90	/* Try getting a data slice that is out of range */91	data = bpf_dynptr_data(&ptr, map_val_size + 1, 1);92	if (data) {93		err = 2;94		return 0;95	}96 97	/* Try getting more bytes than available */98	data = bpf_dynptr_data(&ptr, 0, map_val_size + 1);99	if (data) {100		err = 3;101		return 0;102	}103 104	data = bpf_dynptr_data(&ptr, 0, sizeof(__u32));105	if (!data) {106		err = 4;107		return 0;108	}109 110	*(__u32 *)data = 999;111 112	err = bpf_probe_read_kernel(&val, sizeof(val), data);113	if (err)114		return 0;115 116	if (val != *(int *)data)117		err = 5;118 119	return 0;120}121 122static int ringbuf_callback(__u32 index, void *data)123{124	struct sample *sample;125 126	struct bpf_dynptr *ptr = (struct bpf_dynptr *)data;127 128	sample = bpf_dynptr_data(ptr, 0, sizeof(*sample));129	if (!sample)130		err = 2;131	else132		sample->pid += index;133 134	return 0;135}136 137SEC("?tp/syscalls/sys_enter_nanosleep")138int test_ringbuf(void *ctx)139{140	struct bpf_dynptr ptr;141	struct sample *sample;142 143	if (bpf_get_current_pid_tgid() >> 32 != pid)144		return 0;145 146	val = 100;147 148	/* check that you can reserve a dynamic size reservation */149	err = bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);150 151	sample = err ? NULL : bpf_dynptr_data(&ptr, 0, sizeof(*sample));152	if (!sample) {153		err = 1;154		goto done;155	}156 157	sample->pid = 10;158 159	/* Can pass dynptr to callback functions */160	bpf_loop(10, ringbuf_callback, &ptr, 0);161 162	if (sample->pid != 55)163		err = 2;164 165done:166	bpf_ringbuf_discard_dynptr(&ptr, 0);167	return 0;168}169 170SEC("?cgroup_skb/egress")171int test_skb_readonly(struct __sk_buff *skb)172{173	__u8 write_data[2] = {1, 2};174	struct bpf_dynptr ptr;175	int ret;176 177	if (bpf_dynptr_from_skb(skb, 0, &ptr)) {178		err = 1;179		return 1;180	}181 182	/* since cgroup skbs are read only, writes should fail */183	ret = bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0);184	if (ret != -EINVAL) {185		err = 2;186		return 1;187	}188 189	return 1;190}191 192SEC("?cgroup_skb/egress")193int test_dynptr_skb_data(struct __sk_buff *skb)194{195	struct bpf_dynptr ptr;196	__u64 *data;197 198	if (bpf_dynptr_from_skb(skb, 0, &ptr)) {199		err = 1;200		return 1;201	}202 203	/* This should return NULL. Must use bpf_dynptr_slice API */204	data = bpf_dynptr_data(&ptr, 0, 1);205	if (data) {206		err = 2;207		return 1;208	}209 210	return 1;211}212 213SEC("tp/syscalls/sys_enter_nanosleep")214int test_adjust(void *ctx)215{216	struct bpf_dynptr ptr;217	__u32 bytes = 64;218	__u32 off = 10;219	__u32 trim = 15;220 221	if (bpf_get_current_pid_tgid() >> 32 != pid)222		return 0;223 224	err = bpf_ringbuf_reserve_dynptr(&ringbuf, bytes, 0, &ptr);225	if (err) {226		err = 1;227		goto done;228	}229 230	if (bpf_dynptr_size(&ptr) != bytes) {231		err = 2;232		goto done;233	}234 235	/* Advance the dynptr by off */236	err = bpf_dynptr_adjust(&ptr, off, bpf_dynptr_size(&ptr));237	if (err) {238		err = 3;239		goto done;240	}241 242	if (bpf_dynptr_size(&ptr) != bytes - off) {243		err = 4;244		goto done;245	}246 247	/* Trim the dynptr */248	err = bpf_dynptr_adjust(&ptr, off, 15);249	if (err) {250		err = 5;251		goto done;252	}253 254	/* Check that the size was adjusted correctly */255	if (bpf_dynptr_size(&ptr) != trim - off) {256		err = 6;257		goto done;258	}259 260done:261	bpf_ringbuf_discard_dynptr(&ptr, 0);262	return 0;263}264 265SEC("tp/syscalls/sys_enter_nanosleep")266int test_adjust_err(void *ctx)267{268	char write_data[45] = "hello there, world!!";269	struct bpf_dynptr ptr;270	__u32 size = 64;271	__u32 off = 20;272 273	if (bpf_get_current_pid_tgid() >> 32 != pid)274		return 0;275 276	if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 0, &ptr)) {277		err = 1;278		goto done;279	}280 281	/* Check that start can't be greater than end */282	if (bpf_dynptr_adjust(&ptr, 5, 1) != -EINVAL) {283		err = 2;284		goto done;285	}286 287	/* Check that start can't be greater than size */288	if (bpf_dynptr_adjust(&ptr, size + 1, size + 1) != -ERANGE) {289		err = 3;290		goto done;291	}292 293	/* Check that end can't be greater than size */294	if (bpf_dynptr_adjust(&ptr, 0, size + 1) != -ERANGE) {295		err = 4;296		goto done;297	}298 299	if (bpf_dynptr_adjust(&ptr, off, size)) {300		err = 5;301		goto done;302	}303 304	/* Check that you can't write more bytes than available into the dynptr305	 * after you've adjusted it306	 */307	if (bpf_dynptr_write(&ptr, 0, &write_data, sizeof(write_data), 0) != -E2BIG) {308		err = 6;309		goto done;310	}311 312	/* Check that even after adjusting, submitting/discarding313	 * a ringbuf dynptr works314	 */315	bpf_ringbuf_submit_dynptr(&ptr, 0);316	return 0;317 318done:319	bpf_ringbuf_discard_dynptr(&ptr, 0);320	return 0;321}322 323SEC("tp/syscalls/sys_enter_nanosleep")324int test_zero_size_dynptr(void *ctx)325{326	char write_data = 'x', read_data;327	struct bpf_dynptr ptr;328	__u32 size = 64;329 330	if (bpf_get_current_pid_tgid() >> 32 != pid)331		return 0;332 333	if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 0, &ptr)) {334		err = 1;335		goto done;336	}337 338	/* After this, the dynptr has a size of 0 */339	if (bpf_dynptr_adjust(&ptr, size, size)) {340		err = 2;341		goto done;342	}343 344	/* Test that reading + writing non-zero bytes is not ok */345	if (bpf_dynptr_read(&read_data, sizeof(read_data), &ptr, 0, 0) != -E2BIG) {346		err = 3;347		goto done;348	}349 350	if (bpf_dynptr_write(&ptr, 0, &write_data, sizeof(write_data), 0) != -E2BIG) {351		err = 4;352		goto done;353	}354 355	/* Test that reading + writing 0 bytes from a 0-size dynptr is ok */356	if (bpf_dynptr_read(&read_data, 0, &ptr, 0, 0)) {357		err = 5;358		goto done;359	}360 361	if (bpf_dynptr_write(&ptr, 0, &write_data, 0, 0)) {362		err = 6;363		goto done;364	}365 366	err = 0;367 368done:369	bpf_ringbuf_discard_dynptr(&ptr, 0);370	return 0;371}372 373SEC("tp/syscalls/sys_enter_nanosleep")374int test_dynptr_is_null(void *ctx)375{376	struct bpf_dynptr ptr1;377	struct bpf_dynptr ptr2;378	__u64 size = 4;379 380	if (bpf_get_current_pid_tgid() >> 32 != pid)381		return 0;382 383	/* Pass in invalid flags, get back an invalid dynptr */384	if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 123, &ptr1) != -EINVAL) {385		err = 1;386		goto exit_early;387	}388 389	/* Test that the invalid dynptr is null */390	if (!bpf_dynptr_is_null(&ptr1)) {391		err = 2;392		goto exit_early;393	}394 395	/* Get a valid dynptr */396	if (bpf_ringbuf_reserve_dynptr(&ringbuf, size, 0, &ptr2)) {397		err = 3;398		goto exit;399	}400 401	/* Test that the valid dynptr is not null */402	if (bpf_dynptr_is_null(&ptr2)) {403		err = 4;404		goto exit;405	}406 407exit:408	bpf_ringbuf_discard_dynptr(&ptr2, 0);409exit_early:410	bpf_ringbuf_discard_dynptr(&ptr1, 0);411	return 0;412}413 414SEC("cgroup_skb/egress")415int test_dynptr_is_rdonly(struct __sk_buff *skb)416{417	struct bpf_dynptr ptr1;418	struct bpf_dynptr ptr2;419	struct bpf_dynptr ptr3;420 421	/* Pass in invalid flags, get back an invalid dynptr */422	if (bpf_dynptr_from_skb(skb, 123, &ptr1) != -EINVAL) {423		err = 1;424		return 0;425	}426 427	/* Test that an invalid dynptr is_rdonly returns false */428	if (bpf_dynptr_is_rdonly(&ptr1)) {429		err = 2;430		return 0;431	}432 433	/* Get a read-only dynptr */434	if (bpf_dynptr_from_skb(skb, 0, &ptr2)) {435		err = 3;436		return 0;437	}438 439	/* Test that the dynptr is read-only */440	if (!bpf_dynptr_is_rdonly(&ptr2)) {441		err = 4;442		return 0;443	}444 445	/* Get a read-writeable dynptr */446	if (bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr3)) {447		err = 5;448		goto done;449	}450 451	/* Test that the dynptr is read-only */452	if (bpf_dynptr_is_rdonly(&ptr3)) {453		err = 6;454		goto done;455	}456 457done:458	bpf_ringbuf_discard_dynptr(&ptr3, 0);459	return 0;460}461 462SEC("cgroup_skb/egress")463int test_dynptr_clone(struct __sk_buff *skb)464{465	struct bpf_dynptr ptr1;466	struct bpf_dynptr ptr2;467	__u32 off = 2, size;468 469	/* Get a dynptr */470	if (bpf_dynptr_from_skb(skb, 0, &ptr1)) {471		err = 1;472		return 0;473	}474 475	if (bpf_dynptr_adjust(&ptr1, off, bpf_dynptr_size(&ptr1))) {476		err = 2;477		return 0;478	}479 480	/* Clone the dynptr */481	if (bpf_dynptr_clone(&ptr1, &ptr2)) {482		err = 3;483		return 0;484	}485 486	size = bpf_dynptr_size(&ptr1);487 488	/* Check that the clone has the same size and rd-only */489	if (bpf_dynptr_size(&ptr2) != size) {490		err = 4;491		return 0;492	}493 494	if (bpf_dynptr_is_rdonly(&ptr2) != bpf_dynptr_is_rdonly(&ptr1)) {495		err = 5;496		return 0;497	}498 499	/* Advance and trim the original dynptr */500	bpf_dynptr_adjust(&ptr1, 5, 5);501 502	/* Check that only original dynptr was affected, and the clone wasn't */503	if (bpf_dynptr_size(&ptr2) != size) {504		err = 6;505		return 0;506	}507 508	return 0;509}510 511SEC("?cgroup_skb/egress")512int test_dynptr_skb_no_buff(struct __sk_buff *skb)513{514	struct bpf_dynptr ptr;515	__u64 *data;516 517	if (bpf_dynptr_from_skb(skb, 0, &ptr)) {518		err = 1;519		return 1;520	}521 522	/* This may return NULL. SKB may require a buffer */523	data = bpf_dynptr_slice(&ptr, 0, NULL, 1);524 525	return !!data;526}527 528SEC("?cgroup_skb/egress")529int test_dynptr_skb_strcmp(struct __sk_buff *skb)530{531	struct bpf_dynptr ptr;532	char *data;533 534	if (bpf_dynptr_from_skb(skb, 0, &ptr)) {535		err = 1;536		return 1;537	}538 539	/* This may return NULL. SKB may require a buffer */540	data = bpf_dynptr_slice(&ptr, 0, NULL, 10);541	if (data) {542		bpf_strncmp(data, 10, "foo");543		return 1;544	}545 546	return 1;547}548 549SEC("tp_btf/kfree_skb")550int BPF_PROG(test_dynptr_skb_tp_btf, void *skb, void *location)551{552	__u8 write_data[2] = {1, 2};553	struct bpf_dynptr ptr;554	int ret;555 556	if (bpf_dynptr_from_skb(skb, 0, &ptr)) {557		err = 1;558		return 1;559	}560 561	/* since tp_btf skbs are read only, writes should fail */562	ret = bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0);563	if (ret != -EINVAL) {564		err = 2;565		return 1;566	}567 568	return 1;569}570