10cf7052aSJoanne Koong // SPDX-License-Identifier: GPL-2.0
20cf7052aSJoanne Koong /* Copyright (c) 2022 Facebook */
30cf7052aSJoanne Koong
40cf7052aSJoanne Koong #include <errno.h>
50cf7052aSJoanne Koong #include <string.h>
6*12852f8eSYonghong Song #include <stdbool.h>
70cf7052aSJoanne Koong #include <linux/bpf.h>
80cf7052aSJoanne Koong #include <bpf/bpf_helpers.h>
9cfa7b011SJoanne Koong #include <linux/if_ether.h>
100cf7052aSJoanne Koong #include "bpf_misc.h"
11cfa7b011SJoanne Koong #include "bpf_kfuncs.h"
120cf7052aSJoanne Koong
130cf7052aSJoanne Koong char _license[] SEC("license") = "GPL";
140cf7052aSJoanne Koong
150cf7052aSJoanne Koong struct test_info {
160cf7052aSJoanne Koong int x;
170cf7052aSJoanne Koong struct bpf_dynptr ptr;
180cf7052aSJoanne Koong };
190cf7052aSJoanne Koong
200cf7052aSJoanne Koong struct {
210cf7052aSJoanne Koong __uint(type, BPF_MAP_TYPE_ARRAY);
220cf7052aSJoanne Koong __uint(max_entries, 1);
230cf7052aSJoanne Koong __type(key, __u32);
240cf7052aSJoanne Koong __type(value, struct bpf_dynptr);
250cf7052aSJoanne Koong } array_map1 SEC(".maps");
260cf7052aSJoanne Koong
270cf7052aSJoanne Koong struct {
280cf7052aSJoanne Koong __uint(type, BPF_MAP_TYPE_ARRAY);
290cf7052aSJoanne Koong __uint(max_entries, 1);
300cf7052aSJoanne Koong __type(key, __u32);
310cf7052aSJoanne Koong __type(value, struct test_info);
320cf7052aSJoanne Koong } array_map2 SEC(".maps");
330cf7052aSJoanne Koong
340cf7052aSJoanne Koong struct {
350cf7052aSJoanne Koong __uint(type, BPF_MAP_TYPE_ARRAY);
360cf7052aSJoanne Koong __uint(max_entries, 1);
370cf7052aSJoanne Koong __type(key, __u32);
380cf7052aSJoanne Koong __type(value, __u32);
390cf7052aSJoanne Koong } array_map3 SEC(".maps");
400cf7052aSJoanne Koong
41f4d24edfSKumar Kartikeya Dwivedi struct {
42f4d24edfSKumar Kartikeya Dwivedi __uint(type, BPF_MAP_TYPE_ARRAY);
43f4d24edfSKumar Kartikeya Dwivedi __uint(max_entries, 1);
44f4d24edfSKumar Kartikeya Dwivedi __type(key, __u32);
45f4d24edfSKumar Kartikeya Dwivedi __type(value, __u64);
46f4d24edfSKumar Kartikeya Dwivedi } array_map4 SEC(".maps");
47f4d24edfSKumar Kartikeya Dwivedi
480cf7052aSJoanne Koong struct sample {
490cf7052aSJoanne Koong int pid;
500cf7052aSJoanne Koong long value;
510cf7052aSJoanne Koong char comm[16];
520cf7052aSJoanne Koong };
530cf7052aSJoanne Koong
540cf7052aSJoanne Koong struct {
550cf7052aSJoanne Koong __uint(type, BPF_MAP_TYPE_RINGBUF);
5626c386ecSAndrii Nakryiko __uint(max_entries, 4096);
570cf7052aSJoanne Koong } ringbuf SEC(".maps");
580cf7052aSJoanne Koong
590cf7052aSJoanne Koong int err, val;
600cf7052aSJoanne Koong
get_map_val_dynptr(struct bpf_dynptr * ptr)610cf7052aSJoanne Koong static int get_map_val_dynptr(struct bpf_dynptr *ptr)
620cf7052aSJoanne Koong {
630cf7052aSJoanne Koong __u32 key = 0, *map_val;
640cf7052aSJoanne Koong
650cf7052aSJoanne Koong bpf_map_update_elem(&array_map3, &key, &val, 0);
660cf7052aSJoanne Koong
670cf7052aSJoanne Koong map_val = bpf_map_lookup_elem(&array_map3, &key);
680cf7052aSJoanne Koong if (!map_val)
690cf7052aSJoanne Koong return -ENOENT;
700cf7052aSJoanne Koong
710cf7052aSJoanne Koong bpf_dynptr_from_mem(map_val, sizeof(*map_val), 0, ptr);
720cf7052aSJoanne Koong
730cf7052aSJoanne Koong return 0;
740cf7052aSJoanne Koong }
750cf7052aSJoanne Koong
760cf7052aSJoanne Koong /* Every bpf_ringbuf_reserve_dynptr call must have a corresponding
770cf7052aSJoanne Koong * bpf_ringbuf_submit/discard_dynptr call
780cf7052aSJoanne Koong */
795653f55eSJoanne Koong SEC("?raw_tp")
80f8064ab9SKumar Kartikeya Dwivedi __failure __msg("Unreleased reference id=2")
ringbuf_missing_release1(void * ctx)810cf7052aSJoanne Koong int ringbuf_missing_release1(void *ctx)
820cf7052aSJoanne Koong {
830cf7052aSJoanne Koong struct bpf_dynptr ptr;
840cf7052aSJoanne Koong
850cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);
860cf7052aSJoanne Koong
870cf7052aSJoanne Koong /* missing a call to bpf_ringbuf_discard/submit_dynptr */
880cf7052aSJoanne Koong
890cf7052aSJoanne Koong return 0;
900cf7052aSJoanne Koong }
910cf7052aSJoanne Koong
925653f55eSJoanne Koong SEC("?raw_tp")
93f8064ab9SKumar Kartikeya Dwivedi __failure __msg("Unreleased reference id=4")
ringbuf_missing_release2(void * ctx)940cf7052aSJoanne Koong int ringbuf_missing_release2(void *ctx)
950cf7052aSJoanne Koong {
960cf7052aSJoanne Koong struct bpf_dynptr ptr1, ptr2;
970cf7052aSJoanne Koong struct sample *sample;
980cf7052aSJoanne Koong
990cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr1);
1000cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr2);
1010cf7052aSJoanne Koong
1020cf7052aSJoanne Koong sample = bpf_dynptr_data(&ptr1, 0, sizeof(*sample));
1030cf7052aSJoanne Koong if (!sample) {
1040cf7052aSJoanne Koong bpf_ringbuf_discard_dynptr(&ptr1, 0);
1050cf7052aSJoanne Koong bpf_ringbuf_discard_dynptr(&ptr2, 0);
1060cf7052aSJoanne Koong return 0;
1070cf7052aSJoanne Koong }
1080cf7052aSJoanne Koong
1090cf7052aSJoanne Koong bpf_ringbuf_submit_dynptr(&ptr1, 0);
1100cf7052aSJoanne Koong
1110cf7052aSJoanne Koong /* missing a call to bpf_ringbuf_discard/submit_dynptr on ptr2 */
1120cf7052aSJoanne Koong
1130cf7052aSJoanne Koong return 0;
1140cf7052aSJoanne Koong }
1150cf7052aSJoanne Koong
missing_release_callback_fn(__u32 index,void * data)1160cf7052aSJoanne Koong static int missing_release_callback_fn(__u32 index, void *data)
1170cf7052aSJoanne Koong {
1180cf7052aSJoanne Koong struct bpf_dynptr ptr;
1190cf7052aSJoanne Koong
1200cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);
1210cf7052aSJoanne Koong
1220cf7052aSJoanne Koong /* missing a call to bpf_ringbuf_discard/submit_dynptr */
1230cf7052aSJoanne Koong
1240cf7052aSJoanne Koong return 0;
1250cf7052aSJoanne Koong }
1260cf7052aSJoanne Koong
1270cf7052aSJoanne Koong /* Any dynptr initialized within a callback must have bpf_dynptr_put called */
1285653f55eSJoanne Koong SEC("?raw_tp")
12926c386ecSAndrii Nakryiko __failure __msg("Unreleased reference id")
ringbuf_missing_release_callback(void * ctx)1300cf7052aSJoanne Koong int ringbuf_missing_release_callback(void *ctx)
1310cf7052aSJoanne Koong {
1320cf7052aSJoanne Koong bpf_loop(10, missing_release_callback_fn, NULL, 0);
1330cf7052aSJoanne Koong return 0;
1340cf7052aSJoanne Koong }
1350cf7052aSJoanne Koong
1360cf7052aSJoanne Koong /* Can't call bpf_ringbuf_submit/discard_dynptr on a non-initialized dynptr */
1375653f55eSJoanne Koong SEC("?raw_tp")
13826c386ecSAndrii Nakryiko __failure __msg("arg 1 is an unacquired reference")
ringbuf_release_uninit_dynptr(void * ctx)1390cf7052aSJoanne Koong int ringbuf_release_uninit_dynptr(void *ctx)
1400cf7052aSJoanne Koong {
1410cf7052aSJoanne Koong struct bpf_dynptr ptr;
1420cf7052aSJoanne Koong
1430cf7052aSJoanne Koong /* this should fail */
1440cf7052aSJoanne Koong bpf_ringbuf_submit_dynptr(&ptr, 0);
1450cf7052aSJoanne Koong
1460cf7052aSJoanne Koong return 0;
1470cf7052aSJoanne Koong }
1480cf7052aSJoanne Koong
1490cf7052aSJoanne Koong /* A dynptr can't be used after it has been invalidated */
1505653f55eSJoanne Koong SEC("?raw_tp")
15126c386ecSAndrii Nakryiko __failure __msg("Expected an initialized dynptr as arg #3")
use_after_invalid(void * ctx)1520cf7052aSJoanne Koong int use_after_invalid(void *ctx)
1530cf7052aSJoanne Koong {
1540cf7052aSJoanne Koong struct bpf_dynptr ptr;
1550cf7052aSJoanne Koong char read_data[64];
1560cf7052aSJoanne Koong
1570cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(read_data), 0, &ptr);
1580cf7052aSJoanne Koong
159f8d3da4eSJoanne Koong bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
1600cf7052aSJoanne Koong
1610cf7052aSJoanne Koong bpf_ringbuf_submit_dynptr(&ptr, 0);
1620cf7052aSJoanne Koong
1630cf7052aSJoanne Koong /* this should fail */
164f8d3da4eSJoanne Koong bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
1650cf7052aSJoanne Koong
1660cf7052aSJoanne Koong return 0;
1670cf7052aSJoanne Koong }
1680cf7052aSJoanne Koong
1690cf7052aSJoanne Koong /* Can't call non-dynptr ringbuf APIs on a dynptr ringbuf sample */
1705653f55eSJoanne Koong SEC("?raw_tp")
17126c386ecSAndrii Nakryiko __failure __msg("type=mem expected=ringbuf_mem")
ringbuf_invalid_api(void * ctx)1720cf7052aSJoanne Koong int ringbuf_invalid_api(void *ctx)
1730cf7052aSJoanne Koong {
1740cf7052aSJoanne Koong struct bpf_dynptr ptr;
1750cf7052aSJoanne Koong struct sample *sample;
1760cf7052aSJoanne Koong
1770cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr);
1780cf7052aSJoanne Koong sample = bpf_dynptr_data(&ptr, 0, sizeof(*sample));
1790cf7052aSJoanne Koong if (!sample)
1800cf7052aSJoanne Koong goto done;
1810cf7052aSJoanne Koong
1820cf7052aSJoanne Koong sample->pid = 123;
1830cf7052aSJoanne Koong
1840cf7052aSJoanne Koong /* invalid API use. need to use dynptr API to submit/discard */
1850cf7052aSJoanne Koong bpf_ringbuf_submit(sample, 0);
1860cf7052aSJoanne Koong
1870cf7052aSJoanne Koong done:
1880cf7052aSJoanne Koong bpf_ringbuf_discard_dynptr(&ptr, 0);
1890cf7052aSJoanne Koong return 0;
1900cf7052aSJoanne Koong }
1910cf7052aSJoanne Koong
1920cf7052aSJoanne Koong /* Can't add a dynptr to a map */
1935653f55eSJoanne Koong SEC("?raw_tp")
19426c386ecSAndrii Nakryiko __failure __msg("invalid indirect read from stack")
add_dynptr_to_map1(void * ctx)1950cf7052aSJoanne Koong int add_dynptr_to_map1(void *ctx)
1960cf7052aSJoanne Koong {
1970cf7052aSJoanne Koong struct bpf_dynptr ptr;
1980cf7052aSJoanne Koong int key = 0;
1990cf7052aSJoanne Koong
2000cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);
2010cf7052aSJoanne Koong
2020cf7052aSJoanne Koong /* this should fail */
2030cf7052aSJoanne Koong bpf_map_update_elem(&array_map1, &key, &ptr, 0);
2040cf7052aSJoanne Koong
2050cf7052aSJoanne Koong bpf_ringbuf_submit_dynptr(&ptr, 0);
2060cf7052aSJoanne Koong
2070cf7052aSJoanne Koong return 0;
2080cf7052aSJoanne Koong }
2090cf7052aSJoanne Koong
2100cf7052aSJoanne Koong /* Can't add a struct with an embedded dynptr to a map */
2115653f55eSJoanne Koong SEC("?raw_tp")
21226c386ecSAndrii Nakryiko __failure __msg("invalid indirect read from stack")
add_dynptr_to_map2(void * ctx)2130cf7052aSJoanne Koong int add_dynptr_to_map2(void *ctx)
2140cf7052aSJoanne Koong {
2150cf7052aSJoanne Koong struct test_info x;
2160cf7052aSJoanne Koong int key = 0;
2170cf7052aSJoanne Koong
2180cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &x.ptr);
2190cf7052aSJoanne Koong
2200cf7052aSJoanne Koong /* this should fail */
2210cf7052aSJoanne Koong bpf_map_update_elem(&array_map2, &key, &x, 0);
2220cf7052aSJoanne Koong
2230cf7052aSJoanne Koong bpf_ringbuf_submit_dynptr(&x.ptr, 0);
2240cf7052aSJoanne Koong
2250cf7052aSJoanne Koong return 0;
2260cf7052aSJoanne Koong }
2270cf7052aSJoanne Koong
2280cf7052aSJoanne Koong /* A data slice can't be accessed out of bounds */
2295653f55eSJoanne Koong SEC("?raw_tp")
23026c386ecSAndrii Nakryiko __failure __msg("value is outside of the allowed memory range")
data_slice_out_of_bounds_ringbuf(void * ctx)2310cf7052aSJoanne Koong int data_slice_out_of_bounds_ringbuf(void *ctx)
2320cf7052aSJoanne Koong {
2330cf7052aSJoanne Koong struct bpf_dynptr ptr;
2340cf7052aSJoanne Koong void *data;
2350cf7052aSJoanne Koong
2360cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, 8, 0, &ptr);
2370cf7052aSJoanne Koong
2380cf7052aSJoanne Koong data = bpf_dynptr_data(&ptr, 0, 8);
2390cf7052aSJoanne Koong if (!data)
2400cf7052aSJoanne Koong goto done;
2410cf7052aSJoanne Koong
2420cf7052aSJoanne Koong /* can't index out of bounds of the data slice */
2430cf7052aSJoanne Koong val = *((char *)data + 8);
2440cf7052aSJoanne Koong
2450cf7052aSJoanne Koong done:
2460cf7052aSJoanne Koong bpf_ringbuf_submit_dynptr(&ptr, 0);
2470cf7052aSJoanne Koong return 0;
2480cf7052aSJoanne Koong }
2490cf7052aSJoanne Koong
250cfa7b011SJoanne Koong /* A data slice can't be accessed out of bounds */
251cfa7b011SJoanne Koong SEC("?tc")
252cfa7b011SJoanne Koong __failure __msg("value is outside of the allowed memory range")
data_slice_out_of_bounds_skb(struct __sk_buff * skb)253cfa7b011SJoanne Koong int data_slice_out_of_bounds_skb(struct __sk_buff *skb)
254cfa7b011SJoanne Koong {
255cfa7b011SJoanne Koong struct bpf_dynptr ptr;
256cfa7b011SJoanne Koong struct ethhdr *hdr;
257cfa7b011SJoanne Koong char buffer[sizeof(*hdr)] = {};
258cfa7b011SJoanne Koong
259cfa7b011SJoanne Koong bpf_dynptr_from_skb(skb, 0, &ptr);
260cfa7b011SJoanne Koong
261cfa7b011SJoanne Koong hdr = bpf_dynptr_slice_rdwr(&ptr, 0, buffer, sizeof(buffer));
262cfa7b011SJoanne Koong if (!hdr)
263cfa7b011SJoanne Koong return SK_DROP;
264cfa7b011SJoanne Koong
265cfa7b011SJoanne Koong /* this should fail */
266cfa7b011SJoanne Koong *(__u8*)(hdr + 1) = 1;
267cfa7b011SJoanne Koong
268cfa7b011SJoanne Koong return SK_PASS;
269cfa7b011SJoanne Koong }
270cfa7b011SJoanne Koong
2715653f55eSJoanne Koong SEC("?raw_tp")
27226c386ecSAndrii Nakryiko __failure __msg("value is outside of the allowed memory range")
data_slice_out_of_bounds_map_value(void * ctx)2730cf7052aSJoanne Koong int data_slice_out_of_bounds_map_value(void *ctx)
2740cf7052aSJoanne Koong {
275c8ed6685SAndrii Nakryiko __u32 map_val;
2760cf7052aSJoanne Koong struct bpf_dynptr ptr;
2770cf7052aSJoanne Koong void *data;
2780cf7052aSJoanne Koong
2790cf7052aSJoanne Koong get_map_val_dynptr(&ptr);
2800cf7052aSJoanne Koong
2810cf7052aSJoanne Koong data = bpf_dynptr_data(&ptr, 0, sizeof(map_val));
2820cf7052aSJoanne Koong if (!data)
2830cf7052aSJoanne Koong return 0;
2840cf7052aSJoanne Koong
2850cf7052aSJoanne Koong /* can't index out of bounds of the data slice */
2860cf7052aSJoanne Koong val = *((char *)data + (sizeof(map_val) + 1));
2870cf7052aSJoanne Koong
2880cf7052aSJoanne Koong return 0;
2890cf7052aSJoanne Koong }
2900cf7052aSJoanne Koong
2910cf7052aSJoanne Koong /* A data slice can't be used after it has been released */
2925653f55eSJoanne Koong SEC("?raw_tp")
29326c386ecSAndrii Nakryiko __failure __msg("invalid mem access 'scalar'")
data_slice_use_after_release1(void * ctx)294dc444be8SJoanne Koong int data_slice_use_after_release1(void *ctx)
2950cf7052aSJoanne Koong {
2960cf7052aSJoanne Koong struct bpf_dynptr ptr;
2970cf7052aSJoanne Koong struct sample *sample;
2980cf7052aSJoanne Koong
2990cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr);
3000cf7052aSJoanne Koong sample = bpf_dynptr_data(&ptr, 0, sizeof(*sample));
3010cf7052aSJoanne Koong if (!sample)
3020cf7052aSJoanne Koong goto done;
3030cf7052aSJoanne Koong
3040cf7052aSJoanne Koong sample->pid = 123;
3050cf7052aSJoanne Koong
3060cf7052aSJoanne Koong bpf_ringbuf_submit_dynptr(&ptr, 0);
3070cf7052aSJoanne Koong
3080cf7052aSJoanne Koong /* this should fail */
3090cf7052aSJoanne Koong val = sample->pid;
3100cf7052aSJoanne Koong
3110cf7052aSJoanne Koong return 0;
3120cf7052aSJoanne Koong
3130cf7052aSJoanne Koong done:
3140cf7052aSJoanne Koong bpf_ringbuf_discard_dynptr(&ptr, 0);
3150cf7052aSJoanne Koong return 0;
3160cf7052aSJoanne Koong }
3170cf7052aSJoanne Koong
318dc444be8SJoanne Koong /* A data slice can't be used after it has been released.
319dc444be8SJoanne Koong *
320dc444be8SJoanne Koong * This tests the case where the data slice tracks a dynptr (ptr2)
321dc444be8SJoanne Koong * that is at a non-zero offset from the frame pointer (ptr1 is at fp,
322dc444be8SJoanne Koong * ptr2 is at fp - 16).
323dc444be8SJoanne Koong */
324dc444be8SJoanne Koong SEC("?raw_tp")
32526c386ecSAndrii Nakryiko __failure __msg("invalid mem access 'scalar'")
data_slice_use_after_release2(void * ctx)326dc444be8SJoanne Koong int data_slice_use_after_release2(void *ctx)
327dc444be8SJoanne Koong {
328dc444be8SJoanne Koong struct bpf_dynptr ptr1, ptr2;
329dc444be8SJoanne Koong struct sample *sample;
330dc444be8SJoanne Koong
331dc444be8SJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr1);
332dc444be8SJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(*sample), 0, &ptr2);
333dc444be8SJoanne Koong
334dc444be8SJoanne Koong sample = bpf_dynptr_data(&ptr2, 0, sizeof(*sample));
335dc444be8SJoanne Koong if (!sample)
336dc444be8SJoanne Koong goto done;
337dc444be8SJoanne Koong
338dc444be8SJoanne Koong sample->pid = 23;
339dc444be8SJoanne Koong
340dc444be8SJoanne Koong bpf_ringbuf_submit_dynptr(&ptr2, 0);
341dc444be8SJoanne Koong
342dc444be8SJoanne Koong /* this should fail */
343dc444be8SJoanne Koong sample->pid = 23;
344dc444be8SJoanne Koong
345dc444be8SJoanne Koong bpf_ringbuf_submit_dynptr(&ptr1, 0);
346dc444be8SJoanne Koong
347dc444be8SJoanne Koong return 0;
348dc444be8SJoanne Koong
349dc444be8SJoanne Koong done:
350dc444be8SJoanne Koong bpf_ringbuf_discard_dynptr(&ptr2, 0);
351dc444be8SJoanne Koong bpf_ringbuf_discard_dynptr(&ptr1, 0);
352dc444be8SJoanne Koong return 0;
353dc444be8SJoanne Koong }
354dc444be8SJoanne Koong
3550cf7052aSJoanne Koong /* A data slice must be first checked for NULL */
3565653f55eSJoanne Koong SEC("?raw_tp")
35726c386ecSAndrii Nakryiko __failure __msg("invalid mem access 'mem_or_null'")
data_slice_missing_null_check1(void * ctx)3580cf7052aSJoanne Koong int data_slice_missing_null_check1(void *ctx)
3590cf7052aSJoanne Koong {
3600cf7052aSJoanne Koong struct bpf_dynptr ptr;
3610cf7052aSJoanne Koong void *data;
3620cf7052aSJoanne Koong
3630cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, 8, 0, &ptr);
3640cf7052aSJoanne Koong
3650cf7052aSJoanne Koong data = bpf_dynptr_data(&ptr, 0, 8);
3660cf7052aSJoanne Koong
3670cf7052aSJoanne Koong /* missing if (!data) check */
3680cf7052aSJoanne Koong
3690cf7052aSJoanne Koong /* this should fail */
3700cf7052aSJoanne Koong *(__u8 *)data = 3;
3710cf7052aSJoanne Koong
3720cf7052aSJoanne Koong bpf_ringbuf_submit_dynptr(&ptr, 0);
3730cf7052aSJoanne Koong return 0;
3740cf7052aSJoanne Koong }
3750cf7052aSJoanne Koong
3760cf7052aSJoanne Koong /* A data slice can't be dereferenced if it wasn't checked for null */
3775653f55eSJoanne Koong SEC("?raw_tp")
37826c386ecSAndrii Nakryiko __failure __msg("invalid mem access 'mem_or_null'")
data_slice_missing_null_check2(void * ctx)3790cf7052aSJoanne Koong int data_slice_missing_null_check2(void *ctx)
3800cf7052aSJoanne Koong {
3810cf7052aSJoanne Koong struct bpf_dynptr ptr;
3820cf7052aSJoanne Koong __u64 *data1, *data2;
3830cf7052aSJoanne Koong
3840cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr);
3850cf7052aSJoanne Koong
3860cf7052aSJoanne Koong data1 = bpf_dynptr_data(&ptr, 0, 8);
3870cf7052aSJoanne Koong data2 = bpf_dynptr_data(&ptr, 0, 8);
3880cf7052aSJoanne Koong if (data1)
3890cf7052aSJoanne Koong /* this should fail */
3900cf7052aSJoanne Koong *data2 = 3;
3910cf7052aSJoanne Koong
3920cf7052aSJoanne Koong bpf_ringbuf_discard_dynptr(&ptr, 0);
3930cf7052aSJoanne Koong return 0;
3940cf7052aSJoanne Koong }
3950cf7052aSJoanne Koong
3960cf7052aSJoanne Koong /* Can't pass in a dynptr as an arg to a helper function that doesn't take in a
3970cf7052aSJoanne Koong * dynptr argument
3980cf7052aSJoanne Koong */
3995653f55eSJoanne Koong SEC("?raw_tp")
40026c386ecSAndrii Nakryiko __failure __msg("invalid indirect read from stack")
invalid_helper1(void * ctx)4010cf7052aSJoanne Koong int invalid_helper1(void *ctx)
4020cf7052aSJoanne Koong {
4030cf7052aSJoanne Koong struct bpf_dynptr ptr;
4040cf7052aSJoanne Koong
4050cf7052aSJoanne Koong get_map_val_dynptr(&ptr);
4060cf7052aSJoanne Koong
4070cf7052aSJoanne Koong /* this should fail */
4080cf7052aSJoanne Koong bpf_strncmp((const char *)&ptr, sizeof(ptr), "hello!");
4090cf7052aSJoanne Koong
4100cf7052aSJoanne Koong return 0;
4110cf7052aSJoanne Koong }
4120cf7052aSJoanne Koong
4130cf7052aSJoanne Koong /* A dynptr can't be passed into a helper function at a non-zero offset */
4145653f55eSJoanne Koong SEC("?raw_tp")
41579168a66SKumar Kartikeya Dwivedi __failure __msg("cannot pass in dynptr at an offset=-8")
invalid_helper2(void * ctx)4160cf7052aSJoanne Koong int invalid_helper2(void *ctx)
4170cf7052aSJoanne Koong {
4180cf7052aSJoanne Koong struct bpf_dynptr ptr;
4190cf7052aSJoanne Koong char read_data[64];
4200cf7052aSJoanne Koong
4210cf7052aSJoanne Koong get_map_val_dynptr(&ptr);
4220cf7052aSJoanne Koong
4230cf7052aSJoanne Koong /* this should fail */
424f8d3da4eSJoanne Koong bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 8, 0, 0);
4250cf7052aSJoanne Koong return 0;
4260cf7052aSJoanne Koong }
4270cf7052aSJoanne Koong
4280cf7052aSJoanne Koong /* A bpf_dynptr is invalidated if it's been written into */
4295653f55eSJoanne Koong SEC("?raw_tp")
43026c386ecSAndrii Nakryiko __failure __msg("Expected an initialized dynptr as arg #1")
invalid_write1(void * ctx)4310cf7052aSJoanne Koong int invalid_write1(void *ctx)
4320cf7052aSJoanne Koong {
4330cf7052aSJoanne Koong struct bpf_dynptr ptr;
4340cf7052aSJoanne Koong void *data;
4350cf7052aSJoanne Koong __u8 x = 0;
4360cf7052aSJoanne Koong
4370cf7052aSJoanne Koong get_map_val_dynptr(&ptr);
4380cf7052aSJoanne Koong
4390cf7052aSJoanne Koong memcpy(&ptr, &x, sizeof(x));
4400cf7052aSJoanne Koong
4410cf7052aSJoanne Koong /* this should fail */
4420cf7052aSJoanne Koong data = bpf_dynptr_data(&ptr, 0, 1);
443c8ed6685SAndrii Nakryiko __sink(data);
4440cf7052aSJoanne Koong
4450cf7052aSJoanne Koong return 0;
4460cf7052aSJoanne Koong }
4470cf7052aSJoanne Koong
4480cf7052aSJoanne Koong /*
4490cf7052aSJoanne Koong * A bpf_dynptr can't be used as a dynptr if it has been written into at a fixed
4500cf7052aSJoanne Koong * offset
4510cf7052aSJoanne Koong */
4525653f55eSJoanne Koong SEC("?raw_tp")
453ef8fc7a0SKumar Kartikeya Dwivedi __failure __msg("cannot overwrite referenced dynptr")
invalid_write2(void * ctx)4540cf7052aSJoanne Koong int invalid_write2(void *ctx)
4550cf7052aSJoanne Koong {
4560cf7052aSJoanne Koong struct bpf_dynptr ptr;
4570cf7052aSJoanne Koong char read_data[64];
4580cf7052aSJoanne Koong __u8 x = 0;
4590cf7052aSJoanne Koong
4600cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr);
4610cf7052aSJoanne Koong
4620cf7052aSJoanne Koong memcpy((void *)&ptr + 8, &x, sizeof(x));
4630cf7052aSJoanne Koong
4640cf7052aSJoanne Koong /* this should fail */
465f8d3da4eSJoanne Koong bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
4660cf7052aSJoanne Koong
4670cf7052aSJoanne Koong bpf_ringbuf_submit_dynptr(&ptr, 0);
4680cf7052aSJoanne Koong
4690cf7052aSJoanne Koong return 0;
4700cf7052aSJoanne Koong }
4710cf7052aSJoanne Koong
4720cf7052aSJoanne Koong /*
4730cf7052aSJoanne Koong * A bpf_dynptr can't be used as a dynptr if it has been written into at a
4740cf7052aSJoanne Koong * non-const offset
4750cf7052aSJoanne Koong */
4765653f55eSJoanne Koong SEC("?raw_tp")
477ef8fc7a0SKumar Kartikeya Dwivedi __failure __msg("cannot overwrite referenced dynptr")
invalid_write3(void * ctx)4780cf7052aSJoanne Koong int invalid_write3(void *ctx)
4790cf7052aSJoanne Koong {
4800cf7052aSJoanne Koong struct bpf_dynptr ptr;
4810cf7052aSJoanne Koong char stack_buf[16];
4820cf7052aSJoanne Koong unsigned long len;
4830cf7052aSJoanne Koong __u8 x = 0;
4840cf7052aSJoanne Koong
4850cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, 8, 0, &ptr);
4860cf7052aSJoanne Koong
4870cf7052aSJoanne Koong memcpy(stack_buf, &val, sizeof(val));
4880cf7052aSJoanne Koong len = stack_buf[0] & 0xf;
4890cf7052aSJoanne Koong
4900cf7052aSJoanne Koong memcpy((void *)&ptr + len, &x, sizeof(x));
4910cf7052aSJoanne Koong
4920cf7052aSJoanne Koong /* this should fail */
4930cf7052aSJoanne Koong bpf_ringbuf_submit_dynptr(&ptr, 0);
4940cf7052aSJoanne Koong
4950cf7052aSJoanne Koong return 0;
4960cf7052aSJoanne Koong }
4970cf7052aSJoanne Koong
invalid_write4_callback(__u32 index,void * data)4980cf7052aSJoanne Koong static int invalid_write4_callback(__u32 index, void *data)
4990cf7052aSJoanne Koong {
5000cf7052aSJoanne Koong *(__u32 *)data = 123;
5010cf7052aSJoanne Koong
5020cf7052aSJoanne Koong return 0;
5030cf7052aSJoanne Koong }
5040cf7052aSJoanne Koong
5050cf7052aSJoanne Koong /* If the dynptr is written into in a callback function, it should
5060cf7052aSJoanne Koong * be invalidated as a dynptr
5070cf7052aSJoanne Koong */
5085653f55eSJoanne Koong SEC("?raw_tp")
509ef8fc7a0SKumar Kartikeya Dwivedi __failure __msg("cannot overwrite referenced dynptr")
invalid_write4(void * ctx)5100cf7052aSJoanne Koong int invalid_write4(void *ctx)
5110cf7052aSJoanne Koong {
5120cf7052aSJoanne Koong struct bpf_dynptr ptr;
5130cf7052aSJoanne Koong
5140cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr);
5150cf7052aSJoanne Koong
5160cf7052aSJoanne Koong bpf_loop(10, invalid_write4_callback, &ptr, 0);
5170cf7052aSJoanne Koong
5180cf7052aSJoanne Koong /* this should fail */
5190cf7052aSJoanne Koong bpf_ringbuf_submit_dynptr(&ptr, 0);
5200cf7052aSJoanne Koong
5210cf7052aSJoanne Koong return 0;
5220cf7052aSJoanne Koong }
5230cf7052aSJoanne Koong
5240cf7052aSJoanne Koong /* A globally-defined bpf_dynptr can't be used (it must reside as a stack frame) */
5250cf7052aSJoanne Koong struct bpf_dynptr global_dynptr;
52626c386ecSAndrii Nakryiko
5275653f55eSJoanne Koong SEC("?raw_tp")
52826c386ecSAndrii Nakryiko __failure __msg("type=map_value expected=fp")
global(void * ctx)5290cf7052aSJoanne Koong int global(void *ctx)
5300cf7052aSJoanne Koong {
5310cf7052aSJoanne Koong /* this should fail */
5320cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &global_dynptr);
5330cf7052aSJoanne Koong
5340cf7052aSJoanne Koong bpf_ringbuf_discard_dynptr(&global_dynptr, 0);
5350cf7052aSJoanne Koong
5360cf7052aSJoanne Koong return 0;
5370cf7052aSJoanne Koong }
5380cf7052aSJoanne Koong
5390cf7052aSJoanne Koong /* A direct read should fail */
5405653f55eSJoanne Koong SEC("?raw_tp")
54126c386ecSAndrii Nakryiko __failure __msg("invalid read from stack")
invalid_read1(void * ctx)5420cf7052aSJoanne Koong int invalid_read1(void *ctx)
5430cf7052aSJoanne Koong {
5440cf7052aSJoanne Koong struct bpf_dynptr ptr;
5450cf7052aSJoanne Koong
5460cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr);
5470cf7052aSJoanne Koong
5480cf7052aSJoanne Koong /* this should fail */
5490cf7052aSJoanne Koong val = *(int *)&ptr;
5500cf7052aSJoanne Koong
5510cf7052aSJoanne Koong bpf_ringbuf_discard_dynptr(&ptr, 0);
5520cf7052aSJoanne Koong
5530cf7052aSJoanne Koong return 0;
5540cf7052aSJoanne Koong }
5550cf7052aSJoanne Koong
5560cf7052aSJoanne Koong /* A direct read at an offset should fail */
5575653f55eSJoanne Koong SEC("?raw_tp")
55826c386ecSAndrii Nakryiko __failure __msg("cannot pass in dynptr at an offset")
invalid_read2(void * ctx)5590cf7052aSJoanne Koong int invalid_read2(void *ctx)
5600cf7052aSJoanne Koong {
5610cf7052aSJoanne Koong struct bpf_dynptr ptr;
5620cf7052aSJoanne Koong char read_data[64];
5630cf7052aSJoanne Koong
5640cf7052aSJoanne Koong get_map_val_dynptr(&ptr);
5650cf7052aSJoanne Koong
5660cf7052aSJoanne Koong /* this should fail */
567f8d3da4eSJoanne Koong bpf_dynptr_read(read_data, sizeof(read_data), (void *)&ptr + 1, 0, 0);
5680cf7052aSJoanne Koong
5690cf7052aSJoanne Koong return 0;
5700cf7052aSJoanne Koong }
5710cf7052aSJoanne Koong
5720cf7052aSJoanne Koong /* A direct read at an offset into the lower stack slot should fail */
5735653f55eSJoanne Koong SEC("?raw_tp")
57426c386ecSAndrii Nakryiko __failure __msg("invalid read from stack")
invalid_read3(void * ctx)5750cf7052aSJoanne Koong int invalid_read3(void *ctx)
5760cf7052aSJoanne Koong {
5770cf7052aSJoanne Koong struct bpf_dynptr ptr1, ptr2;
5780cf7052aSJoanne Koong
5790cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr1);
5800cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr2);
5810cf7052aSJoanne Koong
5820cf7052aSJoanne Koong /* this should fail */
5830cf7052aSJoanne Koong memcpy(&val, (void *)&ptr1 + 8, sizeof(val));
5840cf7052aSJoanne Koong
5850cf7052aSJoanne Koong bpf_ringbuf_discard_dynptr(&ptr1, 0);
5860cf7052aSJoanne Koong bpf_ringbuf_discard_dynptr(&ptr2, 0);
5870cf7052aSJoanne Koong
5880cf7052aSJoanne Koong return 0;
5890cf7052aSJoanne Koong }
5900cf7052aSJoanne Koong
invalid_read4_callback(__u32 index,void * data)5910cf7052aSJoanne Koong static int invalid_read4_callback(__u32 index, void *data)
5920cf7052aSJoanne Koong {
5930cf7052aSJoanne Koong /* this should fail */
5940cf7052aSJoanne Koong val = *(__u32 *)data;
5950cf7052aSJoanne Koong
5960cf7052aSJoanne Koong return 0;
5970cf7052aSJoanne Koong }
5980cf7052aSJoanne Koong
5990cf7052aSJoanne Koong /* A direct read within a callback function should fail */
6005653f55eSJoanne Koong SEC("?raw_tp")
60126c386ecSAndrii Nakryiko __failure __msg("invalid read from stack")
invalid_read4(void * ctx)6020cf7052aSJoanne Koong int invalid_read4(void *ctx)
6030cf7052aSJoanne Koong {
6040cf7052aSJoanne Koong struct bpf_dynptr ptr;
6050cf7052aSJoanne Koong
6060cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr);
6070cf7052aSJoanne Koong
6080cf7052aSJoanne Koong bpf_loop(10, invalid_read4_callback, &ptr, 0);
6090cf7052aSJoanne Koong
6100cf7052aSJoanne Koong bpf_ringbuf_submit_dynptr(&ptr, 0);
6110cf7052aSJoanne Koong
6120cf7052aSJoanne Koong return 0;
6130cf7052aSJoanne Koong }
6140cf7052aSJoanne Koong
6150cf7052aSJoanne Koong /* Initializing a dynptr on an offset should fail */
6165653f55eSJoanne Koong SEC("?raw_tp")
61779168a66SKumar Kartikeya Dwivedi __failure __msg("cannot pass in dynptr at an offset=0")
invalid_offset(void * ctx)6180cf7052aSJoanne Koong int invalid_offset(void *ctx)
6190cf7052aSJoanne Koong {
6200cf7052aSJoanne Koong struct bpf_dynptr ptr;
6210cf7052aSJoanne Koong
6220cf7052aSJoanne Koong /* this should fail */
6230cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr + 1);
6240cf7052aSJoanne Koong
6250cf7052aSJoanne Koong bpf_ringbuf_discard_dynptr(&ptr, 0);
6260cf7052aSJoanne Koong
6270cf7052aSJoanne Koong return 0;
6280cf7052aSJoanne Koong }
6290cf7052aSJoanne Koong
6300cf7052aSJoanne Koong /* Can't release a dynptr twice */
6315653f55eSJoanne Koong SEC("?raw_tp")
63226c386ecSAndrii Nakryiko __failure __msg("arg 1 is an unacquired reference")
release_twice(void * ctx)6330cf7052aSJoanne Koong int release_twice(void *ctx)
6340cf7052aSJoanne Koong {
6350cf7052aSJoanne Koong struct bpf_dynptr ptr;
6360cf7052aSJoanne Koong
6370cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, 16, 0, &ptr);
6380cf7052aSJoanne Koong
6390cf7052aSJoanne Koong bpf_ringbuf_discard_dynptr(&ptr, 0);
6400cf7052aSJoanne Koong
6410cf7052aSJoanne Koong /* this second release should fail */
6420cf7052aSJoanne Koong bpf_ringbuf_discard_dynptr(&ptr, 0);
6430cf7052aSJoanne Koong
6440cf7052aSJoanne Koong return 0;
6450cf7052aSJoanne Koong }
6460cf7052aSJoanne Koong
release_twice_callback_fn(__u32 index,void * data)6470cf7052aSJoanne Koong static int release_twice_callback_fn(__u32 index, void *data)
6480cf7052aSJoanne Koong {
6490cf7052aSJoanne Koong /* this should fail */
6500cf7052aSJoanne Koong bpf_ringbuf_discard_dynptr(data, 0);
6510cf7052aSJoanne Koong
6520cf7052aSJoanne Koong return 0;
6530cf7052aSJoanne Koong }
6540cf7052aSJoanne Koong
6550cf7052aSJoanne Koong /* Test that releasing a dynptr twice, where one of the releases happens
656df71a42cSTaichi Nishimura * within a callback function, fails
6570cf7052aSJoanne Koong */
6585653f55eSJoanne Koong SEC("?raw_tp")
65926c386ecSAndrii Nakryiko __failure __msg("arg 1 is an unacquired reference")
release_twice_callback(void * ctx)6600cf7052aSJoanne Koong int release_twice_callback(void *ctx)
6610cf7052aSJoanne Koong {
6620cf7052aSJoanne Koong struct bpf_dynptr ptr;
6630cf7052aSJoanne Koong
6640cf7052aSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, 32, 0, &ptr);
6650cf7052aSJoanne Koong
6660cf7052aSJoanne Koong bpf_ringbuf_discard_dynptr(&ptr, 0);
6670cf7052aSJoanne Koong
6680cf7052aSJoanne Koong bpf_loop(10, release_twice_callback_fn, &ptr, 0);
6690cf7052aSJoanne Koong
6700cf7052aSJoanne Koong return 0;
6710cf7052aSJoanne Koong }
6720cf7052aSJoanne Koong
6730cf7052aSJoanne Koong /* Reject unsupported local mem types for dynptr_from_mem API */
6745653f55eSJoanne Koong SEC("?raw_tp")
67526c386ecSAndrii Nakryiko __failure __msg("Unsupported reg type fp for bpf_dynptr_from_mem data")
dynptr_from_mem_invalid_api(void * ctx)6760cf7052aSJoanne Koong int dynptr_from_mem_invalid_api(void *ctx)
6770cf7052aSJoanne Koong {
6780cf7052aSJoanne Koong struct bpf_dynptr ptr;
6790cf7052aSJoanne Koong int x = 0;
6800cf7052aSJoanne Koong
6810cf7052aSJoanne Koong /* this should fail */
6820cf7052aSJoanne Koong bpf_dynptr_from_mem(&x, sizeof(x), 0, &ptr);
6830cf7052aSJoanne Koong
6840cf7052aSJoanne Koong return 0;
6850cf7052aSJoanne Koong }
686f4d24edfSKumar Kartikeya Dwivedi
687f4d24edfSKumar Kartikeya Dwivedi SEC("?tc")
688f4d24edfSKumar Kartikeya Dwivedi __failure __msg("cannot overwrite referenced dynptr") __log_level(2)
dynptr_pruning_overwrite(struct __sk_buff * ctx)689f4d24edfSKumar Kartikeya Dwivedi int dynptr_pruning_overwrite(struct __sk_buff *ctx)
690f4d24edfSKumar Kartikeya Dwivedi {
691f4d24edfSKumar Kartikeya Dwivedi asm volatile (
692f4d24edfSKumar Kartikeya Dwivedi "r9 = 0xeB9F; \
693f4d24edfSKumar Kartikeya Dwivedi r6 = %[ringbuf] ll; \
694f4d24edfSKumar Kartikeya Dwivedi r1 = r6; \
695f4d24edfSKumar Kartikeya Dwivedi r2 = 8; \
696f4d24edfSKumar Kartikeya Dwivedi r3 = 0; \
697f4d24edfSKumar Kartikeya Dwivedi r4 = r10; \
698f4d24edfSKumar Kartikeya Dwivedi r4 += -16; \
699f4d24edfSKumar Kartikeya Dwivedi call %[bpf_ringbuf_reserve_dynptr]; \
700f4d24edfSKumar Kartikeya Dwivedi if r0 == 0 goto pjmp1; \
701f4d24edfSKumar Kartikeya Dwivedi goto pjmp2; \
702f4d24edfSKumar Kartikeya Dwivedi pjmp1: \
703f4d24edfSKumar Kartikeya Dwivedi *(u64 *)(r10 - 16) = r9; \
704f4d24edfSKumar Kartikeya Dwivedi pjmp2: \
705f4d24edfSKumar Kartikeya Dwivedi r1 = r10; \
706f4d24edfSKumar Kartikeya Dwivedi r1 += -16; \
707f4d24edfSKumar Kartikeya Dwivedi r2 = 0; \
708f4d24edfSKumar Kartikeya Dwivedi call %[bpf_ringbuf_discard_dynptr]; "
709f4d24edfSKumar Kartikeya Dwivedi :
710f4d24edfSKumar Kartikeya Dwivedi : __imm(bpf_ringbuf_reserve_dynptr),
711f4d24edfSKumar Kartikeya Dwivedi __imm(bpf_ringbuf_discard_dynptr),
712f4d24edfSKumar Kartikeya Dwivedi __imm_addr(ringbuf)
713f4d24edfSKumar Kartikeya Dwivedi : __clobber_all
714f4d24edfSKumar Kartikeya Dwivedi );
715f4d24edfSKumar Kartikeya Dwivedi return 0;
716f4d24edfSKumar Kartikeya Dwivedi }
717f4d24edfSKumar Kartikeya Dwivedi
718f4d24edfSKumar Kartikeya Dwivedi SEC("?tc")
719f4d24edfSKumar Kartikeya Dwivedi __success __msg("12: safe") __log_level(2)
dynptr_pruning_stacksafe(struct __sk_buff * ctx)720f4d24edfSKumar Kartikeya Dwivedi int dynptr_pruning_stacksafe(struct __sk_buff *ctx)
721f4d24edfSKumar Kartikeya Dwivedi {
722f4d24edfSKumar Kartikeya Dwivedi asm volatile (
723f4d24edfSKumar Kartikeya Dwivedi "r9 = 0xeB9F; \
724f4d24edfSKumar Kartikeya Dwivedi r6 = %[ringbuf] ll; \
725f4d24edfSKumar Kartikeya Dwivedi r1 = r6; \
726f4d24edfSKumar Kartikeya Dwivedi r2 = 8; \
727f4d24edfSKumar Kartikeya Dwivedi r3 = 0; \
728f4d24edfSKumar Kartikeya Dwivedi r4 = r10; \
729f4d24edfSKumar Kartikeya Dwivedi r4 += -16; \
730f4d24edfSKumar Kartikeya Dwivedi call %[bpf_ringbuf_reserve_dynptr]; \
731f4d24edfSKumar Kartikeya Dwivedi if r0 == 0 goto stjmp1; \
732f4d24edfSKumar Kartikeya Dwivedi goto stjmp2; \
733f4d24edfSKumar Kartikeya Dwivedi stjmp1: \
734f4d24edfSKumar Kartikeya Dwivedi r9 = r9; \
735f4d24edfSKumar Kartikeya Dwivedi stjmp2: \
736f4d24edfSKumar Kartikeya Dwivedi r1 = r10; \
737f4d24edfSKumar Kartikeya Dwivedi r1 += -16; \
738f4d24edfSKumar Kartikeya Dwivedi r2 = 0; \
739f4d24edfSKumar Kartikeya Dwivedi call %[bpf_ringbuf_discard_dynptr]; "
740f4d24edfSKumar Kartikeya Dwivedi :
741f4d24edfSKumar Kartikeya Dwivedi : __imm(bpf_ringbuf_reserve_dynptr),
742f4d24edfSKumar Kartikeya Dwivedi __imm(bpf_ringbuf_discard_dynptr),
743f4d24edfSKumar Kartikeya Dwivedi __imm_addr(ringbuf)
744f4d24edfSKumar Kartikeya Dwivedi : __clobber_all
745f4d24edfSKumar Kartikeya Dwivedi );
746f4d24edfSKumar Kartikeya Dwivedi return 0;
747f4d24edfSKumar Kartikeya Dwivedi }
748f4d24edfSKumar Kartikeya Dwivedi
749f4d24edfSKumar Kartikeya Dwivedi SEC("?tc")
750f4d24edfSKumar Kartikeya Dwivedi __failure __msg("cannot overwrite referenced dynptr") __log_level(2)
dynptr_pruning_type_confusion(struct __sk_buff * ctx)751f4d24edfSKumar Kartikeya Dwivedi int dynptr_pruning_type_confusion(struct __sk_buff *ctx)
752f4d24edfSKumar Kartikeya Dwivedi {
753f4d24edfSKumar Kartikeya Dwivedi asm volatile (
754f4d24edfSKumar Kartikeya Dwivedi "r6 = %[array_map4] ll; \
755f4d24edfSKumar Kartikeya Dwivedi r7 = %[ringbuf] ll; \
756f4d24edfSKumar Kartikeya Dwivedi r1 = r6; \
757f4d24edfSKumar Kartikeya Dwivedi r2 = r10; \
758f4d24edfSKumar Kartikeya Dwivedi r2 += -8; \
759f4d24edfSKumar Kartikeya Dwivedi r9 = 0; \
760f4d24edfSKumar Kartikeya Dwivedi *(u64 *)(r2 + 0) = r9; \
761f4d24edfSKumar Kartikeya Dwivedi r3 = r10; \
762f4d24edfSKumar Kartikeya Dwivedi r3 += -24; \
763f4d24edfSKumar Kartikeya Dwivedi r9 = 0xeB9FeB9F; \
764f4d24edfSKumar Kartikeya Dwivedi *(u64 *)(r10 - 16) = r9; \
765f4d24edfSKumar Kartikeya Dwivedi *(u64 *)(r10 - 24) = r9; \
766f4d24edfSKumar Kartikeya Dwivedi r9 = 0; \
767f4d24edfSKumar Kartikeya Dwivedi r4 = 0; \
768f4d24edfSKumar Kartikeya Dwivedi r8 = r2; \
769f4d24edfSKumar Kartikeya Dwivedi call %[bpf_map_update_elem]; \
770f4d24edfSKumar Kartikeya Dwivedi r1 = r6; \
771f4d24edfSKumar Kartikeya Dwivedi r2 = r8; \
772f4d24edfSKumar Kartikeya Dwivedi call %[bpf_map_lookup_elem]; \
773f4d24edfSKumar Kartikeya Dwivedi if r0 != 0 goto tjmp1; \
774f4d24edfSKumar Kartikeya Dwivedi exit; \
775f4d24edfSKumar Kartikeya Dwivedi tjmp1: \
776f4d24edfSKumar Kartikeya Dwivedi r8 = r0; \
777f4d24edfSKumar Kartikeya Dwivedi r1 = r7; \
778f4d24edfSKumar Kartikeya Dwivedi r2 = 8; \
779f4d24edfSKumar Kartikeya Dwivedi r3 = 0; \
780f4d24edfSKumar Kartikeya Dwivedi r4 = r10; \
781f4d24edfSKumar Kartikeya Dwivedi r4 += -16; \
782f4d24edfSKumar Kartikeya Dwivedi r0 = *(u64 *)(r0 + 0); \
783f4d24edfSKumar Kartikeya Dwivedi call %[bpf_ringbuf_reserve_dynptr]; \
784f4d24edfSKumar Kartikeya Dwivedi if r0 == 0 goto tjmp2; \
785f4d24edfSKumar Kartikeya Dwivedi r8 = r8; \
786f4d24edfSKumar Kartikeya Dwivedi r8 = r8; \
787f4d24edfSKumar Kartikeya Dwivedi r8 = r8; \
788f4d24edfSKumar Kartikeya Dwivedi r8 = r8; \
789f4d24edfSKumar Kartikeya Dwivedi r8 = r8; \
790f4d24edfSKumar Kartikeya Dwivedi r8 = r8; \
791f4d24edfSKumar Kartikeya Dwivedi r8 = r8; \
792f4d24edfSKumar Kartikeya Dwivedi goto tjmp3; \
793f4d24edfSKumar Kartikeya Dwivedi tjmp2: \
794f4d24edfSKumar Kartikeya Dwivedi *(u64 *)(r10 - 8) = r9; \
795f4d24edfSKumar Kartikeya Dwivedi *(u64 *)(r10 - 16) = r9; \
796f4d24edfSKumar Kartikeya Dwivedi r1 = r8; \
797f4d24edfSKumar Kartikeya Dwivedi r1 += 8; \
798f4d24edfSKumar Kartikeya Dwivedi r2 = 0; \
799f4d24edfSKumar Kartikeya Dwivedi r3 = 0; \
800f4d24edfSKumar Kartikeya Dwivedi r4 = r10; \
801f4d24edfSKumar Kartikeya Dwivedi r4 += -16; \
802f4d24edfSKumar Kartikeya Dwivedi call %[bpf_dynptr_from_mem]; \
803f4d24edfSKumar Kartikeya Dwivedi tjmp3: \
804f4d24edfSKumar Kartikeya Dwivedi r1 = r10; \
805f4d24edfSKumar Kartikeya Dwivedi r1 += -16; \
806f4d24edfSKumar Kartikeya Dwivedi r2 = 0; \
807f4d24edfSKumar Kartikeya Dwivedi call %[bpf_ringbuf_discard_dynptr]; "
808f4d24edfSKumar Kartikeya Dwivedi :
809f4d24edfSKumar Kartikeya Dwivedi : __imm(bpf_map_update_elem),
810f4d24edfSKumar Kartikeya Dwivedi __imm(bpf_map_lookup_elem),
811f4d24edfSKumar Kartikeya Dwivedi __imm(bpf_ringbuf_reserve_dynptr),
812f4d24edfSKumar Kartikeya Dwivedi __imm(bpf_dynptr_from_mem),
813f4d24edfSKumar Kartikeya Dwivedi __imm(bpf_ringbuf_discard_dynptr),
814f4d24edfSKumar Kartikeya Dwivedi __imm_addr(array_map4),
815f4d24edfSKumar Kartikeya Dwivedi __imm_addr(ringbuf)
816f4d24edfSKumar Kartikeya Dwivedi : __clobber_all
817f4d24edfSKumar Kartikeya Dwivedi );
818f4d24edfSKumar Kartikeya Dwivedi return 0;
819f4d24edfSKumar Kartikeya Dwivedi }
820ef481013SKumar Kartikeya Dwivedi
821ef481013SKumar Kartikeya Dwivedi SEC("?tc")
822ef481013SKumar Kartikeya Dwivedi __failure __msg("dynptr has to be at a constant offset") __log_level(2)
dynptr_var_off_overwrite(struct __sk_buff * ctx)823ef481013SKumar Kartikeya Dwivedi int dynptr_var_off_overwrite(struct __sk_buff *ctx)
824ef481013SKumar Kartikeya Dwivedi {
825ef481013SKumar Kartikeya Dwivedi asm volatile (
826ef481013SKumar Kartikeya Dwivedi "r9 = 16; \
827ef481013SKumar Kartikeya Dwivedi *(u32 *)(r10 - 4) = r9; \
828ef481013SKumar Kartikeya Dwivedi r8 = *(u32 *)(r10 - 4); \
829ef481013SKumar Kartikeya Dwivedi if r8 >= 0 goto vjmp1; \
830ef481013SKumar Kartikeya Dwivedi r0 = 1; \
831ef481013SKumar Kartikeya Dwivedi exit; \
832ef481013SKumar Kartikeya Dwivedi vjmp1: \
833ef481013SKumar Kartikeya Dwivedi if r8 <= 16 goto vjmp2; \
834ef481013SKumar Kartikeya Dwivedi r0 = 1; \
835ef481013SKumar Kartikeya Dwivedi exit; \
836ef481013SKumar Kartikeya Dwivedi vjmp2: \
837ef481013SKumar Kartikeya Dwivedi r8 &= 16; \
838ef481013SKumar Kartikeya Dwivedi r1 = %[ringbuf] ll; \
839ef481013SKumar Kartikeya Dwivedi r2 = 8; \
840ef481013SKumar Kartikeya Dwivedi r3 = 0; \
841ef481013SKumar Kartikeya Dwivedi r4 = r10; \
842ef481013SKumar Kartikeya Dwivedi r4 += -32; \
843ef481013SKumar Kartikeya Dwivedi r4 += r8; \
844ef481013SKumar Kartikeya Dwivedi call %[bpf_ringbuf_reserve_dynptr]; \
845ef481013SKumar Kartikeya Dwivedi r9 = 0xeB9F; \
846ef481013SKumar Kartikeya Dwivedi *(u64 *)(r10 - 16) = r9; \
847ef481013SKumar Kartikeya Dwivedi r1 = r10; \
848ef481013SKumar Kartikeya Dwivedi r1 += -32; \
849ef481013SKumar Kartikeya Dwivedi r1 += r8; \
850ef481013SKumar Kartikeya Dwivedi r2 = 0; \
851ef481013SKumar Kartikeya Dwivedi call %[bpf_ringbuf_discard_dynptr]; "
852ef481013SKumar Kartikeya Dwivedi :
853ef481013SKumar Kartikeya Dwivedi : __imm(bpf_ringbuf_reserve_dynptr),
854ef481013SKumar Kartikeya Dwivedi __imm(bpf_ringbuf_discard_dynptr),
855ef481013SKumar Kartikeya Dwivedi __imm_addr(ringbuf)
856ef481013SKumar Kartikeya Dwivedi : __clobber_all
857ef481013SKumar Kartikeya Dwivedi );
858ef481013SKumar Kartikeya Dwivedi return 0;
859ef481013SKumar Kartikeya Dwivedi }
860011edc8eSKumar Kartikeya Dwivedi
861011edc8eSKumar Kartikeya Dwivedi SEC("?tc")
862011edc8eSKumar Kartikeya Dwivedi __failure __msg("cannot overwrite referenced dynptr") __log_level(2)
dynptr_partial_slot_invalidate(struct __sk_buff * ctx)863011edc8eSKumar Kartikeya Dwivedi int dynptr_partial_slot_invalidate(struct __sk_buff *ctx)
864011edc8eSKumar Kartikeya Dwivedi {
865011edc8eSKumar Kartikeya Dwivedi asm volatile (
866011edc8eSKumar Kartikeya Dwivedi "r6 = %[ringbuf] ll; \
867011edc8eSKumar Kartikeya Dwivedi r7 = %[array_map4] ll; \
868011edc8eSKumar Kartikeya Dwivedi r1 = r7; \
869011edc8eSKumar Kartikeya Dwivedi r2 = r10; \
870011edc8eSKumar Kartikeya Dwivedi r2 += -8; \
871011edc8eSKumar Kartikeya Dwivedi r9 = 0; \
872011edc8eSKumar Kartikeya Dwivedi *(u64 *)(r2 + 0) = r9; \
873011edc8eSKumar Kartikeya Dwivedi r3 = r2; \
874011edc8eSKumar Kartikeya Dwivedi r4 = 0; \
875011edc8eSKumar Kartikeya Dwivedi r8 = r2; \
876011edc8eSKumar Kartikeya Dwivedi call %[bpf_map_update_elem]; \
877011edc8eSKumar Kartikeya Dwivedi r1 = r7; \
878011edc8eSKumar Kartikeya Dwivedi r2 = r8; \
879011edc8eSKumar Kartikeya Dwivedi call %[bpf_map_lookup_elem]; \
880011edc8eSKumar Kartikeya Dwivedi if r0 != 0 goto sjmp1; \
881011edc8eSKumar Kartikeya Dwivedi exit; \
882011edc8eSKumar Kartikeya Dwivedi sjmp1: \
883011edc8eSKumar Kartikeya Dwivedi r7 = r0; \
884011edc8eSKumar Kartikeya Dwivedi r1 = r6; \
885011edc8eSKumar Kartikeya Dwivedi r2 = 8; \
886011edc8eSKumar Kartikeya Dwivedi r3 = 0; \
887011edc8eSKumar Kartikeya Dwivedi r4 = r10; \
888011edc8eSKumar Kartikeya Dwivedi r4 += -24; \
889011edc8eSKumar Kartikeya Dwivedi call %[bpf_ringbuf_reserve_dynptr]; \
890011edc8eSKumar Kartikeya Dwivedi *(u64 *)(r10 - 16) = r9; \
891011edc8eSKumar Kartikeya Dwivedi r1 = r7; \
892011edc8eSKumar Kartikeya Dwivedi r2 = 8; \
893011edc8eSKumar Kartikeya Dwivedi r3 = 0; \
894011edc8eSKumar Kartikeya Dwivedi r4 = r10; \
895011edc8eSKumar Kartikeya Dwivedi r4 += -16; \
896011edc8eSKumar Kartikeya Dwivedi call %[bpf_dynptr_from_mem]; \
897011edc8eSKumar Kartikeya Dwivedi r1 = r10; \
898011edc8eSKumar Kartikeya Dwivedi r1 += -512; \
899011edc8eSKumar Kartikeya Dwivedi r2 = 488; \
900011edc8eSKumar Kartikeya Dwivedi r3 = r10; \
901011edc8eSKumar Kartikeya Dwivedi r3 += -24; \
902011edc8eSKumar Kartikeya Dwivedi r4 = 0; \
903011edc8eSKumar Kartikeya Dwivedi r5 = 0; \
904011edc8eSKumar Kartikeya Dwivedi call %[bpf_dynptr_read]; \
905011edc8eSKumar Kartikeya Dwivedi r8 = 1; \
906011edc8eSKumar Kartikeya Dwivedi if r0 != 0 goto sjmp2; \
907011edc8eSKumar Kartikeya Dwivedi r8 = 0; \
908011edc8eSKumar Kartikeya Dwivedi sjmp2: \
909011edc8eSKumar Kartikeya Dwivedi r1 = r10; \
910011edc8eSKumar Kartikeya Dwivedi r1 += -24; \
911011edc8eSKumar Kartikeya Dwivedi r2 = 0; \
912011edc8eSKumar Kartikeya Dwivedi call %[bpf_ringbuf_discard_dynptr]; "
913011edc8eSKumar Kartikeya Dwivedi :
914011edc8eSKumar Kartikeya Dwivedi : __imm(bpf_map_update_elem),
915011edc8eSKumar Kartikeya Dwivedi __imm(bpf_map_lookup_elem),
916011edc8eSKumar Kartikeya Dwivedi __imm(bpf_ringbuf_reserve_dynptr),
917011edc8eSKumar Kartikeya Dwivedi __imm(bpf_ringbuf_discard_dynptr),
918011edc8eSKumar Kartikeya Dwivedi __imm(bpf_dynptr_from_mem),
919011edc8eSKumar Kartikeya Dwivedi __imm(bpf_dynptr_read),
920011edc8eSKumar Kartikeya Dwivedi __imm_addr(ringbuf),
921011edc8eSKumar Kartikeya Dwivedi __imm_addr(array_map4)
922011edc8eSKumar Kartikeya Dwivedi : __clobber_all
923011edc8eSKumar Kartikeya Dwivedi );
924011edc8eSKumar Kartikeya Dwivedi return 0;
925011edc8eSKumar Kartikeya Dwivedi }
926ae8e354cSKumar Kartikeya Dwivedi
927ae8e354cSKumar Kartikeya Dwivedi /* Test that it is allowed to overwrite unreferenced dynptr. */
928ae8e354cSKumar Kartikeya Dwivedi SEC("?raw_tp")
929ae8e354cSKumar Kartikeya Dwivedi __success
dynptr_overwrite_unref(void * ctx)930ae8e354cSKumar Kartikeya Dwivedi int dynptr_overwrite_unref(void *ctx)
931ae8e354cSKumar Kartikeya Dwivedi {
932ae8e354cSKumar Kartikeya Dwivedi struct bpf_dynptr ptr;
933ae8e354cSKumar Kartikeya Dwivedi
934ae8e354cSKumar Kartikeya Dwivedi if (get_map_val_dynptr(&ptr))
935ae8e354cSKumar Kartikeya Dwivedi return 0;
936ae8e354cSKumar Kartikeya Dwivedi if (get_map_val_dynptr(&ptr))
937ae8e354cSKumar Kartikeya Dwivedi return 0;
938ae8e354cSKumar Kartikeya Dwivedi if (get_map_val_dynptr(&ptr))
939ae8e354cSKumar Kartikeya Dwivedi return 0;
940ae8e354cSKumar Kartikeya Dwivedi
941ae8e354cSKumar Kartikeya Dwivedi return 0;
942ae8e354cSKumar Kartikeya Dwivedi }
943ae8e354cSKumar Kartikeya Dwivedi
944ae8e354cSKumar Kartikeya Dwivedi /* Test that slices are invalidated on reinitializing a dynptr. */
945ae8e354cSKumar Kartikeya Dwivedi SEC("?raw_tp")
946ae8e354cSKumar Kartikeya Dwivedi __failure __msg("invalid mem access 'scalar'")
dynptr_invalidate_slice_reinit(void * ctx)947ae8e354cSKumar Kartikeya Dwivedi int dynptr_invalidate_slice_reinit(void *ctx)
948ae8e354cSKumar Kartikeya Dwivedi {
949ae8e354cSKumar Kartikeya Dwivedi struct bpf_dynptr ptr;
950ae8e354cSKumar Kartikeya Dwivedi __u8 *p;
951ae8e354cSKumar Kartikeya Dwivedi
952ae8e354cSKumar Kartikeya Dwivedi if (get_map_val_dynptr(&ptr))
953ae8e354cSKumar Kartikeya Dwivedi return 0;
954ae8e354cSKumar Kartikeya Dwivedi p = bpf_dynptr_data(&ptr, 0, 1);
955ae8e354cSKumar Kartikeya Dwivedi if (!p)
956ae8e354cSKumar Kartikeya Dwivedi return 0;
957ae8e354cSKumar Kartikeya Dwivedi if (get_map_val_dynptr(&ptr))
958ae8e354cSKumar Kartikeya Dwivedi return 0;
959ae8e354cSKumar Kartikeya Dwivedi /* this should fail */
960ae8e354cSKumar Kartikeya Dwivedi return *p;
961ae8e354cSKumar Kartikeya Dwivedi }
962ae8e354cSKumar Kartikeya Dwivedi
963ae8e354cSKumar Kartikeya Dwivedi /* Invalidation of dynptr slices on destruction of dynptr should not miss
964ae8e354cSKumar Kartikeya Dwivedi * mem_or_null pointers.
965ae8e354cSKumar Kartikeya Dwivedi */
966ae8e354cSKumar Kartikeya Dwivedi SEC("?raw_tp")
967ae8e354cSKumar Kartikeya Dwivedi __failure __msg("R1 type=scalar expected=percpu_ptr_")
dynptr_invalidate_slice_or_null(void * ctx)968ae8e354cSKumar Kartikeya Dwivedi int dynptr_invalidate_slice_or_null(void *ctx)
969ae8e354cSKumar Kartikeya Dwivedi {
970ae8e354cSKumar Kartikeya Dwivedi struct bpf_dynptr ptr;
971ae8e354cSKumar Kartikeya Dwivedi __u8 *p;
972ae8e354cSKumar Kartikeya Dwivedi
973ae8e354cSKumar Kartikeya Dwivedi if (get_map_val_dynptr(&ptr))
974ae8e354cSKumar Kartikeya Dwivedi return 0;
975ae8e354cSKumar Kartikeya Dwivedi
976ae8e354cSKumar Kartikeya Dwivedi p = bpf_dynptr_data(&ptr, 0, 1);
977ae8e354cSKumar Kartikeya Dwivedi *(__u8 *)&ptr = 0;
978ae8e354cSKumar Kartikeya Dwivedi /* this should fail */
979ae8e354cSKumar Kartikeya Dwivedi bpf_this_cpu_ptr(p);
980ae8e354cSKumar Kartikeya Dwivedi return 0;
981ae8e354cSKumar Kartikeya Dwivedi }
982ae8e354cSKumar Kartikeya Dwivedi
983ae8e354cSKumar Kartikeya Dwivedi /* Destruction of dynptr should also any slices obtained from it */
984ae8e354cSKumar Kartikeya Dwivedi SEC("?raw_tp")
985ae8e354cSKumar Kartikeya Dwivedi __failure __msg("R7 invalid mem access 'scalar'")
dynptr_invalidate_slice_failure(void * ctx)986ae8e354cSKumar Kartikeya Dwivedi int dynptr_invalidate_slice_failure(void *ctx)
987ae8e354cSKumar Kartikeya Dwivedi {
988ae8e354cSKumar Kartikeya Dwivedi struct bpf_dynptr ptr1;
989ae8e354cSKumar Kartikeya Dwivedi struct bpf_dynptr ptr2;
990ae8e354cSKumar Kartikeya Dwivedi __u8 *p1, *p2;
991ae8e354cSKumar Kartikeya Dwivedi
992ae8e354cSKumar Kartikeya Dwivedi if (get_map_val_dynptr(&ptr1))
993ae8e354cSKumar Kartikeya Dwivedi return 0;
994ae8e354cSKumar Kartikeya Dwivedi if (get_map_val_dynptr(&ptr2))
995ae8e354cSKumar Kartikeya Dwivedi return 0;
996ae8e354cSKumar Kartikeya Dwivedi
997ae8e354cSKumar Kartikeya Dwivedi p1 = bpf_dynptr_data(&ptr1, 0, 1);
998ae8e354cSKumar Kartikeya Dwivedi if (!p1)
999ae8e354cSKumar Kartikeya Dwivedi return 0;
1000ae8e354cSKumar Kartikeya Dwivedi p2 = bpf_dynptr_data(&ptr2, 0, 1);
1001ae8e354cSKumar Kartikeya Dwivedi if (!p2)
1002ae8e354cSKumar Kartikeya Dwivedi return 0;
1003ae8e354cSKumar Kartikeya Dwivedi
1004ae8e354cSKumar Kartikeya Dwivedi *(__u8 *)&ptr1 = 0;
1005ae8e354cSKumar Kartikeya Dwivedi /* this should fail */
1006ae8e354cSKumar Kartikeya Dwivedi return *p1;
1007ae8e354cSKumar Kartikeya Dwivedi }
1008ae8e354cSKumar Kartikeya Dwivedi
1009ae8e354cSKumar Kartikeya Dwivedi /* Invalidation of slices should be scoped and should not prevent dereferencing
1010ae8e354cSKumar Kartikeya Dwivedi * slices of another dynptr after destroying unrelated dynptr
1011ae8e354cSKumar Kartikeya Dwivedi */
1012ae8e354cSKumar Kartikeya Dwivedi SEC("?raw_tp")
1013ae8e354cSKumar Kartikeya Dwivedi __success
dynptr_invalidate_slice_success(void * ctx)1014ae8e354cSKumar Kartikeya Dwivedi int dynptr_invalidate_slice_success(void *ctx)
1015ae8e354cSKumar Kartikeya Dwivedi {
1016ae8e354cSKumar Kartikeya Dwivedi struct bpf_dynptr ptr1;
1017ae8e354cSKumar Kartikeya Dwivedi struct bpf_dynptr ptr2;
1018ae8e354cSKumar Kartikeya Dwivedi __u8 *p1, *p2;
1019ae8e354cSKumar Kartikeya Dwivedi
1020ae8e354cSKumar Kartikeya Dwivedi if (get_map_val_dynptr(&ptr1))
1021ae8e354cSKumar Kartikeya Dwivedi return 1;
1022ae8e354cSKumar Kartikeya Dwivedi if (get_map_val_dynptr(&ptr2))
1023ae8e354cSKumar Kartikeya Dwivedi return 1;
1024ae8e354cSKumar Kartikeya Dwivedi
1025ae8e354cSKumar Kartikeya Dwivedi p1 = bpf_dynptr_data(&ptr1, 0, 1);
1026ae8e354cSKumar Kartikeya Dwivedi if (!p1)
1027ae8e354cSKumar Kartikeya Dwivedi return 1;
1028ae8e354cSKumar Kartikeya Dwivedi p2 = bpf_dynptr_data(&ptr2, 0, 1);
1029ae8e354cSKumar Kartikeya Dwivedi if (!p2)
1030ae8e354cSKumar Kartikeya Dwivedi return 1;
1031ae8e354cSKumar Kartikeya Dwivedi
1032ae8e354cSKumar Kartikeya Dwivedi *(__u8 *)&ptr1 = 0;
1033ae8e354cSKumar Kartikeya Dwivedi return *p2;
1034ae8e354cSKumar Kartikeya Dwivedi }
1035ae8e354cSKumar Kartikeya Dwivedi
1036ae8e354cSKumar Kartikeya Dwivedi /* Overwriting referenced dynptr should be rejected */
1037ae8e354cSKumar Kartikeya Dwivedi SEC("?raw_tp")
1038ae8e354cSKumar Kartikeya Dwivedi __failure __msg("cannot overwrite referenced dynptr")
dynptr_overwrite_ref(void * ctx)1039ae8e354cSKumar Kartikeya Dwivedi int dynptr_overwrite_ref(void *ctx)
1040ae8e354cSKumar Kartikeya Dwivedi {
1041ae8e354cSKumar Kartikeya Dwivedi struct bpf_dynptr ptr;
1042ae8e354cSKumar Kartikeya Dwivedi
1043ae8e354cSKumar Kartikeya Dwivedi bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &ptr);
1044ae8e354cSKumar Kartikeya Dwivedi /* this should fail */
1045ae8e354cSKumar Kartikeya Dwivedi if (get_map_val_dynptr(&ptr))
1046ae8e354cSKumar Kartikeya Dwivedi bpf_ringbuf_discard_dynptr(&ptr, 0);
1047ae8e354cSKumar Kartikeya Dwivedi return 0;
1048ae8e354cSKumar Kartikeya Dwivedi }
1049ae8e354cSKumar Kartikeya Dwivedi
1050ae8e354cSKumar Kartikeya Dwivedi /* Reject writes to dynptr slot from bpf_dynptr_read */
1051ae8e354cSKumar Kartikeya Dwivedi SEC("?raw_tp")
1052ae8e354cSKumar Kartikeya Dwivedi __failure __msg("potential write to dynptr at off=-16")
dynptr_read_into_slot(void * ctx)1053ae8e354cSKumar Kartikeya Dwivedi int dynptr_read_into_slot(void *ctx)
1054ae8e354cSKumar Kartikeya Dwivedi {
1055ae8e354cSKumar Kartikeya Dwivedi union {
1056ae8e354cSKumar Kartikeya Dwivedi struct {
1057ae8e354cSKumar Kartikeya Dwivedi char _pad[48];
1058ae8e354cSKumar Kartikeya Dwivedi struct bpf_dynptr ptr;
1059ae8e354cSKumar Kartikeya Dwivedi };
1060ae8e354cSKumar Kartikeya Dwivedi char buf[64];
1061ae8e354cSKumar Kartikeya Dwivedi } data;
1062ae8e354cSKumar Kartikeya Dwivedi
1063ae8e354cSKumar Kartikeya Dwivedi bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &data.ptr);
1064ae8e354cSKumar Kartikeya Dwivedi /* this should fail */
1065ae8e354cSKumar Kartikeya Dwivedi bpf_dynptr_read(data.buf, sizeof(data.buf), &data.ptr, 0, 0);
1066ae8e354cSKumar Kartikeya Dwivedi
1067ae8e354cSKumar Kartikeya Dwivedi return 0;
1068ae8e354cSKumar Kartikeya Dwivedi }
1069ae8e354cSKumar Kartikeya Dwivedi
1070cfa7b011SJoanne Koong /* bpf_dynptr_slice()s are read-only and cannot be written to */
1071cfa7b011SJoanne Koong SEC("?tc")
1072cfa7b011SJoanne Koong __failure __msg("R0 cannot write into rdonly_mem")
skb_invalid_slice_write(struct __sk_buff * skb)1073cfa7b011SJoanne Koong int skb_invalid_slice_write(struct __sk_buff *skb)
1074cfa7b011SJoanne Koong {
1075cfa7b011SJoanne Koong struct bpf_dynptr ptr;
1076cfa7b011SJoanne Koong struct ethhdr *hdr;
1077cfa7b011SJoanne Koong char buffer[sizeof(*hdr)] = {};
1078cfa7b011SJoanne Koong
1079cfa7b011SJoanne Koong bpf_dynptr_from_skb(skb, 0, &ptr);
1080cfa7b011SJoanne Koong
1081cfa7b011SJoanne Koong hdr = bpf_dynptr_slice(&ptr, 0, buffer, sizeof(buffer));
1082cfa7b011SJoanne Koong if (!hdr)
1083cfa7b011SJoanne Koong return SK_DROP;
1084cfa7b011SJoanne Koong
1085cfa7b011SJoanne Koong /* this should fail */
1086cfa7b011SJoanne Koong hdr->h_proto = 1;
1087cfa7b011SJoanne Koong
1088cfa7b011SJoanne Koong return SK_PASS;
1089cfa7b011SJoanne Koong }
1090cfa7b011SJoanne Koong
1091cfa7b011SJoanne Koong /* The read-only data slice is invalidated whenever a helper changes packet data */
1092cfa7b011SJoanne Koong SEC("?tc")
1093cfa7b011SJoanne Koong __failure __msg("invalid mem access 'scalar'")
skb_invalid_data_slice1(struct __sk_buff * skb)1094cfa7b011SJoanne Koong int skb_invalid_data_slice1(struct __sk_buff *skb)
1095cfa7b011SJoanne Koong {
1096cfa7b011SJoanne Koong struct bpf_dynptr ptr;
1097cfa7b011SJoanne Koong struct ethhdr *hdr;
1098cfa7b011SJoanne Koong char buffer[sizeof(*hdr)] = {};
1099cfa7b011SJoanne Koong
1100cfa7b011SJoanne Koong bpf_dynptr_from_skb(skb, 0, &ptr);
1101cfa7b011SJoanne Koong
1102cfa7b011SJoanne Koong hdr = bpf_dynptr_slice(&ptr, 0, buffer, sizeof(buffer));
1103cfa7b011SJoanne Koong if (!hdr)
1104cfa7b011SJoanne Koong return SK_DROP;
1105cfa7b011SJoanne Koong
1106cfa7b011SJoanne Koong val = hdr->h_proto;
1107cfa7b011SJoanne Koong
1108cfa7b011SJoanne Koong if (bpf_skb_pull_data(skb, skb->len))
1109cfa7b011SJoanne Koong return SK_DROP;
1110cfa7b011SJoanne Koong
1111cfa7b011SJoanne Koong /* this should fail */
1112cfa7b011SJoanne Koong val = hdr->h_proto;
1113cfa7b011SJoanne Koong
1114cfa7b011SJoanne Koong return SK_PASS;
1115cfa7b011SJoanne Koong }
1116cfa7b011SJoanne Koong
1117cfa7b011SJoanne Koong /* The read-write data slice is invalidated whenever a helper changes packet data */
1118cfa7b011SJoanne Koong SEC("?tc")
1119cfa7b011SJoanne Koong __failure __msg("invalid mem access 'scalar'")
skb_invalid_data_slice2(struct __sk_buff * skb)1120cfa7b011SJoanne Koong int skb_invalid_data_slice2(struct __sk_buff *skb)
1121cfa7b011SJoanne Koong {
1122cfa7b011SJoanne Koong struct bpf_dynptr ptr;
1123cfa7b011SJoanne Koong struct ethhdr *hdr;
1124cfa7b011SJoanne Koong char buffer[sizeof(*hdr)] = {};
1125cfa7b011SJoanne Koong
1126cfa7b011SJoanne Koong bpf_dynptr_from_skb(skb, 0, &ptr);
1127cfa7b011SJoanne Koong
1128cfa7b011SJoanne Koong hdr = bpf_dynptr_slice_rdwr(&ptr, 0, buffer, sizeof(buffer));
1129cfa7b011SJoanne Koong if (!hdr)
1130cfa7b011SJoanne Koong return SK_DROP;
1131cfa7b011SJoanne Koong
1132cfa7b011SJoanne Koong hdr->h_proto = 123;
1133cfa7b011SJoanne Koong
1134cfa7b011SJoanne Koong if (bpf_skb_pull_data(skb, skb->len))
1135cfa7b011SJoanne Koong return SK_DROP;
1136cfa7b011SJoanne Koong
1137cfa7b011SJoanne Koong /* this should fail */
1138cfa7b011SJoanne Koong hdr->h_proto = 1;
1139cfa7b011SJoanne Koong
1140cfa7b011SJoanne Koong return SK_PASS;
1141cfa7b011SJoanne Koong }
1142cfa7b011SJoanne Koong
1143cfa7b011SJoanne Koong /* The read-only data slice is invalidated whenever bpf_dynptr_write() is called */
1144cfa7b011SJoanne Koong SEC("?tc")
1145cfa7b011SJoanne Koong __failure __msg("invalid mem access 'scalar'")
skb_invalid_data_slice3(struct __sk_buff * skb)1146cfa7b011SJoanne Koong int skb_invalid_data_slice3(struct __sk_buff *skb)
1147cfa7b011SJoanne Koong {
1148cfa7b011SJoanne Koong char write_data[64] = "hello there, world!!";
1149cfa7b011SJoanne Koong struct bpf_dynptr ptr;
1150cfa7b011SJoanne Koong struct ethhdr *hdr;
1151cfa7b011SJoanne Koong char buffer[sizeof(*hdr)] = {};
1152cfa7b011SJoanne Koong
1153cfa7b011SJoanne Koong bpf_dynptr_from_skb(skb, 0, &ptr);
1154cfa7b011SJoanne Koong
1155cfa7b011SJoanne Koong hdr = bpf_dynptr_slice(&ptr, 0, buffer, sizeof(buffer));
1156cfa7b011SJoanne Koong if (!hdr)
1157cfa7b011SJoanne Koong return SK_DROP;
1158cfa7b011SJoanne Koong
1159cfa7b011SJoanne Koong val = hdr->h_proto;
1160cfa7b011SJoanne Koong
1161cfa7b011SJoanne Koong bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0);
1162cfa7b011SJoanne Koong
1163cfa7b011SJoanne Koong /* this should fail */
1164cfa7b011SJoanne Koong val = hdr->h_proto;
1165cfa7b011SJoanne Koong
1166cfa7b011SJoanne Koong return SK_PASS;
1167cfa7b011SJoanne Koong }
1168cfa7b011SJoanne Koong
1169cfa7b011SJoanne Koong /* The read-write data slice is invalidated whenever bpf_dynptr_write() is called */
1170cfa7b011SJoanne Koong SEC("?tc")
1171cfa7b011SJoanne Koong __failure __msg("invalid mem access 'scalar'")
skb_invalid_data_slice4(struct __sk_buff * skb)1172cfa7b011SJoanne Koong int skb_invalid_data_slice4(struct __sk_buff *skb)
1173cfa7b011SJoanne Koong {
1174cfa7b011SJoanne Koong char write_data[64] = "hello there, world!!";
1175cfa7b011SJoanne Koong struct bpf_dynptr ptr;
1176cfa7b011SJoanne Koong struct ethhdr *hdr;
1177cfa7b011SJoanne Koong char buffer[sizeof(*hdr)] = {};
1178cfa7b011SJoanne Koong
1179cfa7b011SJoanne Koong bpf_dynptr_from_skb(skb, 0, &ptr);
1180cfa7b011SJoanne Koong hdr = bpf_dynptr_slice_rdwr(&ptr, 0, buffer, sizeof(buffer));
1181cfa7b011SJoanne Koong if (!hdr)
1182cfa7b011SJoanne Koong return SK_DROP;
1183cfa7b011SJoanne Koong
1184cfa7b011SJoanne Koong hdr->h_proto = 123;
1185cfa7b011SJoanne Koong
1186cfa7b011SJoanne Koong bpf_dynptr_write(&ptr, 0, write_data, sizeof(write_data), 0);
1187cfa7b011SJoanne Koong
1188cfa7b011SJoanne Koong /* this should fail */
1189cfa7b011SJoanne Koong hdr->h_proto = 1;
1190cfa7b011SJoanne Koong
1191cfa7b011SJoanne Koong return SK_PASS;
1192cfa7b011SJoanne Koong }
1193cfa7b011SJoanne Koong
1194cfa7b011SJoanne Koong /* The read-only data slice is invalidated whenever a helper changes packet data */
1195cfa7b011SJoanne Koong SEC("?xdp")
1196cfa7b011SJoanne Koong __failure __msg("invalid mem access 'scalar'")
xdp_invalid_data_slice1(struct xdp_md * xdp)1197cfa7b011SJoanne Koong int xdp_invalid_data_slice1(struct xdp_md *xdp)
1198cfa7b011SJoanne Koong {
1199cfa7b011SJoanne Koong struct bpf_dynptr ptr;
1200cfa7b011SJoanne Koong struct ethhdr *hdr;
1201cfa7b011SJoanne Koong char buffer[sizeof(*hdr)] = {};
1202cfa7b011SJoanne Koong
1203cfa7b011SJoanne Koong bpf_dynptr_from_xdp(xdp, 0, &ptr);
1204cfa7b011SJoanne Koong hdr = bpf_dynptr_slice(&ptr, 0, buffer, sizeof(buffer));
1205cfa7b011SJoanne Koong if (!hdr)
1206cfa7b011SJoanne Koong return SK_DROP;
1207cfa7b011SJoanne Koong
1208cfa7b011SJoanne Koong val = hdr->h_proto;
1209cfa7b011SJoanne Koong
1210cfa7b011SJoanne Koong if (bpf_xdp_adjust_head(xdp, 0 - (int)sizeof(*hdr)))
1211cfa7b011SJoanne Koong return XDP_DROP;
1212cfa7b011SJoanne Koong
1213cfa7b011SJoanne Koong /* this should fail */
1214cfa7b011SJoanne Koong val = hdr->h_proto;
1215cfa7b011SJoanne Koong
1216cfa7b011SJoanne Koong return XDP_PASS;
1217cfa7b011SJoanne Koong }
1218cfa7b011SJoanne Koong
1219cfa7b011SJoanne Koong /* The read-write data slice is invalidated whenever a helper changes packet data */
1220cfa7b011SJoanne Koong SEC("?xdp")
1221cfa7b011SJoanne Koong __failure __msg("invalid mem access 'scalar'")
xdp_invalid_data_slice2(struct xdp_md * xdp)1222cfa7b011SJoanne Koong int xdp_invalid_data_slice2(struct xdp_md *xdp)
1223cfa7b011SJoanne Koong {
1224cfa7b011SJoanne Koong struct bpf_dynptr ptr;
1225cfa7b011SJoanne Koong struct ethhdr *hdr;
1226cfa7b011SJoanne Koong char buffer[sizeof(*hdr)] = {};
1227cfa7b011SJoanne Koong
1228cfa7b011SJoanne Koong bpf_dynptr_from_xdp(xdp, 0, &ptr);
1229cfa7b011SJoanne Koong hdr = bpf_dynptr_slice_rdwr(&ptr, 0, buffer, sizeof(buffer));
1230cfa7b011SJoanne Koong if (!hdr)
1231cfa7b011SJoanne Koong return SK_DROP;
1232cfa7b011SJoanne Koong
1233cfa7b011SJoanne Koong hdr->h_proto = 9;
1234cfa7b011SJoanne Koong
1235cfa7b011SJoanne Koong if (bpf_xdp_adjust_head(xdp, 0 - (int)sizeof(*hdr)))
1236cfa7b011SJoanne Koong return XDP_DROP;
1237cfa7b011SJoanne Koong
1238cfa7b011SJoanne Koong /* this should fail */
1239cfa7b011SJoanne Koong hdr->h_proto = 1;
1240cfa7b011SJoanne Koong
1241cfa7b011SJoanne Koong return XDP_PASS;
1242cfa7b011SJoanne Koong }
1243cfa7b011SJoanne Koong
1244cfa7b011SJoanne Koong /* Only supported prog type can create skb-type dynptrs */
1245cfa7b011SJoanne Koong SEC("?raw_tp")
1246cfa7b011SJoanne Koong __failure __msg("calling kernel function bpf_dynptr_from_skb is not allowed")
skb_invalid_ctx(void * ctx)1247cfa7b011SJoanne Koong int skb_invalid_ctx(void *ctx)
1248cfa7b011SJoanne Koong {
1249cfa7b011SJoanne Koong struct bpf_dynptr ptr;
1250cfa7b011SJoanne Koong
1251cfa7b011SJoanne Koong /* this should fail */
1252cfa7b011SJoanne Koong bpf_dynptr_from_skb(ctx, 0, &ptr);
1253cfa7b011SJoanne Koong
1254cfa7b011SJoanne Koong return 0;
1255cfa7b011SJoanne Koong }
1256cfa7b011SJoanne Koong
1257ae8e354cSKumar Kartikeya Dwivedi /* Reject writes to dynptr slot for uninit arg */
1258ae8e354cSKumar Kartikeya Dwivedi SEC("?raw_tp")
1259ae8e354cSKumar Kartikeya Dwivedi __failure __msg("potential write to dynptr at off=-16")
uninit_write_into_slot(void * ctx)1260ae8e354cSKumar Kartikeya Dwivedi int uninit_write_into_slot(void *ctx)
1261ae8e354cSKumar Kartikeya Dwivedi {
1262ae8e354cSKumar Kartikeya Dwivedi struct {
1263ae8e354cSKumar Kartikeya Dwivedi char buf[64];
1264ae8e354cSKumar Kartikeya Dwivedi struct bpf_dynptr ptr;
1265ae8e354cSKumar Kartikeya Dwivedi } data;
1266ae8e354cSKumar Kartikeya Dwivedi
1267ae8e354cSKumar Kartikeya Dwivedi bpf_ringbuf_reserve_dynptr(&ringbuf, 80, 0, &data.ptr);
1268ae8e354cSKumar Kartikeya Dwivedi /* this should fail */
1269ae8e354cSKumar Kartikeya Dwivedi bpf_get_current_comm(data.buf, 80);
1270ae8e354cSKumar Kartikeya Dwivedi
1271ae8e354cSKumar Kartikeya Dwivedi return 0;
1272ae8e354cSKumar Kartikeya Dwivedi }
1273ae8e354cSKumar Kartikeya Dwivedi
1274cfa7b011SJoanne Koong /* Only supported prog type can create xdp-type dynptrs */
1275cfa7b011SJoanne Koong SEC("?raw_tp")
1276cfa7b011SJoanne Koong __failure __msg("calling kernel function bpf_dynptr_from_xdp is not allowed")
xdp_invalid_ctx(void * ctx)1277cfa7b011SJoanne Koong int xdp_invalid_ctx(void *ctx)
1278cfa7b011SJoanne Koong {
1279cfa7b011SJoanne Koong struct bpf_dynptr ptr;
1280cfa7b011SJoanne Koong
1281cfa7b011SJoanne Koong /* this should fail */
1282cfa7b011SJoanne Koong bpf_dynptr_from_xdp(ctx, 0, &ptr);
1283cfa7b011SJoanne Koong
1284cfa7b011SJoanne Koong return 0;
1285cfa7b011SJoanne Koong }
1286cfa7b011SJoanne Koong
1287cfa7b011SJoanne Koong __u32 hdr_size = sizeof(struct ethhdr);
1288cfa7b011SJoanne Koong /* Can't pass in variable-sized len to bpf_dynptr_slice */
1289cfa7b011SJoanne Koong SEC("?tc")
1290cfa7b011SJoanne Koong __failure __msg("unbounded memory access")
dynptr_slice_var_len1(struct __sk_buff * skb)1291cfa7b011SJoanne Koong int dynptr_slice_var_len1(struct __sk_buff *skb)
1292cfa7b011SJoanne Koong {
1293cfa7b011SJoanne Koong struct bpf_dynptr ptr;
1294cfa7b011SJoanne Koong struct ethhdr *hdr;
1295cfa7b011SJoanne Koong char buffer[sizeof(*hdr)] = {};
1296cfa7b011SJoanne Koong
1297cfa7b011SJoanne Koong bpf_dynptr_from_skb(skb, 0, &ptr);
1298cfa7b011SJoanne Koong
1299cfa7b011SJoanne Koong /* this should fail */
1300cfa7b011SJoanne Koong hdr = bpf_dynptr_slice(&ptr, 0, buffer, hdr_size);
1301cfa7b011SJoanne Koong if (!hdr)
1302cfa7b011SJoanne Koong return SK_DROP;
1303cfa7b011SJoanne Koong
1304cfa7b011SJoanne Koong return SK_PASS;
1305cfa7b011SJoanne Koong }
1306cfa7b011SJoanne Koong
1307cfa7b011SJoanne Koong /* Can't pass in variable-sized len to bpf_dynptr_slice */
1308cfa7b011SJoanne Koong SEC("?tc")
1309cfa7b011SJoanne Koong __failure __msg("must be a known constant")
dynptr_slice_var_len2(struct __sk_buff * skb)1310cfa7b011SJoanne Koong int dynptr_slice_var_len2(struct __sk_buff *skb)
1311cfa7b011SJoanne Koong {
1312cfa7b011SJoanne Koong char buffer[sizeof(struct ethhdr)] = {};
1313cfa7b011SJoanne Koong struct bpf_dynptr ptr;
1314cfa7b011SJoanne Koong struct ethhdr *hdr;
1315cfa7b011SJoanne Koong
1316cfa7b011SJoanne Koong bpf_dynptr_from_skb(skb, 0, &ptr);
1317cfa7b011SJoanne Koong
1318cfa7b011SJoanne Koong if (hdr_size <= sizeof(buffer)) {
1319cfa7b011SJoanne Koong /* this should fail */
1320cfa7b011SJoanne Koong hdr = bpf_dynptr_slice_rdwr(&ptr, 0, buffer, hdr_size);
1321cfa7b011SJoanne Koong if (!hdr)
1322cfa7b011SJoanne Koong return SK_DROP;
1323cfa7b011SJoanne Koong hdr->h_proto = 12;
1324cfa7b011SJoanne Koong }
1325cfa7b011SJoanne Koong
1326cfa7b011SJoanne Koong return SK_PASS;
1327cfa7b011SJoanne Koong }
1328cfa7b011SJoanne Koong
callback(__u32 index,void * data)1329ae8e354cSKumar Kartikeya Dwivedi static int callback(__u32 index, void *data)
1330ae8e354cSKumar Kartikeya Dwivedi {
1331ae8e354cSKumar Kartikeya Dwivedi *(__u32 *)data = 123;
1332ae8e354cSKumar Kartikeya Dwivedi
1333ae8e354cSKumar Kartikeya Dwivedi return 0;
1334ae8e354cSKumar Kartikeya Dwivedi }
1335ae8e354cSKumar Kartikeya Dwivedi
1336ae8e354cSKumar Kartikeya Dwivedi /* If the dynptr is written into in a callback function, its data
1337ae8e354cSKumar Kartikeya Dwivedi * slices should be invalidated as well.
1338ae8e354cSKumar Kartikeya Dwivedi */
1339ae8e354cSKumar Kartikeya Dwivedi SEC("?raw_tp")
1340ae8e354cSKumar Kartikeya Dwivedi __failure __msg("invalid mem access 'scalar'")
invalid_data_slices(void * ctx)1341ae8e354cSKumar Kartikeya Dwivedi int invalid_data_slices(void *ctx)
1342ae8e354cSKumar Kartikeya Dwivedi {
1343ae8e354cSKumar Kartikeya Dwivedi struct bpf_dynptr ptr;
1344ae8e354cSKumar Kartikeya Dwivedi __u32 *slice;
1345ae8e354cSKumar Kartikeya Dwivedi
1346ae8e354cSKumar Kartikeya Dwivedi if (get_map_val_dynptr(&ptr))
1347ae8e354cSKumar Kartikeya Dwivedi return 0;
1348ae8e354cSKumar Kartikeya Dwivedi
1349ae8e354cSKumar Kartikeya Dwivedi slice = bpf_dynptr_data(&ptr, 0, sizeof(__u32));
1350ae8e354cSKumar Kartikeya Dwivedi if (!slice)
1351ae8e354cSKumar Kartikeya Dwivedi return 0;
1352ae8e354cSKumar Kartikeya Dwivedi
1353ae8e354cSKumar Kartikeya Dwivedi bpf_loop(10, callback, &ptr, 0);
1354ae8e354cSKumar Kartikeya Dwivedi
1355ae8e354cSKumar Kartikeya Dwivedi /* this should fail */
1356ae8e354cSKumar Kartikeya Dwivedi *slice = 1;
1357ae8e354cSKumar Kartikeya Dwivedi
1358ae8e354cSKumar Kartikeya Dwivedi return 0;
1359ae8e354cSKumar Kartikeya Dwivedi }
1360cfa7b011SJoanne Koong
1361cfa7b011SJoanne Koong /* Program types that don't allow writes to packet data should fail if
1362cfa7b011SJoanne Koong * bpf_dynptr_slice_rdwr is called
1363cfa7b011SJoanne Koong */
1364cfa7b011SJoanne Koong SEC("cgroup_skb/ingress")
1365cfa7b011SJoanne Koong __failure __msg("the prog does not allow writes to packet data")
invalid_slice_rdwr_rdonly(struct __sk_buff * skb)1366cfa7b011SJoanne Koong int invalid_slice_rdwr_rdonly(struct __sk_buff *skb)
1367cfa7b011SJoanne Koong {
1368cfa7b011SJoanne Koong char buffer[sizeof(struct ethhdr)] = {};
1369cfa7b011SJoanne Koong struct bpf_dynptr ptr;
1370cfa7b011SJoanne Koong struct ethhdr *hdr;
1371cfa7b011SJoanne Koong
1372cfa7b011SJoanne Koong bpf_dynptr_from_skb(skb, 0, &ptr);
1373cfa7b011SJoanne Koong
1374cfa7b011SJoanne Koong /* this should fail since cgroup_skb doesn't allow
1375cfa7b011SJoanne Koong * changing packet data
1376cfa7b011SJoanne Koong */
1377cfa7b011SJoanne Koong hdr = bpf_dynptr_slice_rdwr(&ptr, 0, buffer, sizeof(buffer));
1378c8ed6685SAndrii Nakryiko __sink(hdr);
1379cfa7b011SJoanne Koong
1380cfa7b011SJoanne Koong return 0;
1381cfa7b011SJoanne Koong }
1382d911ba7cSJoanne Koong
1383d911ba7cSJoanne Koong /* bpf_dynptr_adjust can only be called on initialized dynptrs */
1384d911ba7cSJoanne Koong SEC("?raw_tp")
1385d911ba7cSJoanne Koong __failure __msg("Expected an initialized dynptr as arg #1")
dynptr_adjust_invalid(void * ctx)1386d911ba7cSJoanne Koong int dynptr_adjust_invalid(void *ctx)
1387d911ba7cSJoanne Koong {
1388d911ba7cSJoanne Koong struct bpf_dynptr ptr;
1389d911ba7cSJoanne Koong
1390d911ba7cSJoanne Koong /* this should fail */
1391d911ba7cSJoanne Koong bpf_dynptr_adjust(&ptr, 1, 2);
1392d911ba7cSJoanne Koong
1393d911ba7cSJoanne Koong return 0;
1394d911ba7cSJoanne Koong }
1395d911ba7cSJoanne Koong
1396d911ba7cSJoanne Koong /* bpf_dynptr_is_null can only be called on initialized dynptrs */
1397d911ba7cSJoanne Koong SEC("?raw_tp")
1398d911ba7cSJoanne Koong __failure __msg("Expected an initialized dynptr as arg #1")
dynptr_is_null_invalid(void * ctx)1399d911ba7cSJoanne Koong int dynptr_is_null_invalid(void *ctx)
1400d911ba7cSJoanne Koong {
1401d911ba7cSJoanne Koong struct bpf_dynptr ptr;
1402d911ba7cSJoanne Koong
1403d911ba7cSJoanne Koong /* this should fail */
1404d911ba7cSJoanne Koong bpf_dynptr_is_null(&ptr);
1405d911ba7cSJoanne Koong
1406d911ba7cSJoanne Koong return 0;
1407d911ba7cSJoanne Koong }
1408d911ba7cSJoanne Koong
1409d911ba7cSJoanne Koong /* bpf_dynptr_is_rdonly can only be called on initialized dynptrs */
1410d911ba7cSJoanne Koong SEC("?raw_tp")
1411d911ba7cSJoanne Koong __failure __msg("Expected an initialized dynptr as arg #1")
dynptr_is_rdonly_invalid(void * ctx)1412d911ba7cSJoanne Koong int dynptr_is_rdonly_invalid(void *ctx)
1413d911ba7cSJoanne Koong {
1414d911ba7cSJoanne Koong struct bpf_dynptr ptr;
1415d911ba7cSJoanne Koong
1416d911ba7cSJoanne Koong /* this should fail */
1417d911ba7cSJoanne Koong bpf_dynptr_is_rdonly(&ptr);
1418d911ba7cSJoanne Koong
1419d911ba7cSJoanne Koong return 0;
1420d911ba7cSJoanne Koong }
1421d911ba7cSJoanne Koong
1422d911ba7cSJoanne Koong /* bpf_dynptr_size can only be called on initialized dynptrs */
1423d911ba7cSJoanne Koong SEC("?raw_tp")
1424d911ba7cSJoanne Koong __failure __msg("Expected an initialized dynptr as arg #1")
dynptr_size_invalid(void * ctx)1425d911ba7cSJoanne Koong int dynptr_size_invalid(void *ctx)
1426d911ba7cSJoanne Koong {
1427d911ba7cSJoanne Koong struct bpf_dynptr ptr;
1428d911ba7cSJoanne Koong
1429d911ba7cSJoanne Koong /* this should fail */
1430d911ba7cSJoanne Koong bpf_dynptr_size(&ptr);
1431d911ba7cSJoanne Koong
1432d911ba7cSJoanne Koong return 0;
1433d911ba7cSJoanne Koong }
1434d911ba7cSJoanne Koong
1435d911ba7cSJoanne Koong /* Only initialized dynptrs can be cloned */
1436d911ba7cSJoanne Koong SEC("?raw_tp")
1437d911ba7cSJoanne Koong __failure __msg("Expected an initialized dynptr as arg #1")
clone_invalid1(void * ctx)1438d911ba7cSJoanne Koong int clone_invalid1(void *ctx)
1439d911ba7cSJoanne Koong {
1440d911ba7cSJoanne Koong struct bpf_dynptr ptr1;
1441d911ba7cSJoanne Koong struct bpf_dynptr ptr2;
1442d911ba7cSJoanne Koong
1443d911ba7cSJoanne Koong /* this should fail */
1444d911ba7cSJoanne Koong bpf_dynptr_clone(&ptr1, &ptr2);
1445d911ba7cSJoanne Koong
1446d911ba7cSJoanne Koong return 0;
1447d911ba7cSJoanne Koong }
1448d911ba7cSJoanne Koong
1449d911ba7cSJoanne Koong /* Can't overwrite an existing dynptr when cloning */
1450d911ba7cSJoanne Koong SEC("?xdp")
1451d911ba7cSJoanne Koong __failure __msg("cannot overwrite referenced dynptr")
clone_invalid2(struct xdp_md * xdp)1452d911ba7cSJoanne Koong int clone_invalid2(struct xdp_md *xdp)
1453d911ba7cSJoanne Koong {
1454d911ba7cSJoanne Koong struct bpf_dynptr ptr1;
1455d911ba7cSJoanne Koong struct bpf_dynptr clone;
1456d911ba7cSJoanne Koong
1457d911ba7cSJoanne Koong bpf_dynptr_from_xdp(xdp, 0, &ptr1);
1458d911ba7cSJoanne Koong
1459d911ba7cSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, 64, 0, &clone);
1460d911ba7cSJoanne Koong
1461d911ba7cSJoanne Koong /* this should fail */
1462d911ba7cSJoanne Koong bpf_dynptr_clone(&ptr1, &clone);
1463d911ba7cSJoanne Koong
1464d911ba7cSJoanne Koong bpf_ringbuf_submit_dynptr(&clone, 0);
1465d911ba7cSJoanne Koong
1466d911ba7cSJoanne Koong return 0;
1467d911ba7cSJoanne Koong }
1468d911ba7cSJoanne Koong
1469d911ba7cSJoanne Koong /* Invalidating a dynptr should invalidate its clones */
1470d911ba7cSJoanne Koong SEC("?raw_tp")
1471d911ba7cSJoanne Koong __failure __msg("Expected an initialized dynptr as arg #3")
clone_invalidate1(void * ctx)1472d911ba7cSJoanne Koong int clone_invalidate1(void *ctx)
1473d911ba7cSJoanne Koong {
1474d911ba7cSJoanne Koong struct bpf_dynptr clone;
1475d911ba7cSJoanne Koong struct bpf_dynptr ptr;
1476d911ba7cSJoanne Koong char read_data[64];
1477d911ba7cSJoanne Koong
1478d911ba7cSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);
1479d911ba7cSJoanne Koong
1480d911ba7cSJoanne Koong bpf_dynptr_clone(&ptr, &clone);
1481d911ba7cSJoanne Koong
1482d911ba7cSJoanne Koong bpf_ringbuf_submit_dynptr(&ptr, 0);
1483d911ba7cSJoanne Koong
1484d911ba7cSJoanne Koong /* this should fail */
1485d911ba7cSJoanne Koong bpf_dynptr_read(read_data, sizeof(read_data), &clone, 0, 0);
1486d911ba7cSJoanne Koong
1487d911ba7cSJoanne Koong return 0;
1488d911ba7cSJoanne Koong }
1489d911ba7cSJoanne Koong
1490d911ba7cSJoanne Koong /* Invalidating a dynptr should invalidate its parent */
1491d911ba7cSJoanne Koong SEC("?raw_tp")
1492d911ba7cSJoanne Koong __failure __msg("Expected an initialized dynptr as arg #3")
clone_invalidate2(void * ctx)1493d911ba7cSJoanne Koong int clone_invalidate2(void *ctx)
1494d911ba7cSJoanne Koong {
1495d911ba7cSJoanne Koong struct bpf_dynptr ptr;
1496d911ba7cSJoanne Koong struct bpf_dynptr clone;
1497d911ba7cSJoanne Koong char read_data[64];
1498d911ba7cSJoanne Koong
1499d911ba7cSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);
1500d911ba7cSJoanne Koong
1501d911ba7cSJoanne Koong bpf_dynptr_clone(&ptr, &clone);
1502d911ba7cSJoanne Koong
1503d911ba7cSJoanne Koong bpf_ringbuf_submit_dynptr(&clone, 0);
1504d911ba7cSJoanne Koong
1505d911ba7cSJoanne Koong /* this should fail */
1506d911ba7cSJoanne Koong bpf_dynptr_read(read_data, sizeof(read_data), &ptr, 0, 0);
1507d911ba7cSJoanne Koong
1508d911ba7cSJoanne Koong return 0;
1509d911ba7cSJoanne Koong }
1510d911ba7cSJoanne Koong
1511d911ba7cSJoanne Koong /* Invalidating a dynptr should invalidate its siblings */
1512d911ba7cSJoanne Koong SEC("?raw_tp")
1513d911ba7cSJoanne Koong __failure __msg("Expected an initialized dynptr as arg #3")
clone_invalidate3(void * ctx)1514d911ba7cSJoanne Koong int clone_invalidate3(void *ctx)
1515d911ba7cSJoanne Koong {
1516d911ba7cSJoanne Koong struct bpf_dynptr ptr;
1517d911ba7cSJoanne Koong struct bpf_dynptr clone1;
1518d911ba7cSJoanne Koong struct bpf_dynptr clone2;
1519d911ba7cSJoanne Koong char read_data[64];
1520d911ba7cSJoanne Koong
1521d911ba7cSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);
1522d911ba7cSJoanne Koong
1523d911ba7cSJoanne Koong bpf_dynptr_clone(&ptr, &clone1);
1524d911ba7cSJoanne Koong
1525d911ba7cSJoanne Koong bpf_dynptr_clone(&ptr, &clone2);
1526d911ba7cSJoanne Koong
1527d911ba7cSJoanne Koong bpf_ringbuf_submit_dynptr(&clone2, 0);
1528d911ba7cSJoanne Koong
1529d911ba7cSJoanne Koong /* this should fail */
1530d911ba7cSJoanne Koong bpf_dynptr_read(read_data, sizeof(read_data), &clone1, 0, 0);
1531d911ba7cSJoanne Koong
1532d911ba7cSJoanne Koong return 0;
1533d911ba7cSJoanne Koong }
1534d911ba7cSJoanne Koong
1535d911ba7cSJoanne Koong /* Invalidating a dynptr should invalidate any data slices
1536d911ba7cSJoanne Koong * of its clones
1537d911ba7cSJoanne Koong */
1538d911ba7cSJoanne Koong SEC("?raw_tp")
1539d911ba7cSJoanne Koong __failure __msg("invalid mem access 'scalar'")
clone_invalidate4(void * ctx)1540d911ba7cSJoanne Koong int clone_invalidate4(void *ctx)
1541d911ba7cSJoanne Koong {
1542d911ba7cSJoanne Koong struct bpf_dynptr ptr;
1543d911ba7cSJoanne Koong struct bpf_dynptr clone;
1544d911ba7cSJoanne Koong int *data;
1545d911ba7cSJoanne Koong
1546d911ba7cSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);
1547d911ba7cSJoanne Koong
1548d911ba7cSJoanne Koong bpf_dynptr_clone(&ptr, &clone);
1549d911ba7cSJoanne Koong data = bpf_dynptr_data(&clone, 0, sizeof(val));
1550d911ba7cSJoanne Koong if (!data)
1551d911ba7cSJoanne Koong return 0;
1552d911ba7cSJoanne Koong
1553d911ba7cSJoanne Koong bpf_ringbuf_submit_dynptr(&ptr, 0);
1554d911ba7cSJoanne Koong
1555d911ba7cSJoanne Koong /* this should fail */
1556d911ba7cSJoanne Koong *data = 123;
1557d911ba7cSJoanne Koong
1558d911ba7cSJoanne Koong return 0;
1559d911ba7cSJoanne Koong }
1560d911ba7cSJoanne Koong
1561d911ba7cSJoanne Koong /* Invalidating a dynptr should invalidate any data slices
1562d911ba7cSJoanne Koong * of its parent
1563d911ba7cSJoanne Koong */
1564d911ba7cSJoanne Koong SEC("?raw_tp")
1565d911ba7cSJoanne Koong __failure __msg("invalid mem access 'scalar'")
clone_invalidate5(void * ctx)1566d911ba7cSJoanne Koong int clone_invalidate5(void *ctx)
1567d911ba7cSJoanne Koong {
1568d911ba7cSJoanne Koong struct bpf_dynptr ptr;
1569d911ba7cSJoanne Koong struct bpf_dynptr clone;
1570d911ba7cSJoanne Koong int *data;
1571d911ba7cSJoanne Koong
1572d911ba7cSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);
1573d911ba7cSJoanne Koong data = bpf_dynptr_data(&ptr, 0, sizeof(val));
1574d911ba7cSJoanne Koong if (!data)
1575d911ba7cSJoanne Koong return 0;
1576d911ba7cSJoanne Koong
1577d911ba7cSJoanne Koong bpf_dynptr_clone(&ptr, &clone);
1578d911ba7cSJoanne Koong
1579d911ba7cSJoanne Koong bpf_ringbuf_submit_dynptr(&clone, 0);
1580d911ba7cSJoanne Koong
1581d911ba7cSJoanne Koong /* this should fail */
1582d911ba7cSJoanne Koong *data = 123;
1583d911ba7cSJoanne Koong
1584d911ba7cSJoanne Koong return 0;
1585d911ba7cSJoanne Koong }
1586d911ba7cSJoanne Koong
1587d911ba7cSJoanne Koong /* Invalidating a dynptr should invalidate any data slices
1588d911ba7cSJoanne Koong * of its sibling
1589d911ba7cSJoanne Koong */
1590d911ba7cSJoanne Koong SEC("?raw_tp")
1591d911ba7cSJoanne Koong __failure __msg("invalid mem access 'scalar'")
clone_invalidate6(void * ctx)1592d911ba7cSJoanne Koong int clone_invalidate6(void *ctx)
1593d911ba7cSJoanne Koong {
1594d911ba7cSJoanne Koong struct bpf_dynptr ptr;
1595d911ba7cSJoanne Koong struct bpf_dynptr clone1;
1596d911ba7cSJoanne Koong struct bpf_dynptr clone2;
1597d911ba7cSJoanne Koong int *data;
1598d911ba7cSJoanne Koong
1599d911ba7cSJoanne Koong bpf_ringbuf_reserve_dynptr(&ringbuf, val, 0, &ptr);
1600d911ba7cSJoanne Koong
1601d911ba7cSJoanne Koong bpf_dynptr_clone(&ptr, &clone1);
1602d911ba7cSJoanne Koong
1603d911ba7cSJoanne Koong bpf_dynptr_clone(&ptr, &clone2);
1604d911ba7cSJoanne Koong
1605d911ba7cSJoanne Koong data = bpf_dynptr_data(&clone1, 0, sizeof(val));
1606d911ba7cSJoanne Koong if (!data)
1607d911ba7cSJoanne Koong return 0;
1608d911ba7cSJoanne Koong
1609d911ba7cSJoanne Koong bpf_ringbuf_submit_dynptr(&clone2, 0);
1610d911ba7cSJoanne Koong
1611d911ba7cSJoanne Koong /* this should fail */
1612d911ba7cSJoanne Koong *data = 123;
1613d911ba7cSJoanne Koong
1614d911ba7cSJoanne Koong return 0;
1615d911ba7cSJoanne Koong }
1616d911ba7cSJoanne Koong
1617d911ba7cSJoanne Koong /* A skb clone's data slices should be invalid anytime packet data changes */
1618d911ba7cSJoanne Koong SEC("?tc")
1619d911ba7cSJoanne Koong __failure __msg("invalid mem access 'scalar'")
clone_skb_packet_data(struct __sk_buff * skb)1620d911ba7cSJoanne Koong int clone_skb_packet_data(struct __sk_buff *skb)
1621d911ba7cSJoanne Koong {
1622d911ba7cSJoanne Koong char buffer[sizeof(__u32)] = {};
1623d911ba7cSJoanne Koong struct bpf_dynptr clone;
1624d911ba7cSJoanne Koong struct bpf_dynptr ptr;
1625d911ba7cSJoanne Koong __u32 *data;
1626d911ba7cSJoanne Koong
1627d911ba7cSJoanne Koong bpf_dynptr_from_skb(skb, 0, &ptr);
1628d911ba7cSJoanne Koong
1629d911ba7cSJoanne Koong bpf_dynptr_clone(&ptr, &clone);
1630d911ba7cSJoanne Koong data = bpf_dynptr_slice_rdwr(&clone, 0, buffer, sizeof(buffer));
1631d911ba7cSJoanne Koong if (!data)
1632d911ba7cSJoanne Koong return XDP_DROP;
1633d911ba7cSJoanne Koong
1634d911ba7cSJoanne Koong if (bpf_skb_pull_data(skb, skb->len))
1635d911ba7cSJoanne Koong return SK_DROP;
1636d911ba7cSJoanne Koong
1637d911ba7cSJoanne Koong /* this should fail */
1638d911ba7cSJoanne Koong *data = 123;
1639d911ba7cSJoanne Koong
1640d911ba7cSJoanne Koong return 0;
1641d911ba7cSJoanne Koong }
1642d911ba7cSJoanne Koong
1643d911ba7cSJoanne Koong /* A xdp clone's data slices should be invalid anytime packet data changes */
1644d911ba7cSJoanne Koong SEC("?xdp")
1645d911ba7cSJoanne Koong __failure __msg("invalid mem access 'scalar'")
clone_xdp_packet_data(struct xdp_md * xdp)1646d911ba7cSJoanne Koong int clone_xdp_packet_data(struct xdp_md *xdp)
1647d911ba7cSJoanne Koong {
1648d911ba7cSJoanne Koong char buffer[sizeof(__u32)] = {};
1649d911ba7cSJoanne Koong struct bpf_dynptr clone;
1650d911ba7cSJoanne Koong struct bpf_dynptr ptr;
1651d911ba7cSJoanne Koong struct ethhdr *hdr;
1652d911ba7cSJoanne Koong __u32 *data;
1653d911ba7cSJoanne Koong
1654d911ba7cSJoanne Koong bpf_dynptr_from_xdp(xdp, 0, &ptr);
1655d911ba7cSJoanne Koong
1656d911ba7cSJoanne Koong bpf_dynptr_clone(&ptr, &clone);
1657d911ba7cSJoanne Koong data = bpf_dynptr_slice_rdwr(&clone, 0, buffer, sizeof(buffer));
1658d911ba7cSJoanne Koong if (!data)
1659d911ba7cSJoanne Koong return XDP_DROP;
1660d911ba7cSJoanne Koong
1661d911ba7cSJoanne Koong if (bpf_xdp_adjust_head(xdp, 0 - (int)sizeof(*hdr)))
1662d911ba7cSJoanne Koong return XDP_DROP;
1663d911ba7cSJoanne Koong
1664d911ba7cSJoanne Koong /* this should fail */
1665d911ba7cSJoanne Koong *data = 123;
1666d911ba7cSJoanne Koong
1667d911ba7cSJoanne Koong return 0;
1668d911ba7cSJoanne Koong }
16693881fdfeSDaniel Rosenberg
16703881fdfeSDaniel Rosenberg /* Buffers that are provided must be sufficiently long */
16713881fdfeSDaniel Rosenberg SEC("?cgroup_skb/egress")
16723881fdfeSDaniel Rosenberg __failure __msg("memory, len pair leads to invalid memory access")
test_dynptr_skb_small_buff(struct __sk_buff * skb)16733881fdfeSDaniel Rosenberg int test_dynptr_skb_small_buff(struct __sk_buff *skb)
16743881fdfeSDaniel Rosenberg {
16753881fdfeSDaniel Rosenberg struct bpf_dynptr ptr;
16763881fdfeSDaniel Rosenberg char buffer[8] = {};
16773881fdfeSDaniel Rosenberg __u64 *data;
16783881fdfeSDaniel Rosenberg
16793881fdfeSDaniel Rosenberg if (bpf_dynptr_from_skb(skb, 0, &ptr)) {
16803881fdfeSDaniel Rosenberg err = 1;
16813881fdfeSDaniel Rosenberg return 1;
16823881fdfeSDaniel Rosenberg }
16833881fdfeSDaniel Rosenberg
16843881fdfeSDaniel Rosenberg /* This may return NULL. SKB may require a buffer */
16853881fdfeSDaniel Rosenberg data = bpf_dynptr_slice(&ptr, 0, buffer, 9);
16863881fdfeSDaniel Rosenberg
16873881fdfeSDaniel Rosenberg return !!data;
16883881fdfeSDaniel Rosenberg }
1689