NullRabbit
cohort.v1
← Back to Research
Research · June 26, 2026

The same method, pointed at the packet path

Simon Morley·5 min read

The HTTP work and the kernel work look unrelated from the outside. They are the same method in different clothes, and this post is about the clothes.

The Linux kernel reassembles network packets before any application sees a byte. A flood of small packets arriving on a busy server gets coalesced into bigger units on the way in (the kernel calls this GRO) and split back apart on the way out (GSO). It is a performance trick, and it is implemented not once but roughly a dozen times. TCP has its handler, UDP has its own, tunnelling protocols have theirs, and each one independently honours the same contract: coalesce these packets, track the lengths, re-segment them correctly. Read that description again and you will hear the HTTP story in it. It is a parser family. Many implementations, one shared contract, and the interesting question is always the same. Which one omits the length check the others enforce?

That is the convergent-design lens, and it is exactly what we used on blockchain transports and on HTTP proxies. So we retargeted it at the kernel, and we did it the only way that is responsible: through Google's sanctioned kernel bug-bounty programs. Everything runs in a local lab or on the program's own infrastructure, every finding is coordinated with kernel maintainers, and the output is a fix in upstream Linux. The bounty is the incentive. Hardening the kernel everyone runs is the result.

Why the packet path specifically? Because the other doors are closing. The kernel hardening that shipped across 2025 deliberately switched off several of the most productive bug-factory subsystems for unprivileged attackers. What remains as a rich surface reachable by an ordinary, unprivileged process is the packet receive-and-reassembly path, and reassembly is exactly where our prior work lives. Reassembly is where two pieces of code disagree about where a message ends. We have been mining that seam for years, and the kernel turned out to have one of the biggest examples of it.

The lens points at concrete things. There is a coalescing path an unprivileged process can steer traffic into with a single socket option, no special privilege required, that flows through the segment-and-resegment code with a hard size cap, and a hard cap on a length is exactly the kind of boundary where off-by-one math goes wrong. There is a core re-segmentation routine that several protocols funnel into, with awkward edge cases around zero-sized segments. And there is the kind of asymmetry the convergent lens exists to catch: a defensive check that one protocol's handler performs before handing off, and that its sibling handler appears to skip. Each of those is a candidate, a thing to read carefully and then prove, never a thing to announce.

There is a second idea worth naming, because it is a direct port. In the validator work we use a timing differential to prove a crafted packet actually reaches the deep code path we are targeting, rather than getting rejected at the door. Call it differential reachability as a coverage oracle. The same trick works in the kernel. You can show a malformed packet is reaching the deep reassembly stage before anything faults, instead of guessing. Coverage you can prove beats coverage you assume.

And a third: we watch the upstream fix stream, not the CVE feed. When a network fix lands in the mainline kernel tree, there is a window, a couple of weeks and sometimes more, before it is backported to the long-term-support kernels deployed in the wild. The fix is public and the bug is now readable in the patch, but the mitigation has not shipped everywhere. Watching that window is how you find a one-day before anyone has labelled it a one-day. So we built a tracker that does exactly that. It pulls the network fixes, checks which ones touch code present in the deployed kernel, and ranks them by how corruption-shaped and how unprivileged-reachable they look.

Now the part that matters most, and it is the same value we hold in every post. We measured our own opportunity, and we reported the real number.

We ran the tracker. We read the candidates. And on a freshly rotated kernel, with the 2025 hardening in force, almost every promising lead failed a single brutal filter: it needed a privilege an unprivileged attacker does not have. A genuinely unpatched memory-corruption bug that needed an admin capability to reach. A high-scoring fix that turned out to be root-only. One by one, the candidates that looked like money turned out to be gated. The honest conclusion was that the gap on a fresh kernel is thin, and we wrote that down as plainly as we would have written down a win.

That is not a failure, it is the method working. The same discipline that made us retract a validator finding when the baseline turned out to be a config artefact made us say "thin gap, not now" here, instead of talking ourselves into a candidate. The tracker keeps running, because the gap widens as a deployed kernel ages and new fixes pile up un-backported. The fuzzing harnesses are built and staged for the surface the lens points at. When the gap opens, we will be reading it.

But the headline is the part people skip. A security researcher's most valuable habit is being willing to measure their own story and report it honestly, even when the honest answer is "there is nothing here yet." If we will do that to our own opportunity, you can trust what we do to a finding before we hand it to you.

Simon Morley researches infrastructure security and is the founder of NullRabbit. About / contact.

security-researchlinux-kernelmethodologydisclosurefuzzing

Related Posts