Security: Unbounded wire sizes enable OOM denial of service #156

Closed
opened 2026-07-29 18:34:28 +02:00 by TapTap · 0 comments
Owner

Description

receive_data() and receive_str() read an 8-byte (or sizeof(size_t)) length field from the peer and then malloc() that many bytes without any upper bound or sanity check. A malicious client or server can send a very large length value and cause the peer to allocate an enormous amount of memory, leading to denial of service.

Affected functions:

  • src/shared/protocol.c:176-189receive_data() reads unsigned long long size and does malloc((size_t)size).
  • src/shared/protocol.c:150-164receive_str() reads size_t size and does malloc(size + 1).
  • src/shared/file.c:521-529receive_manifest() reads an int count from the network and loops count times, receiving strings; a huge value can exhaust memory or spin forever.
  • src/shared/chunk.c:98-109 and :149-160chunk_deserialize() reads path_len and file_data_size as size_t from the wire and allocates them directly.

On 32-bit platforms, the unsigned long long to size_t cast in receive_data() can also silently truncate a huge value, causing a small buffer to be allocated for a large receive.

Reproduction scenario

A peer sends a receive_data header where size is 0xFFFFFFFFFFFFFFFF. The target calls malloc((size_t)-1) and either fails or consumes all available memory.

Suggested fix

  1. Define a maximum allowable message size (e.g., MAX_WIRE_SIZE, possibly derived from available memory or a sensible cap like 1 GB).
  2. In receive_data() and receive_str(), reject lengths greater than MAX_WIRE_SIZE before allocating.
  3. In receive_manifest(), bound the count to a reasonable number of files per transfer.
  4. In chunk_deserialize(), validate path_len and file_data_size against the remaining chunk bytes and the global cap.

Severity

High

Category

security


This issue was automatically generated by the issue-creator agent.

## Description `receive_data()` and `receive_str()` read an 8-byte (or `sizeof(size_t)`) length field from the peer and then `malloc()` that many bytes without any upper bound or sanity check. A malicious client or server can send a very large length value and cause the peer to allocate an enormous amount of memory, leading to denial of service. Affected functions: - `src/shared/protocol.c:176-189` — `receive_data()` reads `unsigned long long size` and does `malloc((size_t)size)`. - `src/shared/protocol.c:150-164` — `receive_str()` reads `size_t size` and does `malloc(size + 1)`. - `src/shared/file.c:521-529` — `receive_manifest()` reads an `int count` from the network and loops `count` times, receiving strings; a huge value can exhaust memory or spin forever. - `src/shared/chunk.c:98-109` and `:149-160` — `chunk_deserialize()` reads `path_len` and `file_data_size` as `size_t` from the wire and allocates them directly. On 32-bit platforms, the `unsigned long long` to `size_t` cast in `receive_data()` can also silently truncate a huge value, causing a small buffer to be allocated for a large receive. ## Reproduction scenario A peer sends a `receive_data` header where `size` is `0xFFFFFFFFFFFFFFFF`. The target calls `malloc((size_t)-1)` and either fails or consumes all available memory. ## Suggested fix 1. Define a maximum allowable message size (e.g., `MAX_WIRE_SIZE`, possibly derived from available memory or a sensible cap like 1 GB). 2. In `receive_data()` and `receive_str()`, reject lengths greater than `MAX_WIRE_SIZE` before allocating. 3. In `receive_manifest()`, bound the count to a reasonable number of files per transfer. 4. In `chunk_deserialize()`, validate `path_len` and `file_data_size` against the remaining chunk bytes and the global cap. ## Severity High ## Category security --- _This issue was automatically generated by the issue-creator agent._
TapTap added the bugsecurityneeds-triage labels 2026-07-29 18:34:28 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: TapTap/FastSync#156