Re: [PATCH net] inet_diag: make bytecode audit O(n) to prevent CPU DoS

From: Eric Dumazet

Date: Mon Jul 27 2026 - 12:36:24 EST


On Mon, Jul 27, 2026 at 5:39 PM Yizhou Zhao
<zhaoyz24@xxxxxxxxxxxxxxxxxxxxx> wrote:
>
> inet_diag: make bytecode audit O(n) to prevent CPU DoS
>
> inet_diag_bc_audit() validates the user-supplied INET_DIAG_REQ_BYTECODE
> filter of a SOCK_DIAG dump request. It runs synchronously in the sender's
> sendmsg() at dump start, before any socket is iterated.
>
> The audit's outer loop walks one opcode per iteration following the
> yes-chain, and for every non-NOP opcode whose 'no' branch stays inside the
> buffer it calls valid_cc(bytecode, bytecode_len, len - op->no). valid_cc()
> re-walks the bytecode from offset 0 following yes-jumps until it reaches
> the target offset. This is O(n) per opcode, nested inside the O(n) outer
> loop, making the whole audit O(n^2) in the bytecode length.
>
> NETLINK_SOCK_DIAG is reachable by unprivileged users (diag_nlsk is created
> with NL_CFG_F_NONROOT_RECV, the SOCK_DIAG_BY_FAMILY dump path has no
> capability gate, and netlink_sendmsg skips the NL_CFG_F_NONROOT_SEND check
> when dst_portid == 0 && dst_group == 0). The bytecode length is bounded
> only by the u16 nla_len cap (~64 KB), so a local unprivileged attacker can
> submit a ~64 KB bytecode of JMP ops {yes=4, no=4} that passes every
> validation check, is accepted, and forces ~n^2/2 (~1.3e8) inner iterations
> per request, pinning a CPU for hundreds of milliseconds; concurrent
> requests pin all CPUs. The burn happens at dump start, so it occurs even
> when zero sockets match.
>
> Replace the repeated from-start re-walk with a single-pass bitmap
> reachability check that preserves the exact semantics of valid_cc().
> Allocate one bit per 4-byte slot: when an opcode's 'no' branch targets an
> offset strictly inside the buffer (op->no < len), set the bit for that
> target; when the yes-chain later arrives at an offset, clear its bit
> (proving it is a reachable opcode boundary). After the walk, any bit still
> set marks a 'no' target the yes-chain never lands on -- i.e. it points
> mid-opcode or at an unreachable op -- which is exactly the condition
> valid_cc() rejected, so the audit returns -EINVAL. Each opcode now does
> O(1) bitmap work, making the audit O(n).

Say no to kernel bloat.

If a use wants to eat cpu cycles, I see no reason to be nice.

We have generic ways to deal with this nowadays.

grep PREEMPT .config