Re: [PATCH net v5 3/4] selftests: net: Test UDP length overflow with PMTU discover and big MTU
From: netdev-bot+sashiko@kernel.org
Date: 2026-09-04 10:57:41
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider: Critical: 0 · High: 0 · Medium: 2 · Low: 3 - [Medium] tools/testing/selftests/net/cork_fragsize.py:38 uses a PEP 604 union annotation (`def check_kernel_config(option: str) -> bool |… - [Medium] check_dmesg_clean() (cork_fragsize.py:72-79) greps the whole retained kernel ring buffer for `WARNING:.*<func>` after the send,… - [Low] The `return None` at cork_fragsize.py:57 (last statement of the `for` body in check_kernel_config()) is unreachable: the `try` block… - [Low] assert_debug_kernel() (cork_fragsize.py:60-69) treats an unreadable kernel configuration as "assume debug kernel and run the… - [Low] check_dmesg_clean()'s docstring (cork_fragsize.py:73-75) says "Check if the given function produced a WARN in dmesg", which is the… -- selftests: net: Test UDP length overflow with PMTU discover and big MTU This adds a new python selftest, cork_fragsize.py, that sends an oversized UDP datagram over a dummy netdev with a very large MTU while IP(V6)_MTU_DISCOVER is set, and checks both the sendto() errno and dmesg. A third test verifies UDP jumbograms over a raw IPv6 socket still work. A few questions about the new test below.
quoted hunk ↗ jump to hunk
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index 517c09d60bef7..3ee3378f8b26e 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile@@ -25,6 +25,7 @@ TEST_PROGS := \ cmsg_so_mark.sh \ cmsg_so_priority.sh \ cmsg_time.sh \ + cork_fragsize.py \ double_udp_encap.sh \ drop_monitor_tests.sh \ ecmp_rehash.sh \diff --git a/tools/testing/selftests/net/cork_fragsize.py b/tools/testing/selftests/net/cork_fragsize.py new file mode 100755 index 0000000000000..7afd643d07ec2 --- /dev/null +++ b/tools/testing/selftests/net/cork_fragsize.py@@ -0,0 +1,187 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 + +'''Test possible UDP length overflow in udp_send_skb/udp_v6_send_skb.''' + +import errno +import gzip +import os +import socket +import struct +import subprocess +from contextlib import contextmanager
[ ... ]
+def check_kernel_config(option: str) -> bool | None:
[Severity: Medium] Does this signature work on the minimum supported interpreter? Documentation/process/changes.rst lists: Python 3.9.x python3 --version The PEP 604 union syntax "bool | None" in a function annotation is evaluated eagerly when the def statement executes, i.e. at module import, and type.__or__ only exists from CPython 3.10. Without "from __future__ import annotations" in the file, would importing this on a 3.9 host raise: TypeError: unsupported operand type(s) for |: 'type' and 'NoneType' before ksft_run() is reached, so that the entry just added to TEST_PROGS reports a hard error instead of running or skipping the two UDP tests? Would typing.Optional[bool], or the future import, avoid this? The other new annotations in the file (tuple[int, int, int], -> None) are fine on 3.9.
+ '''
+ Check whether the option is enabled in the config of the running kernel.
+ Returns None if the config is not found; otherwise returns True/False
+ depending on the option value in the config.
+ '''
+
+ for filename, method in [
+ ('/proc/config.gz', gzip.open),
+ (f'/boot/config-{os.uname().release}', open),
+ ]:
+ try:
+ with method(filename, 'rt') as config:
+ for line in config:
+ if line.rstrip() == f'{option}=y':
+ return True
+ return False
+ except OSError:
+ continue
+ return None[Severity: Low] Is this return None reachable? It sits at the end of the for body, but the try block always returns (True on match, False once the file is exhausted) and the only other path is "except OSError: continue", which restarts the loop. The documented "Returns None if the config is not found" behaviour comes from falling off the end of the loop after both candidates raise OSError. If the try/except were ever reworked so that the statement did execute, it would also stop the /boot/config-$(uname -r) candidate from being tried. Was this meant to be dedented out of the loop, or dropped?
+
+
+def assert_debug_kernel() -> None:
+ '''
+ Skip the test if CONFIG_DEBUG_NET is not set in the kernel config.
+ '''
+
+ res = check_kernel_config('CONFIG_DEBUG_NET')
+ if res is None:
+ ksft_pr("WARN: Can't read kernel config; assuming debug kernel, and running the test")
+ elif not res:
+ raise KsftSkipEx('CONFIG_DEBUG_NET is not set')[Severity: Low] Should an unreadable config be treated as satisfying the CONFIG_DEBUG_NET precondition rather than as a skip? On a kernel built without CONFIG_IKCONFIG_PROC and with no /boot/config-* file, check_kernel_config() returns None and the test proceeds. If CONFIG_DEBUG_NET happens to be off, the warning the ipv4 variant depends on does not exist at all: include/net/net_debug.h: #define DEBUG_NET_WARN_ON_ONCE(cond) BUILD_BUG_ON_INVALID(cond) An unfixed kernel then emits nothing, sendto() still returns EMSGSIZE from ip_fragment(), check_dmesg_clean() reports clean, and the ipv4 variant passes with the overflow still present. Would KsftSkipEx be a safer default here?
+ + +def check_dmesg_clean(func: str) -> bool: + ''' + Check if the given function produced a WARN in dmesg. + '''
[Severity: Low] Is this docstring inverted with respect to the return value? grep exits 0 on a match, so "res.returncode != 0" means no warning was found, and True means "clean", which matches the function name but not the comment. A future caller following the docstring would invert the verdict of the test.
+
+ with subprocess.Popen(['dmesg'], stdout=subprocess.PIPE) as dmesg:
+ res = subprocess.run(['grep', '-q', f'WARNING:.*{func}'], stdin=dmesg.stdout, check=False)
+ return res.returncode != 0 and dmesg.returncode == 0
[Severity: Medium]
Can this grep of the whole retained ring buffer misreport in both
directions? There is no pre-test snapshot, message count, timestamp filter
or dmesg -C to bound the window.
False failure: any earlier "WARNING:" line in this boot whose text contains
udp_send_skb or udp_v6_send_skb, including a previous run of this same test
in the same boot, makes a correctly fixed kernel report:
not ok ... WARNING detected in dmesg
False pass: the diagnostic being consumed fires once per boot per site,
include/linux/udp.h:udp_set_len_short() {
DEBUG_NET_WARN_ON_ONCE(len >= GRO_LEGACY_MAX_SIZE);
}
so if that record has already scrolled out of a wrapped buffer, or was
already consumed, the oversized send leaves no visible record. For the
ipv4 variant the errno cannot discriminate either, since __ip_append_data()
returns -EMSGSIZE on a fixed kernel and ip_fragment() returns -EMSGSIZE on
an unfixed one after the warning, which the test docstring notes. So a
still-broken kernel can pass.
Other net selftests bound the window with before/after counts, for example
fib_nexthops.sh and openvswitch/openvswitch.sh. Would recording a dmesg
boundary before the send, and grepping only what was added, be more
reliable here?
Separately, does the "and dmesg.returncode == 0" term conflate two
different failures? If dmesg itself exits non-zero, for instance under
kernel.dmesg_restrict or in an unprivileged container, the helper returns
False and the caller prints "WARNING detected in dmesg" for a warning that
was never observed. Would a distinct error or skip be clearer for that
case?
[ ... ]
+ if not ipv6: + assert_debug_kernel() + + with ( + NetNS() as ns, + dummy_netdev(ns, 65556 + 20 * ipv6, ipv6), + NetNSEnter(ns), + socket.socket(af, socket.SOCK_DGRAM) as fd, + ): + fd.setsockopt(*sockopts) + with ksft_raises(OSError) as e: + fd.sendto(b' ' * 65528, (destip, 1234)) + # IPv6: EMSGSIZE happens on kernels with the fix. + # IPv4: EMSGSIZE happens on both fixed and unfixed kernels, after the + # WARN is printed - ignore it and rely on the dmesg check. + if e.exception is not None: + ksft_eq(e.exception.errno, errno.EMSGSIZE) + + ksft_true(check_dmesg_clean(func), 'WARNING detected in dmesg')
[ ... ] -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260901195714.673548-1-alice.kernel%40fastmail.im