From: Jeremy Harris Date: Sat, 11 Jan 2020 21:52:24 +0000 (+0000) Subject: taint enforce: file access backstops X-Git-Url: https://git.exim.org/users/jgh/exim.git/commitdiff_plain/9e21ce8fc41aea068996e0a22093dfae33f542c7?ds=sidebyside taint enforce: file access backstops --- diff --git a/src/src/expand.c b/src/src/expand.c index fe5384ab8..55aaf53ca 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -8550,7 +8550,7 @@ expand_file_big_buffer(const uschar * filename) { int fd, off = 0, len; -if ((fd = open(CS filename, O_RDONLY)) < 0) +if ((fd = exim_open2(CS filename, O_RDONLY)) < 0) { log_write(0, LOG_MAIN | LOG_PANIC, "unable to open file for reading: %s", filename); diff --git a/src/src/functions.h b/src/src/functions.h index d5df98796..fe15cc573 100644 --- a/src/src/functions.h +++ b/src/src/functions.h @@ -930,6 +930,8 @@ subdir_str[1] = '\0'; } /******************************************************************************/ +/* Time calculations */ + static inline void timesince(struct timeval * diff, const struct timeval * then) { @@ -983,6 +985,51 @@ if (f.running_in_test_harness) millisleep(millisec); #endif } +/******************************************************************************/ +/* Taint-checked file opens */ + +static inline int +exim_open2(const char *pathname, int flags) +{ +if (!is_tainted(pathname)) return open(pathname, flags); +log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'\n", pathname); +errno = EACCES; +return -1; +} +static inline int +exim_open(const char *pathname, int flags, mode_t mode) +{ +if (!is_tainted(pathname)) return open(pathname, flags, mode); +log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'\n", pathname); +errno = EACCES; +return -1; +} +static inline int +exim_openat(int dirfd, const char *pathname, int flags) +{ +if (!is_tainted(pathname)) return openat(dirfd, pathname, flags); +log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'\n", pathname); +errno = EACCES; +return -1; +} +static inline int +exim_openat4(int dirfd, const char *pathname, int flags, mode_t mode) +{ +if (!is_tainted(pathname)) return openat(dirfd, pathname, flags, mode); +log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'\n", pathname); +errno = EACCES; +return -1; +} + +static inline FILE * +exim_fopen(const char *pathname, const char *mode) +{ +if (!is_tainted(pathname)) return fopen(pathname, mode); +log_write(0, LOG_MAIN|LOG_PANIC, "Tainted filename '%s'\n", pathname); +errno = EACCES; +return NULL; +} + #endif /* !MACRO_PREDEF */ #endif /* _FUNCTIONS_H_ */ diff --git a/src/src/malware.c b/src/src/malware.c index ef27daf37..ec2f7c1cf 100644 --- a/src/src/malware.c +++ b/src/src/malware.c @@ -791,7 +791,7 @@ if (!malware_ok) if (*scanner_options != '/') { /* calc file size */ - if ((drweb_fd = open(CCS eml_filename, O_RDONLY)) == -1) + if ((drweb_fd = exim_open(CCS eml_filename, O_RDONLY)) == -1) return m_panic_defer_3(scanent, NULL, string_sprintf("can't open spool file %s: %s", eml_filename, strerror(errno)), @@ -1362,13 +1362,10 @@ badseek: err = errno; malware_name = US"unknown"; /* re-open the scanner output file, look for name match */ - scanner_record = fopen(CS file_name, "rb"); - while (fgets(CS linebuffer, sizeof(linebuffer), scanner_record)) - { - /* try match */ - if ((s = m_pcre_exec(cmdline_regex_re, linebuffer))) + scanner_record = Ufopen(file_name, "rb"); + while (Ufgets(linebuffer, sizeof(linebuffer), scanner_record)) + if ((s = m_pcre_exec(cmdline_regex_re, linebuffer))) /* try match */ malware_name = s; - } (void)fclose(scanner_record); } else /* no virus found */ @@ -1638,7 +1635,7 @@ badseek: err = errno; malware_daemon_ctx.sock); /* calc file size */ - if ((clam_fd = open(CS eml_filename, O_RDONLY)) < 0) + if ((clam_fd = exim_open2(CS eml_filename, O_RDONLY)) < 0) { int err = errno; return m_panic_defer_3(scanent, NULL, diff --git a/src/src/mytypes.h b/src/src/mytypes.h index eba3f7e9d..d652daea3 100644 --- a/src/src/mytypes.h +++ b/src/src/mytypes.h @@ -89,15 +89,17 @@ functions that are called quite often; for other calls to external libraries #define Uchdir(s) chdir(CCS(s)) #define Uchmod(s,n) chmod(CCS(s),n) #define Ufgets(b,n,f) fgets(CS(b),n,f) -#define Ufopen(s,t) fopen(CCS(s),CCS(t)) +#define Ufopen(s,t) exim_fopen(CCS(s),CCS(t)) #define Ulink(s,t) link(CCS(s),CCS(t)) #define Ulstat(s,t) lstat(CCS(s),t) -#ifdef O_BINARY /* This is for Cygwin, */ -#define Uopen(s,n,m) open(CCS(s),(n)|O_BINARY,m) /* where all files must */ -#else /* be opened as binary */ -#define Uopen(s,n,m) open(CCS(s),n,m) /* to avoid problems */ -#endif /* with CRLF endings. */ +#ifdef O_BINARY /* This is for Cygwin, */ +#define Uopen(s,n,m) exim_open(CCS(s),(n)|O_BINARY,m) /* where all files must */ +#define Uopen2(s,n) exim_open2(CCS(s),(n)|O_BINARY) +#else /* be opened as binary */ +#define Uopen(s,n,m) exim_open(CCS(s),n,m) /* to avoid problems */ +#define Uopen2(s,n) exim_open2(CCS(s),n) +#endif /* with CRLF endings. */ #define Uread(f,b,l) read(f,CS(b),l) #define Urename(s,t) rename(CCS(s),CCS(t)) #define Ustat(s,t) stat(CCS(s),t) diff --git a/src/src/parse.c b/src/src/parse.c index be70effe9..71f48f379 100644 --- a/src/src/parse.c +++ b/src/src/parse.c @@ -1454,7 +1454,7 @@ for (;;) with a flag that fails symlinks. */ { - int fd = open(CS directory, O_RDONLY); + int fd = exim_open2(CS directory, O_RDONLY); if (fd < 0) { *error = string_sprintf("failed to open directory %s", directory); @@ -1470,7 +1470,7 @@ for (;;) temp = *p; *p = '\0'; - fd2 = openat(fd, CS q, O_RDONLY|O_NOFOLLOW); + fd2 = exim_openat(fd, CS q, O_RDONLY|O_NOFOLLOW); close(fd); *p = temp; if (fd2 < 0) diff --git a/src/src/transports/queuefile.c b/src/src/transports/queuefile.c index bb2b9b9f3..4339d1fdd 100644 --- a/src/src/transports/queuefile.c +++ b/src/src/transports/queuefile.c @@ -134,11 +134,11 @@ else /* use data copy */ tb->name, srcpath, dstpath); if ( (s = dstpath, - (dstfd = openat(ddfd, CCS filename, O_RDWR|O_CREAT|O_EXCL, SPOOL_MODE)) + (dstfd = exim_openat4(ddfd, CCS filename, O_RDWR|O_CREAT|O_EXCL, SPOOL_MODE)) < 0 ) || is_hdr_file - && (s = srcpath, (srcfd = openat(sdfd, CCS filename, O_RDONLY)) < 0) + && (s = srcpath, (srcfd = exim_openat(sdfd, CCS filename, O_RDONLY)) < 0) ) op = US"opening";