[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