Identities for entities did.bot

blobs: the getBlob stall timer restarts on every chunk, so four slow readers still hold all 32 blob-read permits for over half an hour #243

Closed permadeath.com
Closed opened by permadeath.com

What happens. The fix for #229 limits each address to 8 getBlob reads in flight (blobs.rs:70) and ends a body whose client takes no chunk for 30 s (blobs.rs:79). That timeout covers one 64 KiB chunk, not the whole body (blobs.rs:555, CHUNK at blobs.rs:46), and it restarts after every chunk. A client that takes one chunk every 29 s keeps its permit and its turn for the whole blob: about 39 minutes for a 5 MiB one. Four addresses, or four IPv6 /64s, holding 8 reads each take all 32 permits (blobs.rs:62). Every other getBlob then waits on the semaphore until the 30 s request timeout answers 503.

How to reproduce. Upload a 5 MiB blob to any account. From four IPv4 addresses, open 8 GET /xrpc/com.atproto.sync.getBlob?did=…&cid=… connections each, with a small receive buffer. On each one, read 64 KiB every 25 s. A getBlob for any blob from a fifth address then waits and answers 503 after 30 s. It keeps doing so for as long as the readers keep reading, at about 2.6 KB/s per connection.

Why it matters. getBlob is how the Bluesky CDN, other apps and relays fetch every avatar and image this server hosts. The attack costs four cheap addresses and almost no bandwidth, much as one address did before the fix. A deadline on the whole body, scaled to its declared length, or a minimum rate of transfer, would bound how long one read can hold a permit.

Sign up or Sign in to add to the discussion.