Problem:protocol_reserve_memory()/MAX_CONNECTION_MEMORY (256MB) only accounts for buffers from receive_data_limited(). Decompression buffers and per-file chunk_deserialize copies are NOT charged to total_allocated_bytes; only per-allocation max_alloc gates them. Multithreaded receiver enqueues up to 100 files ahead of the disk writer, each up to 64MB uncompressed. Since chunks arrive compressed, an attacker (any --allow-unauthenticated/stdio/authenticated peer) feeds the queue with little bandwidth -> heap high-water ~100*64MB = ~6.4GB per connection, up to 100 connections -> OOM host.
Fix: Charge per-file payload allocations and decompression buffers against the session memory reserve, or bound the receiver queue by bytes.
Verify with a targeted test where possible.
Found by security audit of `dev` (9f8b588).
**Where:** src/shared/chunk.c:310-338 (receive_chunk_data decompress), chunk.c:247-255 (uncharged per-file memcpy copy), src/shared/protocol.c:90-104,446-484 (reserve only covers wire buffer), src/server/server.c:298 + src/shared/multiprocessing.c:99-135 (queue depth 100).
**Problem:** `protocol_reserve_memory()`/MAX_CONNECTION_MEMORY (256MB) only accounts for buffers from receive_data_limited(). Decompression buffers and per-file chunk_deserialize copies are NOT charged to total_allocated_bytes; only per-allocation max_alloc gates them. Multithreaded receiver enqueues up to 100 files ahead of the disk writer, each up to 64MB uncompressed. Since chunks arrive *compressed*, an attacker (any --allow-unauthenticated/stdio/authenticated peer) feeds the queue with little bandwidth -> heap high-water ~100*64MB = ~6.4GB per connection, up to 100 connections -> OOM host.
**Fix:** Charge per-file payload allocations and decompression buffers against the session memory reserve, or bound the receiver queue by bytes.
Verify with a targeted test where possible.
Fixed on dev via fix/security-hardening (98120fc): receiver queue bounded by aggregate payload bytes (RECEIVER_QUEUE_MAX_BYTES) with blocking backpressure; writer releases budget per file. Unit test test_receiver_enqueue_byte_budget added. Reconciled with outcome reporting at merge (68e7ed5).
CI run #461: all jobs green (lint, build-and-test, sanitizers address+undefined, fuzz-build, coverage, valgrind). Unit 25/25, integration 83 passed / 10 skipped / 1 xpassed. Closing.
**Resolved on `dev`** (HEAD f7c6c91).
Fixed on dev via fix/security-hardening (98120fc): receiver queue bounded by aggregate payload bytes (RECEIVER_QUEUE_MAX_BYTES) with blocking backpressure; writer releases budget per file. Unit test test_receiver_enqueue_byte_budget added. Reconciled with outcome reporting at merge (68e7ed5).
CI run #461: all jobs green (lint, build-and-test, sanitizers address+undefined, fuzz-build, coverage, valgrind). Unit 25/25, integration 83 passed / 10 skipped / 1 xpassed. Closing.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Found by security audit of
dev(9f8b588).Where: src/shared/chunk.c:310-338 (receive_chunk_data decompress), chunk.c:247-255 (uncharged per-file memcpy copy), src/shared/protocol.c:90-104,446-484 (reserve only covers wire buffer), src/server/server.c:298 + src/shared/multiprocessing.c:99-135 (queue depth 100).
Problem:
protocol_reserve_memory()/MAX_CONNECTION_MEMORY (256MB) only accounts for buffers from receive_data_limited(). Decompression buffers and per-file chunk_deserialize copies are NOT charged to total_allocated_bytes; only per-allocation max_alloc gates them. Multithreaded receiver enqueues up to 100 files ahead of the disk writer, each up to 64MB uncompressed. Since chunks arrive compressed, an attacker (any --allow-unauthenticated/stdio/authenticated peer) feeds the queue with little bandwidth -> heap high-water ~100*64MB = ~6.4GB per connection, up to 100 connections -> OOM host.Fix: Charge per-file payload allocations and decompression buffers against the session memory reserve, or bound the receiver queue by bytes.
Verify with a targeted test where possible.
Resolved on
dev(HEADf7c6c91).Fixed on dev via fix/security-hardening (
98120fc): receiver queue bounded by aggregate payload bytes (RECEIVER_QUEUE_MAX_BYTES) with blocking backpressure; writer releases budget per file. Unit test test_receiver_enqueue_byte_budget added. Reconciled with outcome reporting at merge (68e7ed5).CI run #461: all jobs green (lint, build-and-test, sanitizers address+undefined, fuzz-build, coverage, valgrind). Unit 25/25, integration 83 passed / 10 skipped / 1 xpassed. Closing.