From: Jeremy Harris Date: Thu, 31 Dec 2020 22:18:30 +0000 (+0000) Subject: malware: avoid slurping entire spoolfile for sending to ClamAV X-Git-Url: https://git.exim.org/users/heiko/exim.git/commitdiff_plain/62a4137ec452ff0a6801923930b003e954ec09aa malware: avoid slurping entire spoolfile for sending to ClamAV --- diff --git a/src/src/malware.c b/src/src/malware.c index 03bb832fc..2883f225a 100644 --- a/src/src/malware.c +++ b/src/src/malware.c @@ -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 chunks, 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 */