Commit fb91db01 authored by Alexei Starovoitov's avatar Alexei Starovoitov
Browse files

Merge branch 'Add skb_adjust_room() for SK_SKB'



John Fastabend says:

====================
This implements the helper skb_adjust_room() for BPF_SKS_SK_STREAM_VERDICT
programs so we can push/pop headers from the data on recieve. One use
case is to pop TLS headers off kTLS packets.

The first patch implements the helper and the second updates test_sockmap
to use it removing some case handling we had to do earlier to account for
the TLS headers in the kTLS tests.

v1->v2:
 Fix error path for TLS case (Daniel)
 check mode input is 0 because we don't use it now (Daniel)
 Remove incorrect/misleading comment (Lorenz)

Thanks,
John
Acked-by: default avatarMartin KaFai Lau <kafai@fb.com>
---
====================

Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents 60a128b5 91274ca5
Loading
Loading
Loading
Loading
+46 −0
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@
#include <net/bpf_sk_storage.h>
#include <net/transp_v6.h>
#include <linux/btf_ids.h>
#include <net/tls.h>

static const struct bpf_func_proto *
bpf_sk_base_func_proto(enum bpf_func_id func_id);
@@ -3479,6 +3480,48 @@ static u32 __bpf_skb_max_len(const struct sk_buff *skb)
			  SKB_MAX_ALLOC;
}

BPF_CALL_4(sk_skb_adjust_room, struct sk_buff *, skb, s32, len_diff,
	   u32, mode, u64, flags)
{
	u32 len_diff_abs = abs(len_diff);
	bool shrink = len_diff < 0;
	int ret = 0;

	if (unlikely(flags || mode))
		return -EINVAL;
	if (unlikely(len_diff_abs > 0xfffU))
		return -EFAULT;

	if (!shrink) {
		ret = skb_cow(skb, len_diff);
		if (unlikely(ret < 0))
			return ret;
		__skb_push(skb, len_diff_abs);
		memset(skb->data, 0, len_diff_abs);
	} else {
		if (unlikely(!pskb_may_pull(skb, len_diff_abs)))
			return -ENOMEM;
		__skb_pull(skb, len_diff_abs);
	}
	bpf_compute_data_end_sk_skb(skb);
	if (tls_sw_has_ctx_rx(skb->sk)) {
		struct strp_msg *rxm = strp_msg(skb);

		rxm->full_len += len_diff;
	}
	return ret;
}

static const struct bpf_func_proto sk_skb_adjust_room_proto = {
	.func		= sk_skb_adjust_room,
	.gpl_only	= false,
	.ret_type	= RET_INTEGER,
	.arg1_type	= ARG_PTR_TO_CTX,
	.arg2_type	= ARG_ANYTHING,
	.arg3_type	= ARG_ANYTHING,
	.arg4_type	= ARG_ANYTHING,
};

BPF_CALL_4(bpf_skb_adjust_room, struct sk_buff *, skb, s32, len_diff,
	   u32, mode, u64, flags)
{
@@ -6745,6 +6788,7 @@ bool bpf_helper_changes_pkt_data(void *func)
	    func == bpf_skb_change_tail ||
	    func == sk_skb_change_tail ||
	    func == bpf_skb_adjust_room ||
	    func == sk_skb_adjust_room ||
	    func == bpf_skb_pull_data ||
	    func == sk_skb_pull_data ||
	    func == bpf_clone_redirect ||
@@ -7218,6 +7262,8 @@ sk_skb_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
		return &sk_skb_change_tail_proto;
	case BPF_FUNC_skb_change_head:
		return &sk_skb_change_head_proto;
	case BPF_FUNC_skb_adjust_room:
		return &sk_skb_adjust_room_proto;
	case BPF_FUNC_get_socket_cookie:
		return &bpf_get_socket_cookie_proto;
	case BPF_FUNC_get_socket_uid:
+25 −9
Original line number Diff line number Diff line
@@ -131,39 +131,55 @@ int bpf_prog2(struct __sk_buff *skb)

}

SEC("sk_skb3")
int bpf_prog3(struct __sk_buff *skb)
static inline void bpf_write_pass(struct __sk_buff *skb, int offset)
{
	const int one = 1;
	int err, *f, ret = SK_PASS;
	int err = bpf_skb_pull_data(skb, 6 + offset);
	void *data_end;
	char *c;

	err = bpf_skb_pull_data(skb, 19);
	if (err)
		goto tls_out;
		return;

	c = (char *)(long)skb->data;
	data_end = (void *)(long)skb->data_end;

	if (c + 18 < data_end)
		memcpy(&c[13], "PASS", 4);
	if (c + 5 + offset < data_end)
		memcpy(c + offset, "PASS", 4);
}

SEC("sk_skb3")
int bpf_prog3(struct __sk_buff *skb)
{
	int err, *f, ret = SK_PASS;
	const int one = 1;

	f = bpf_map_lookup_elem(&sock_skb_opts, &one);
	if (f && *f) {
		__u64 flags = 0;

		ret = 0;
		flags = *f;

		err = bpf_skb_adjust_room(skb, -13, 0, 0);
		if (err)
			return SK_DROP;
		err = bpf_skb_adjust_room(skb, 4, 0, 0);
		if (err)
			return SK_DROP;
		bpf_write_pass(skb, 0);
#ifdef SOCKMAP
		return bpf_sk_redirect_map(skb, &tls_sock_map, ret, flags);
#else
		return bpf_sk_redirect_hash(skb, &tls_sock_map, &ret, flags);
#endif
	}

	f = bpf_map_lookup_elem(&sock_skb_opts, &one);
	if (f && *f)
		ret = SK_DROP;
	err = bpf_skb_adjust_room(skb, 4, 0, 0);
	if (err)
		return SK_DROP;
	bpf_write_pass(skb, 13);
tls_out:
	return ret;
}
+6 −21
Original line number Diff line number Diff line
@@ -518,28 +518,13 @@ static int msg_verify_data(struct msghdr *msg, int size, int chunk_sz)
		if (i == 0 && txmsg_ktls_skb) {
			if (msg->msg_iov[i].iov_len < 4)
				return -EIO;
			if (txmsg_ktls_skb_redir) {
				if (memcmp(&d[13], "PASS", 4) != 0) {
					fprintf(stderr,
						"detected redirect ktls_skb data error with skb ingress update @iov[%i]:%i \"%02x %02x %02x %02x\" != \"PASS\"\n", i, 0, d[13], d[14], d[15], d[16]);
					return -EIO;
				}
				d[13] = 0;
				d[14] = 1;
				d[15] = 2;
				d[16] = 3;
				j = 13;
			} else if (txmsg_ktls_skb) {
			if (memcmp(d, "PASS", 4) != 0) {
				fprintf(stderr,
						"detected ktls_skb data error with skb ingress update @iov[%i]:%i \"%02x %02x %02x %02x\" != \"PASS\"\n", i, 0, d[0], d[1], d[2], d[3]);
					"detected skb data error with skb ingress update @iov[%i]:%i \"%02x %02x %02x %02x\" != \"PASS\"\n",
					i, 0, d[0], d[1], d[2], d[3]);
				return -EIO;
			}
				d[0] = 0;
				d[1] = 1;
				d[2] = 2;
				d[3] = 3;
			}
			j = 4; /* advance index past PASS header */
		}

		for (; j < msg->msg_iov[i].iov_len && size; j++) {