Greg Kroah-Hartman put some numbers out ahead of Kernel Recipes in Paris next month, and they read like a five-alarm fire right up until you sit with them for a minute. The Linux kernel is closing in on 2,000 CVEs per release. Linux 7.3 is probably the one that breaks through.

The slope matters more than the number. From 6.9 through 6.19 the average sat around 500 a release. Since 7.0 it's been over a thousand. Linux 7.2, out on 16 August, cleared 1,500. Call it a tripling in a little over a year.

And nobody started writing three times worse C last spring. What changed is that finding the bugs got cheap.

Everyone bought a bug-finding machine

The explanation is the unglamorous one: people are pointing LLMs at the kernel's ~34 million lines of C and letting them grind. Not one team — everyone. Vendors, academics, security shops, some guy with an API budget and a free weekend.

Static analysis could always do this in principle. In practice it needed someone who understood the kernel well enough to write the rules, sift the output and file something a maintainer wouldn't throw away on sight. That person was scarce and expensive. Now that step costs a few dollars in tokens and a prompt that says look for use-after-free.

And the part that stops this being a smug story about slop: the reports are largely real. This isn't a wave of nonsense getting bounced. It's a wave of genuine bugs that were sitting in tree, in code nobody had a commercial reason to audit — the third-tier driver for hardware nine people still own — getting surfaced at industrial scale for the first time in their lives.

The number is not a danger meter

Worth remembering what a kernel CVE actually is. The kernel has been its own CNA since 2024, and its stated position is that because of the layer it sits at, almost any bug might turn out to be exploitable, and you usually can't tell at fix time. So the team assigns numbers generously to identified fixes rather than pretending to predict which ones matter. Greg has written the process up more than once, mostly at people who are angry about it.

That policy was already contentious at 500 a release. At 2,000 it stops being contentious and starts being a category error in whatever dashboard you're feeding.

Because a CVE count produced this way doesn't measure how dangerous your kernel is. It measures how much compute got pointed at it. Those were roughly correlated for years, which is why nobody had to think about it, and they have now decoupled hard enough that reading the graph as risk means reading a scanner-throughput chart and calling it exposure.

If your compliance process counts kernel CVEs, this year is going to be exciting for you, and not in the good way.

The half that doesn't scale

Fine, so the number is inflated. The work isn't.

Every one of those CVEs has a patch attached. Somebody reviews it. Somebody backports it across the stable trees. Somebody at your distro decides whether it rides the next update or an out-of-band one. Somebody's fleet reboots. That entire half of the pipeline is people, and it did not triple.

That's the actual story, and it isn't really about Linux. Discovery now scales with GPU spend. Triage scales with Greg. You don't need a model to extrapolate that curve.

Which is why the interesting response isn't find them faster. It's stop being able to write them.

Greg's answer is a wrapper type

Back in May, at RustWeek in Utrecht, he gave a keynote with the deeply unsubtle title Untrusted data in Linux — How Rust is going to save us. The claim: roughly 80% of kernel CVEs would have been impossible to write in Rust. Coming from the person who has personally looked at every kernel security bug since the security team was formed in 2005, that's not a vibes estimate.

The specific thing he keeps running into is provenance. Data arrives from userspace, or off a wire, or out of a device's registers. It should be treated as hostile. You copy it in, and the instant it lands it's a u32 like any other u32 — the type system has forgotten where it came from, and it gets passed around like anything else. C's answer is __user annotations checked by sparse, which is an external tool people don't always run, which is a long way of saying the check is optional, which is a long way of saying it isn't a check.

So the proposal, built with Benno Lossin, is Untrusted<T>. It's a transparent newtype — an Untrusted<u8> is one byte, laid out identically, zero runtime cost, it's a marker and nothing else. And you cannot read what's inside it. To get the value you go through an explicit validation step that hands you back a trusted T.

That's the whole idea. That's it.

I wanted to be a bit rude about this and I can't manage it. Thirty years of "be careful with data from userspace" as a code review convention, answered by a struct with one field and no getter. It is almost insultingly small. But that's exactly why it works: the compiler stops depending on your discipline. Validation goes from something you remember to do to something you cannot skip, and it collapses into one visible, auditable place instead of being smeared across four hundred lines of driver.

Pair that with pushing the __user distinction properly into the type system and Greg reckons those two changes alone cover something like 60% of kernel bugs.

Naturally, it's stuck behind a compiler feature

Untrusted<T> isn't merged. It's been through four revisions, Lossin has been asking people to actually use it and report where it hurts, and the blocker is upstream in rustc: Rust can't yet project fields through a user-defined wrapper the way it does through a plain reference. Given an Untrusted<MyStruct>, there's no clean way to reach Untrusted<that_field> without hand-writing boilerplate for every field of every struct, which is precisely the kind of tax that makes people not adopt a thing. That's field projections, it's an active Rust project goal, and it is still closer to design than to implementation.

So: the structural fix for the CVE flood is a language feature that doesn't exist yet, gating a kernel API that isn't merged, written in a language that accounts for about 113,000 of the kernel's ~34 million lines.

I say that with affection. Rust in the kernel stopped being an experiment in 7.0 back in April — Ojeda's patch was literally titled conclude the Rust experiment — and 113k lines is an enormous amount of code for something that spent years being a mailing list argument. But if you're waiting on this to turn your CVE dashboard green, bring a book. A long one.

What I'd actually take from it

Two things, neither of them urgent.

First, stop reading kernel CVE counts as a risk signal, and go and find out whether anything you own does it automatically. Somewhere in most orgs there's a scanner that will start emitting four times as much noise this year for no change in actual exposure, and the failure mode isn't panic, it's fatigue — the moment the list is unreadable, people stop reading it. What still works is boring: patch cadence, a stable kernel you actually track, and reboots that happen.

Second, steal the pattern. You don't need Rust in the kernel to get the good bit. If you've got a service parsing anything from outside — request bodies, webhook payloads, a CSV a customer uploaded — the same move is available in whatever you're writing today. Newtype the untrusted thing. RawEmail and Email, not string and string. Make the only path between them a function that validates. It costs an afternoon and it converts an entire category of "we forgot to check this one" into a compile error, or at minimum a type error your reviewer can see from across the diff.

So

The headline number is nonsense and the underlying problem is real, which is an annoying combination to hold in your head at once.

What I keep coming back to is that we've just built machines that are very good at reading code for bugs, pointed them at the most-audited codebase on the planet, and found thousands. Not thousands of exotic ones — thousands of the same tired class we've been writing since the nineties, because C lets you forget where a byte came from.

The scanners are going to keep getting cheaper. The reviewing isn't. Sooner or later the only lever left is making the bug unwriteable, and it turns out that lever is a struct with one field in it.

Anyway. Go and check what your vuln scanner is counting.