diff options
| author | Madhav Khosla <madhav.khoslaa@gmail.com> | 2026-09-20 14:25:49 +0530 |
|---|---|---|
| committer | Alexei Starovoitov <ast@kernel.org> | 2026-09-22 23:53:24 +0000 |
| commit | ddaa827dcea4544ccfffa1dd85ab0ea35cd06e6d (patch) | |
| tree | 9f16286d10ca7f853c89d24b1f4aaac5513c70ea /tools/testing/selftests/bpf | |
| parent | 94809ecf9d2f9cfed27ce5c3db2fbeadd8f90965 (diff) | |
| download | linux-next-ddaa827dcea4544ccfffa1dd85ab0ea35cd06e6d.tar.gz linux-next-ddaa827dcea4544ccfffa1dd85ab0ea35cd06e6d.zip | |
selftests/bpf: Fix csum_partial() dropping trailing byte on odd length
csum_partial() computes num_u16 = len >> 1 and only sums that many
16-bit words, so the last byte of an odd-length buffer never gets
added to the checksum. RFC 1071 says it should be padded with a zero
byte and summed as one more word, not dropped.
This backs build_ip_csum(), build_udp_v4_csum() and
build_udp_v6_csum(), used by flow_dissector_classification.c and
xdp_metadata.c to hand-build packets. No current caller builds an
odd-length payload, so nothing fails today, but a future one would
get a silently wrong checksum.
Also bump flow_dissector_classification's TEST_PACKET_LEN from 100 to
99 so this actually gets exercised instead of staying latent.
f4504af68575 wrote the len >> 1 division, but it only ever passed
sizeof(iphdr), always even, so it couldn't hit the bug. Tagging
bcc00987bc56 instead, since it added the first caller,
build_udp_v4_csum()/build_udp_v6_csum(), that can pass an odd length.
Verified with test_progs under vmtest.sh: without the fix, an odd
TEST_PACKET_LEN makes the kernel drop the packet over a bad checksum
and flow_dissector_classification fails; with the fix, both
flow_dissector_classification and xdp_metadata pass.
Signed-off-by: Madhav Khosla <madhav.khoslaa@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20260920085549.867099-1-madhav.khoslaa@gmail.com
Diffstat (limited to 'tools/testing/selftests/bpf')
| -rw-r--r-- | tools/testing/selftests/bpf/network_helpers.h | 15 | ||||
| -rw-r--r-- | tools/testing/selftests/bpf/prog_tests/flow_dissector_classification.c | 2 |
2 files changed, 14 insertions, 3 deletions
diff --git a/tools/testing/selftests/bpf/network_helpers.h b/tools/testing/selftests/bpf/network_helpers.h index 75133119c04a..878c9fc5c37c 100644 --- a/tools/testing/selftests/bpf/network_helpers.h +++ b/tools/testing/selftests/bpf/network_helpers.h @@ -129,12 +129,23 @@ static __u16 csum_fold(__u32 csum) static __wsum csum_partial(const void *buf, int len, __wsum sum) { - __u16 *p = (__u16 *)buf; + const __u8 *p = buf; int num_u16 = len >> 1; int i; for (i = 0; i < num_u16; i++) - sum += p[i]; + sum += ((const __u16 *)p)[i]; + + /* + * RFC 1071: an odd-length buffer's trailing byte is paired with + * a zero pad byte to form the final 16-bit word. + */ + if (len & 1) { + __u16 tail = 0; + + __builtin_memcpy(&tail, p + len - 1, 1); + sum += tail; + } return sum; } diff --git a/tools/testing/selftests/bpf/prog_tests/flow_dissector_classification.c b/tools/testing/selftests/bpf/prog_tests/flow_dissector_classification.c index 80b153d3ddec..421dfa6c4ea3 100644 --- a/tools/testing/selftests/bpf/prog_tests/flow_dissector_classification.c +++ b/tools/testing/selftests/bpf/prog_tests/flow_dissector_classification.c @@ -27,7 +27,7 @@ #define TEST_NAME_MAX_LEN (32 + SUBTEST_NAME_MAX_LEN) #define MAX_SOURCE_PORTS 3 #define TEST_PACKETS_COUNT 10 -#define TEST_PACKET_LEN 100 +#define TEST_PACKET_LEN 99 #define TEST_PACKET_PATTERN 'a' #define TEST_IPV4 "192.168.0.1/32" #define TEST_IPV6 "100::a/128" |
