From a5f5415eae9f70df9dd4633656cac7a3b88985b9 Mon Sep 17 00:00:00 2001 From: Michael Moore Date: Sat, 29 Nov 2025 11:47:19 -0700 Subject: [PATCH] fix: improve slurp() robustness with size limit and read loop Addresses several issues in slurp(): 1. No size limit - A large dependency file could exhaust memory 2. Partial reads - read() can return fewer bytes than requested 3. EINTR - Interrupted system calls weren't retried Fix: - Add 10MB size limit (SLURP_MAX_SIZE) - Read in a loop until all bytes are received - Retry on EINTR - Log malloc failures Note: Preserves the TOCTOU fix from PR #9 (fstat after open). --- src/job.c | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/job.c b/src/job.c index 355a490..5786969 100644 --- a/src/job.c +++ b/src/job.c @@ -345,10 +345,13 @@ char *fpath(job_t *job, char *file) { } /* this function reads a whole file into a malloc'd buffer */ +#define SLURP_MAX_SIZE (10 * 1024 * 1024) /* 10 MB limit */ int slurp(char *file, char **text, size_t *len) { struct stat s; char *buf; - int fd = -1, rc=-1, nr; + int fd = -1, rc=-1; + ssize_t nr; + size_t total = 0; *text=NULL; *len = 0; if ( (fd = open(file, O_RDONLY)) == -1) { @@ -361,15 +364,27 @@ int slurp(char *file, char **text, size_t *len) { } *len = s.st_size; if (*len == 0) {rc=0; goto done;} // special case, empty file - if ( (*text = malloc(*len)) == NULL) goto done; - if ( (nr=read(fd, *text, *len)) != *len) { - if (nr == -1) { - syslog(LOG_CRIT,"read %s failed: %s", file, strerror(errno)); - } else { - syslog(LOG_CRIT,"read %s failed: incomplete (%u/%u)", file, - nr, (unsigned)*len); - } - goto done; + if (*len > SLURP_MAX_SIZE) { + syslog(LOG_ERR,"%s: file too large (%zu bytes)", file, *len); + goto done; + } + if ( (*text = malloc(*len)) == NULL) { + syslog(LOG_ERR,"malloc failed for %s", file); + goto done; + } + while (total < *len) { + nr = read(fd, *text + total, *len - total); + if (nr == -1) { + if (errno == EINTR) continue; + syslog(LOG_CRIT,"read %s failed: %s", file, strerror(errno)); + goto done; + } + if (nr == 0) { + syslog(LOG_CRIT,"read %s failed: unexpected EOF (%zu/%zu)", file, + total, *len); + goto done; + } + total += nr; } rc = 0;