I guess we're gonna see a lot of these issues over the years. Even TCP still has some novel attack vector for a DoS once a decade or so today, and it is a dinosaur conceived when the default assumption was that everyone is playing nice on the Internet.
Surprising to see that a protocol designed today still allows for such trivial resource exhaustion attacks. And thanks to the protocol living in user space, we're guaranteed that vulnerable implementations will live on for years to come in docker containers, smartphone apps, etc. (Granted in this case it seems not that bad at least for the latter since this affects servers.)
I'd argue that the decision to keep it in userspace was the right one. If an application doesn't get security updates, a broken QUIC stack is probably the least of your worries.
You also mention Android, which is notorious for having a lot of devices that don't get OS updates because they've reached end-of-life.
Protocol ossification at the OS level is also a valid concern.
Resource exhaustion attacks have gotten much, much worse over the past decade.
The "modern" way to do things is to have a connection/session for everything you do. This means state allocation for everything you do, which means resource exhaustion attacks everywhere. It has turned the internet into a fragile mess that can't survive without a godlike cloudflare to sweep all the resource exhaustion attacks under the rug.
Hey I know, let's make DNS use TCP! What could go wrong.
Bittorrent survives and even thrives in the face of constant active MPAA-funded attacks, because its DHT doesn't use sessions. IPFS collapses under its own weight because it does.
Wireguard is the only silver lining in all of this. I think it's the only major sessionless protocol introduced in the last decade. The cookie scheme it uses to avoid sessions is genius (and Rosenpass has an improved version that avoids creating a circular dependency with NTP).
Good writeup, but can you point to where in the spec this behavior is mandated? I'm looking at section 8.2 of RFC 9000, and I see nothing implying a requirement to maintain an unbounded queue of un-acked PATH_CHALLENGE packets. The closest I can find is the final sentence in 8.2.1:
> Unlike other cases where datagrams are expanded, endpoints MUST NOT discard datagrams that appear to be too small when they contain PATH_CHALLENGE or PATH_RESPONSE.
But I don't read it as saying never to discard PATH_CHALLENGE packets, only that the implementation should refrain from filtering out such packets on the basis of them being too small.
So this strikes me as an implementation flaw, not an inherent weakness of the protocol.
Yeah, seems suspicious. PATH_CHALLENGE frame is used to determine if a path is valid in the first place. It seems like the correct operation of a client can not possibly depend on lossless responses since, by its very nature, the client must expect that it might be sending packets on a path to the void.
There is no way for a client to distinguish between a invalid path and a server packet drop, so a server that randomly drops such frames seems externally indistinguishable from a “compliant” one. For that matter, you can even characterize that as a path to the server that is “temporarily invalid” which follows the letter of the spec.
The only problem that may exist here is if the spec actually demands such a undetectable, unenforceable, irrelevant requirement.
Surprising to see that a protocol designed today still allows for such trivial resource exhaustion attacks. And thanks to the protocol living in user space, we're guaranteed that vulnerable implementations will live on for years to come in docker containers, smartphone apps, etc. (Granted in this case it seems not that bad at least for the latter since this affects servers.)