[Bug 3912] New: sftp-server: Unbounded loop in `process_extended_copy_data` allows authenticated resource exhaustion
bugzilla-daemon at mindrot.org
bugzilla-daemon at mindrot.org
Tue Jan 27 00:07:32 AEDT 2026
https://bugzilla.mindrot.org/show_bug.cgi?id=3912
Bug ID: 3912
Summary: sftp-server: Unbounded loop in
`process_extended_copy_data` allows authenticated
resource exhaustion
Product: Portable OpenSSH
Version: 10.2p1
Hardware: 68k
OS: Linux
Status: NEW
Severity: normal
Priority: P5
Component: sftp
Assignee: unassigned-bugs at mindrot.org
Reporter: xiangwei1895 at gmail.com
Created attachment 3935
--> https://bugzilla.mindrot.org/attachment.cgi?id=3935&action=edit
poc
### 1. Summary
The `process_extended_copy_data()` function in `sftp-server.c` contains
a logic flaw when handling the `copy-data` extension.
When a client sends a request with `read_len` set to **0**, the server
enters an "infinite copy" mode (`copy_until_eof = 1`) without any
safety bounds. The copy loop lacks:
1. A maximum size limit (e.g., `SFTP_MAX_COPY`).
2. A timeout mechanism.
3. A check for interrupts.
This allows an authenticated user to trigger a blocking operation that
hangs the `sftp-server` subprocess indefinitely, potentially leading to
resource exhaustion (consuming `MaxStartups`/`MaxSessions` slots) or
zombie processes.
### 2. Technical Analysis
**File:** `sftp-server.c`
**Function:** `process_extended_copy_data` (lines ~1605-1691)
The vulnerability is triggered by this logic block:
```c
/* sftp-server.c:1628 */
if (read_len == 0) {
read_len = (u_int64_t)-1 - read_off; /* Effectively infinite */
copy_until_eof = 1;
}
```
Subsequently, the code enters a `while` loop that calls `atomicio`:
```c
/* sftp-server.c:1659 */
while (read_len > 0 || copy_until_eof) {
len = MINIMUM(sizeof(buf), read_len);
/* BLOCKING CALL: No timeout, no interrupt check */
ret = atomicio(read, read_fd, buf, len);
if (ret == 0 && errno == EPIPE) {
status = copy_until_eof ? SSH2_FX_OK : SSH2_FX_EOF;
break;
}
/* ... write logic ... */
}
```
If the source file descriptor (`read_fd`) is a blocking resource (e.g.,
a pipe, a very large file, or a special device), the `sftp-server`
process will block or busy-loop here indefinitely, becoming
unresponsive to other SFTP commands in the same session.
### 3. Reproduction Steps
**Pre-requisites:**
* A valid SSH account on the target server.
* Python 3 with `paramiko`.
**Steps:**
1. **Setup**: Monitor the server process using `ps aux | grep
sftp-server`.
2. **Execution**: Run the attached Proof-of-Concept script:
`python3 sftp_dos_poc.py --host [TARGET_IP] --user [USERNAME] --pass
[PASSWORD]`
*(See attachment: `sftp_dos_poc.py`)*
3. **Observation**:
* The script sends a `copy-data` request with `read_len=0`.
* The server-side `sftp-server` process enters a blocked state (State
`S+` or `D+`).
* The SSH session becomes unresponsive.
4. **Verification**:
Attaching `strace` to the PID reveals the process is stuck in the
read/write loop:
```bash
$ sudo strace -p [PID]
# Output shows repeating IO calls without exit:
read(3, "...", 4096) = 4096
write(3, "...", 4096) = 4096
...
```
### 4. Impact
* **Resource Exhaustion**: An attacker can exhaust `MaxStartups` or
`MaxSessions` limits by spawning multiple hanging sessions.
* **Zombie Processes**: Requires manual administrator intervention
(kill) to clear the hung processes.
* **Scope**: Authenticated DoS (requires valid credentials).
--
You are receiving this mail because:
You are watching the assignee of the bug.
More information about the openssh-bugs
mailing list