Skip to content

Commit 5584289

Browse files
committed
Merge branch 'net-fix-inet_proto_csum_replace_by_diff-for-ipv6'
Paul Chaignon says: ==================== net: Fix inet_proto_csum_replace_by_diff for IPv6 This patchset fixes a bug that causes skb->csum to hold an incorrect value when calling inet_proto_csum_replace_by_diff for an IPv6 packet in CHECKSUM_COMPLETE state. This bug affects BPF helper bpf_l4_csum_replace and IPv6 ILA in adj-transport mode. In those cases, inet_proto_csum_replace_by_diff updates the L4 checksum field after an IPv6 address change. These two changes cancel each other in terms of checksum, so skb->csum shouldn't be updated. v2: https://lore.kernel.org/[email protected] ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 44abca1 + ead7f9b commit 5584289

File tree

6 files changed

+13
-8
lines changed

6 files changed

+13
-8
lines changed

include/net/checksum.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
152152
const __be32 *from, const __be32 *to,
153153
bool pseudohdr);
154154
void inet_proto_csum_replace_by_diff(__sum16 *sum, struct sk_buff *skb,
155-
__wsum diff, bool pseudohdr);
155+
__wsum diff, bool pseudohdr, bool ipv6);
156156

157157
static __always_inline
158158
void inet_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb,

include/uapi/linux/bpf.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2056,6 +2056,7 @@ union bpf_attr {
20562056
* for updates resulting in a null checksum the value is set to
20572057
* **CSUM_MANGLED_0** instead. Flag **BPF_F_PSEUDO_HDR** indicates
20582058
* that the modified header field is part of the pseudo-header.
2059+
* Flag **BPF_F_IPV6** should be set for IPv6 packets.
20592060
*
20602061
* This helper works in combination with **bpf_csum_diff**\ (),
20612062
* which does not update the checksum in-place, but offers more
@@ -6072,6 +6073,7 @@ enum {
60726073
BPF_F_PSEUDO_HDR = (1ULL << 4),
60736074
BPF_F_MARK_MANGLED_0 = (1ULL << 5),
60746075
BPF_F_MARK_ENFORCE = (1ULL << 6),
6076+
BPF_F_IPV6 = (1ULL << 7),
60756077
};
60766078

60776079
/* BPF_FUNC_skb_set_tunnel_key and BPF_FUNC_skb_get_tunnel_key flags. */

net/core/filter.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1968,10 +1968,11 @@ BPF_CALL_5(bpf_l4_csum_replace, struct sk_buff *, skb, u32, offset,
19681968
bool is_pseudo = flags & BPF_F_PSEUDO_HDR;
19691969
bool is_mmzero = flags & BPF_F_MARK_MANGLED_0;
19701970
bool do_mforce = flags & BPF_F_MARK_ENFORCE;
1971+
bool is_ipv6 = flags & BPF_F_IPV6;
19711972
__sum16 *ptr;
19721973

19731974
if (unlikely(flags & ~(BPF_F_MARK_MANGLED_0 | BPF_F_MARK_ENFORCE |
1974-
BPF_F_PSEUDO_HDR | BPF_F_HDR_FIELD_MASK)))
1975+
BPF_F_PSEUDO_HDR | BPF_F_HDR_FIELD_MASK | BPF_F_IPV6)))
19751976
return -EINVAL;
19761977
if (unlikely(offset > 0xffff || offset & 1))
19771978
return -EFAULT;
@@ -1987,7 +1988,7 @@ BPF_CALL_5(bpf_l4_csum_replace, struct sk_buff *, skb, u32, offset,
19871988
if (unlikely(from != 0))
19881989
return -EINVAL;
19891990

1990-
inet_proto_csum_replace_by_diff(ptr, skb, to, is_pseudo);
1991+
inet_proto_csum_replace_by_diff(ptr, skb, to, is_pseudo, is_ipv6);
19911992
break;
19921993
case 2:
19931994
inet_proto_csum_replace2(ptr, skb, from, to, is_pseudo);

net/core/utils.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -473,11 +473,11 @@ void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb,
473473
EXPORT_SYMBOL(inet_proto_csum_replace16);
474474

475475
void inet_proto_csum_replace_by_diff(__sum16 *sum, struct sk_buff *skb,
476-
__wsum diff, bool pseudohdr)
476+
__wsum diff, bool pseudohdr, bool ipv6)
477477
{
478478
if (skb->ip_summed != CHECKSUM_PARTIAL) {
479479
csum_replace_by_diff(sum, diff);
480-
if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr)
480+
if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr && !ipv6)
481481
skb->csum = ~csum_sub(diff, skb->csum);
482482
} else if (pseudohdr) {
483483
*sum = ~csum_fold(csum_add(diff, csum_unfold(*sum)));

net/ipv6/ila/ila_common.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ static void ila_csum_adjust_transport(struct sk_buff *skb,
8686

8787
diff = get_csum_diff(ip6h, p);
8888
inet_proto_csum_replace_by_diff(&th->check, skb,
89-
diff, true);
89+
diff, true, true);
9090
}
9191
break;
9292
case NEXTHDR_UDP:
@@ -97,7 +97,7 @@ static void ila_csum_adjust_transport(struct sk_buff *skb,
9797
if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
9898
diff = get_csum_diff(ip6h, p);
9999
inet_proto_csum_replace_by_diff(&uh->check, skb,
100-
diff, true);
100+
diff, true, true);
101101
if (!uh->check)
102102
uh->check = CSUM_MANGLED_0;
103103
}
@@ -111,7 +111,7 @@ static void ila_csum_adjust_transport(struct sk_buff *skb,
111111

112112
diff = get_csum_diff(ip6h, p);
113113
inet_proto_csum_replace_by_diff(&ih->icmp6_cksum, skb,
114-
diff, true);
114+
diff, true, true);
115115
}
116116
break;
117117
}

tools/include/uapi/linux/bpf.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2056,6 +2056,7 @@ union bpf_attr {
20562056
* for updates resulting in a null checksum the value is set to
20572057
* **CSUM_MANGLED_0** instead. Flag **BPF_F_PSEUDO_HDR** indicates
20582058
* that the modified header field is part of the pseudo-header.
2059+
* Flag **BPF_F_IPV6** should be set for IPv6 packets.
20592060
*
20602061
* This helper works in combination with **bpf_csum_diff**\ (),
20612062
* which does not update the checksum in-place, but offers more
@@ -6072,6 +6073,7 @@ enum {
60726073
BPF_F_PSEUDO_HDR = (1ULL << 4),
60736074
BPF_F_MARK_MANGLED_0 = (1ULL << 5),
60746075
BPF_F_MARK_ENFORCE = (1ULL << 6),
6076+
BPF_F_IPV6 = (1ULL << 7),
60756077
};
60766078

60776079
/* BPF_FUNC_skb_set_tunnel_key and BPF_FUNC_skb_get_tunnel_key flags. */

0 commit comments

Comments
 (0)