Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2f72959a authored by Daniel Borkmann's avatar Daniel Borkmann Committed by David S. Miller
Browse files

bpf: fix csum update in bpf_l4_csum_replace helper for udp



When using this helper for updating UDP checksums, we need to extend
this in order to write CSUM_MANGLED_0 for csum computations that result
into 0 as sum. Reason we need this is because packets with a checksum
could otherwise become incorrectly marked as a packet without a checksum.
Likewise, if the user indicates BPF_F_MARK_MANGLED_0, then we should
not turn packets without a checksum into ones with a checksum.

Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Acked-by: default avatarAlexei Starovoitov <ast@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 3697649f
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -313,6 +313,7 @@ enum bpf_func_id {


/* BPF_FUNC_l4_csum_replace flags. */
/* BPF_FUNC_l4_csum_replace flags. */
#define BPF_F_PSEUDO_HDR		(1ULL << 4)
#define BPF_F_PSEUDO_HDR		(1ULL << 4)
#define BPF_F_MARK_MANGLED_0		(1ULL << 5)


/* BPF_FUNC_clone_redirect and BPF_FUNC_redirect flags. */
/* BPF_FUNC_clone_redirect and BPF_FUNC_redirect flags. */
#define BPF_F_INGRESS			(1ULL << 0)
#define BPF_F_INGRESS			(1ULL << 0)
+7 −1
Original line number Original line Diff line number Diff line
@@ -1477,10 +1477,12 @@ static u64 bpf_l4_csum_replace(u64 r1, u64 r2, u64 from, u64 to, u64 flags)
{
{
	struct sk_buff *skb = (struct sk_buff *) (long) r1;
	struct sk_buff *skb = (struct sk_buff *) (long) r1;
	bool is_pseudo = flags & BPF_F_PSEUDO_HDR;
	bool is_pseudo = flags & BPF_F_PSEUDO_HDR;
	bool is_mmzero = flags & BPF_F_MARK_MANGLED_0;
	int offset = (int) r2;
	int offset = (int) r2;
	__sum16 sum, *ptr;
	__sum16 sum, *ptr;


	if (unlikely(flags & ~(BPF_F_PSEUDO_HDR | BPF_F_HDR_FIELD_MASK)))
	if (unlikely(flags & ~(BPF_F_MARK_MANGLED_0 | BPF_F_PSEUDO_HDR |
			       BPF_F_HDR_FIELD_MASK)))
		return -EINVAL;
		return -EINVAL;
	if (unlikely((u32) offset > 0xffff))
	if (unlikely((u32) offset > 0xffff))
		return -EFAULT;
		return -EFAULT;
@@ -1490,6 +1492,8 @@ static u64 bpf_l4_csum_replace(u64 r1, u64 r2, u64 from, u64 to, u64 flags)
	ptr = skb_header_pointer(skb, offset, sizeof(sum), &sum);
	ptr = skb_header_pointer(skb, offset, sizeof(sum), &sum);
	if (unlikely(!ptr))
	if (unlikely(!ptr))
		return -EFAULT;
		return -EFAULT;
	if (is_mmzero && !*ptr)
		return 0;


	switch (flags & BPF_F_HDR_FIELD_MASK) {
	switch (flags & BPF_F_HDR_FIELD_MASK) {
	case 0:
	case 0:
@@ -1508,6 +1512,8 @@ static u64 bpf_l4_csum_replace(u64 r1, u64 r2, u64 from, u64 to, u64 flags)
		return -EINVAL;
		return -EINVAL;
	}
	}


	if (is_mmzero && !*ptr)
		*ptr = CSUM_MANGLED_0;
	if (ptr == &sum)
	if (ptr == &sum)
		/* skb_store_bits guaranteed to not return -EFAULT here */
		/* skb_store_bits guaranteed to not return -EFAULT here */
		skb_store_bits(skb, offset, ptr, sizeof(sum));
		skb_store_bits(skb, offset, ptr, sizeof(sum));