Commit bd1b51b3 authored by Jakub Sitnicki's avatar Jakub Sitnicki Committed by Martin KaFai Lau
Browse files

selftests/bpf: Cover read/write to skb metadata at an offset



Exercise r/w access to skb metadata through an offset-adjusted dynptr,
read/write helper with an offset argument, and a slice starting at an
offset.

Also check for the expected errors when the offset is out of bounds.

Signed-off-by: default avatarJakub Sitnicki <jakub@cloudflare.com>
Signed-off-by: default avatarMartin KaFai Lau <martin.lau@kernel.org>
Reviewed-by: default avatarJesse Brandeburg <jbrandeburg@cloudflare.com>
Acked-by: default avatarEduard Zingerman <eddyz87@gmail.com>
Link: https://patch.msgid.link/20250814-skb-metadata-thru-dynptr-v7-8-8a39e636e0fb@cloudflare.com
parent ed933608
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -375,6 +375,16 @@ void test_xdp_context_tuntap(void)
			    skel->progs.ing_cls_dynptr_slice_rdwr,
			    skel->progs.ing_cls_dynptr_slice,
			    skel->maps.test_result);
	if (test__start_subtest("dynptr_offset"))
		test_tuntap(skel->progs.ing_xdp_zalloc_meta,
			    skel->progs.ing_cls_dynptr_offset_wr,
			    skel->progs.ing_cls_dynptr_offset_rd,
			    skel->maps.test_result);
	if (test__start_subtest("dynptr_offset_oob"))
		test_tuntap(skel->progs.ing_xdp,
			    skel->progs.ing_cls_dynptr_offset_oob,
			    skel->progs.ing_cls,
			    skel->maps.test_result);

	test_xdp_meta__destroy(skel);
}
+119 −0
Original line number Diff line number Diff line
#include <stdbool.h>
#include <linux/bpf.h>
#include <linux/errno.h>
#include <linux/if_ether.h>
#include <linux/pkt_cls.h>

@@ -122,6 +123,124 @@ int ing_cls_dynptr_slice_rdwr(struct __sk_buff *ctx)
	return TC_ACT_UNSPEC; /* pass */
}

/* Read skb metadata in chunks from various offsets in different ways. */
SEC("tc")
int ing_cls_dynptr_offset_rd(struct __sk_buff *ctx)
{
	struct bpf_dynptr meta;
	const __u32 chunk_len = META_SIZE / 4;
	const __u32 zero = 0;
	__u8 *dst, *src;

	dst = bpf_map_lookup_elem(&test_result, &zero);
	if (!dst)
		return TC_ACT_SHOT;

	/* 1. Regular read */
	bpf_dynptr_from_skb_meta(ctx, 0, &meta);
	bpf_dynptr_read(dst, chunk_len, &meta, 0, 0);
	dst += chunk_len;

	/* 2. Read from an offset-adjusted dynptr */
	bpf_dynptr_adjust(&meta, chunk_len, bpf_dynptr_size(&meta));
	bpf_dynptr_read(dst, chunk_len, &meta, 0, 0);
	dst += chunk_len;

	/* 3. Read at an offset */
	bpf_dynptr_read(dst, chunk_len, &meta, chunk_len, 0);
	dst += chunk_len;

	/* 4. Read from a slice starting at an offset */
	src = bpf_dynptr_slice(&meta, 2 * chunk_len, NULL, chunk_len);
	if (!src)
		return TC_ACT_SHOT;
	__builtin_memcpy(dst, src, chunk_len);

	return TC_ACT_SHOT;
}

/* Write skb metadata in chunks at various offsets in different ways. */
SEC("tc")
int ing_cls_dynptr_offset_wr(struct __sk_buff *ctx)
{
	const __u32 chunk_len = META_SIZE / 4;
	__u8 payload[META_SIZE];
	struct bpf_dynptr meta;
	__u8 *dst, *src;

	bpf_skb_load_bytes(ctx, sizeof(struct ethhdr), payload, sizeof(payload));
	src = payload;

	/* 1. Regular write */
	bpf_dynptr_from_skb_meta(ctx, 0, &meta);
	bpf_dynptr_write(&meta, 0, src, chunk_len, 0);
	src += chunk_len;

	/* 2. Write to an offset-adjusted dynptr */
	bpf_dynptr_adjust(&meta, chunk_len, bpf_dynptr_size(&meta));
	bpf_dynptr_write(&meta, 0, src, chunk_len, 0);
	src += chunk_len;

	/* 3. Write at an offset */
	bpf_dynptr_write(&meta, chunk_len, src, chunk_len, 0);
	src += chunk_len;

	/* 4. Write to a slice starting at an offset */
	dst = bpf_dynptr_slice_rdwr(&meta, 2 * chunk_len, NULL, chunk_len);
	if (!dst)
		return TC_ACT_SHOT;
	__builtin_memcpy(dst, src, chunk_len);

	return TC_ACT_UNSPEC; /* pass */
}

/* Pass an OOB offset to dynptr read, write, adjust, slice. */
SEC("tc")
int ing_cls_dynptr_offset_oob(struct __sk_buff *ctx)
{
	struct bpf_dynptr meta;
	__u8 md, *p;
	int err;

	err = bpf_dynptr_from_skb_meta(ctx, 0, &meta);
	if (err)
		goto fail;

	/* read offset OOB */
	err = bpf_dynptr_read(&md, sizeof(md), &meta, META_SIZE, 0);
	if (err != -E2BIG)
		goto fail;

	/* write offset OOB */
	err = bpf_dynptr_write(&meta, META_SIZE, &md, sizeof(md), 0);
	if (err != -E2BIG)
		goto fail;

	/* adjust end offset OOB */
	err = bpf_dynptr_adjust(&meta, 0, META_SIZE + 1);
	if (err != -ERANGE)
		goto fail;

	/* adjust start offset OOB */
	err = bpf_dynptr_adjust(&meta, META_SIZE + 1, META_SIZE + 1);
	if (err != -ERANGE)
		goto fail;

	/* slice offset OOB */
	p = bpf_dynptr_slice(&meta, META_SIZE, NULL, sizeof(*p));
	if (p)
		goto fail;

	/* slice rdwr offset OOB */
	p = bpf_dynptr_slice_rdwr(&meta, META_SIZE, NULL, sizeof(*p));
	if (p)
		goto fail;

	return TC_ACT_UNSPEC;
fail:
	return TC_ACT_SHOT;
}

/* Reserve and clear space for metadata but don't populate it */
SEC("xdp")
int ing_xdp_zalloc_meta(struct xdp_md *ctx)