]> git.ipfire.org Git - thirdparty/openssh-portable.git/commitdiff
upstream: avoid situation where sftp_download() could get stuck in
authordjm@openbsd.org <djm@openbsd.org>
Mon, 29 Jun 2026 01:53:21 +0000 (01:53 +0000)
committerDamien Miller <djm@mindrot.org>
Mon, 29 Jun 2026 02:19:49 +0000 (12:19 +1000)
a loop if a broken server repeatedly returned zero length while reading a
file. Identified by Swival scanner

OpenBSD-Commit-ID: 53f1de5065ff01952d2abb51747c2418ce21cd96

sftp-client.c

index 69ef28cdc16bc4f476c5a93c2178018a83b55f6c..1f031128e141e11f6836a622b109a3f599dbc46a 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp-client.c,v 1.185 2026/03/03 09:57:25 dtucker Exp $ */
+/* $OpenBSD: sftp-client.c,v 1.186 2026/06/29 01:53:21 djm Exp $ */
 /*
  * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
  *
@@ -1585,7 +1585,7 @@ sftp_download(struct sftp_conn *conn, const char *remote_path,
 {
        struct sshbuf *msg;
        u_char *handle;
-       int local_fd = -1, write_error;
+       int local_fd = -1, write_error, seen_zerolen = 0;
        int read_error, write_errno, lmodified = 0, reordered = 0, r;
        uint64_t offset = 0, size, highwater = 0, maxack = 0;
        u_int mode, id, buflen, num_req, max_req, status = SSH2_FX_OK;
@@ -1733,6 +1733,11 @@ sftp_download(struct sftp_conn *conn, const char *remote_path,
                        if (len > req->len)
                                fatal("Received more data than asked for "
                                    "%zu > %zu", len, req->len);
+                       if (len == 0) {
+                               if (seen_zerolen)
+                                       fatal_f("server sent zero data length");
+                               seen_zerolen = 1;
+                       }
                        lmodified = 1;
                        if ((lseek(local_fd, req->offset, SEEK_SET) == -1 ||
                            atomicio(vwrite, local_fd, data, len) != len) &&
@@ -2446,7 +2451,7 @@ sftp_crossload(struct sftp_conn *from, struct sftp_conn *to,
     Attrib *a, int preserve_flag)
 {
        struct sshbuf *msg;
-       int write_error, read_error, r;
+       int write_error, read_error, r, seen_zerolen = 0;
        uint64_t offset = 0, size;
        u_int id, buflen, num_req, max_req, status = SSH2_FX_OK;
        u_int num_upload_req;
@@ -2576,6 +2581,11 @@ sftp_crossload(struct sftp_conn *from, struct sftp_conn *to,
                        if (len > req->len)
                                fatal("Received more data than asked for "
                                    "%zu > %zu", len, req->len);
+                       if (len == 0) {
+                               if (seen_zerolen)
+                                       fatal_f("server sent zero data length");
+                               seen_zerolen = 1;
+                       }
 
                        /* Write this chunk out to the destination */
                        sshbuf_reset(msg);