malware: avoid slurping entire spoolfile for sending to ClamAV
authorJeremy Harris <jgh146exb@wizmail.org>
Thu, 31 Dec 2020 22:18:30 +0000 (22:18 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Thu, 31 Dec 2020 22:18:30 +0000 (22:18 +0000)
src/src/malware.c

index 03bb832fc0131795bb1cb6858162ba0ba28f5507..2883f225af4b7c526940c530ad65583f4a790ebc 100644 (file)
@@ -1445,7 +1445,6 @@ badseek:  err = errno;
       host_item connhost;
       uschar *clamav_fbuf;
       int clam_fd, result;
-      off_t fsize;
       unsigned int fsize_uint;
       BOOL use_scan_command = FALSE;
       clamd_address * cv[MAX_CLAMD_SERVERS];
@@ -1621,6 +1620,7 @@ badseek:  err = errno;
 
       if (!use_scan_command)
        {
+       struct stat st;
        /* New protocol: "zINSTREAM\n" followed by a sequence of <length><data>
        chunks, <n> a 4-byte number (network order), terminated by a zero-length
        chunk. */
@@ -1637,7 +1637,6 @@ badseek:  err = errno;
                strerror(errno)),
              malware_daemon_ctx.sock);
 
-       /* calc file size */
        if ((clam_fd = exim_open2(CS eml_filename, O_RDONLY)) < 0)
          {
          int err = errno;
@@ -1646,61 +1645,51 @@ badseek:  err = errno;
              eml_filename, strerror(err)),
            malware_daemon_ctx.sock);
          }
-       if ((fsize = lseek(clam_fd, 0, SEEK_END)) < 0)
+       if (fstat(clam_fd, &st) < 0)
          {
-         int err;
-b_seek:   err = errno;
+         int err = errno;
          (void)close(clam_fd);
          return m_panic_defer_3(scanent, NULL,
-           string_sprintf("can't seek spool file %s: %s",
+           string_sprintf("can't stat spool file %s: %s",
              eml_filename, strerror(err)),
            malware_daemon_ctx.sock);
          }
-       fsize_uint = (unsigned int) fsize;
-       if ((off_t)fsize_uint != fsize)
+       fsize_uint = (unsigned int) st.st_size;
+       if ((off_t)fsize_uint != st.st_size)
          {
          (void)close(clam_fd);
          return m_panic_defer_3(scanent, NULL,
-           string_sprintf("seeking spool file %s, size overflow",
-             eml_filename),
+           string_sprintf("stat spool file %s, size overflow", eml_filename),
            malware_daemon_ctx.sock);
          }
-       if (lseek(clam_fd, 0, SEEK_SET) < 0)
-         goto b_seek;
 
-       if (!(clamav_fbuf = store_malloc(fsize_uint)))
-         {
-         (void)close(clam_fd);
+       /* send file body to socket */
+       send_size = htonl(fsize_uint);
+       if (send(malware_daemon_ctx.sock, &send_size, sizeof(send_size), 0) < 0)
          return m_panic_defer_3(scanent, NULL,
-           string_sprintf("unable to allocate memory %u for file (%s)",
-             fsize_uint, eml_filename),
+           string_sprintf("unable to send file size to socket (%s)", hostname),
            malware_daemon_ctx.sock);
-         }
 
-       if ((result = read(clam_fd, clamav_fbuf, fsize_uint)) < 0)
+       while (fsize_uint)
          {
-         int err = errno;
-         store_free(clamav_fbuf); (void)close(clam_fd);
-         return m_panic_defer_3(scanent, NULL,
-           string_sprintf("can't read spool file %s: %s",
-             eml_filename, strerror(err)),
-           malware_daemon_ctx.sock);
+         unsigned n = MIN(fsize_uint, big_buffer_size);
+         if ((n = read(clam_fd, big_buffer, n)) < 0)
+           return m_panic_defer_3(scanent, NULL,
+             string_sprintf("can't read spool file %s: %s",
+               eml_filename, strerror(errno)),
+             malware_daemon_ctx.sock);
+         if ((n = send(malware_daemon_ctx.sock, clamav_fbuf, n, 0)) < 0)
+           return m_panic_defer_3(scanent, NULL,
+             string_sprintf("unable to send file body to socket (%s)", hostname),
+             malware_daemon_ctx.sock);
+         fsize_uint -= n;
          }
-       (void)close(clam_fd);
 
-       /* send file body to socket */
-       send_size = htonl(fsize_uint);
        send_final_zeroblock = 0;
-       if ((send(malware_daemon_ctx.sock, &send_size, sizeof(send_size), 0) < 0) ||
-           (send(malware_daemon_ctx.sock, clamav_fbuf, fsize_uint, 0) < 0) ||
-           (send(malware_daemon_ctx.sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0))
-         {
-         store_free(clamav_fbuf);
+       if (send(malware_daemon_ctx.sock, &send_final_zeroblock, sizeof(send_final_zeroblock), 0) < 0)
          return m_panic_defer_3(scanent, NULL,
-           string_sprintf("unable to send file body to socket (%s)", hostname),
+           string_sprintf("unable to send file terminator to socket (%s)", hostname),
            malware_daemon_ctx.sock);
-         }
-       store_free(clamav_fbuf);
        }
       else
        { /* use scan command */