taint enforce: file access backstops
authorJeremy Harris <jgh146exb@wizmail.org>
Sat, 11 Jan 2020 21:52:24 +0000 (21:52 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Sat, 11 Jan 2020 21:52:24 +0000 (21:52 +0000)
src/src/expand.c
src/src/functions.h
src/src/malware.c
src/src/mytypes.h
src/src/parse.c
src/src/transports/queuefile.c

index fe5384ab8f09fc2ecfdf2dedea26ab7825b4691e..55aaf53cab2c49e5bb745a6fc1552f8ba053e068 100644 (file)
@@ -8550,7 +8550,7 @@ expand_file_big_buffer(const uschar * filename)
 {
 int fd, off = 0, len;
 
 {
 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);
   {
   log_write(0, LOG_MAIN | LOG_PANIC, "unable to open file for reading: %s",
             filename);
index d5df987966220dda2f1e30d6ee98f3dafbe51a4f..fe15cc573251b6ca2fa3a21bce8b77a2608d3a5e 100644 (file)
@@ -930,6 +930,8 @@ subdir_str[1] = '\0';
 }
 
 /******************************************************************************/
 }
 
 /******************************************************************************/
+/* Time calculations */
+
 static inline void
 timesince(struct timeval * diff, const struct timeval * then)
 {
 static inline void
 timesince(struct timeval * diff, const struct timeval * then)
 {
@@ -983,6 +985,51 @@ if (f.running_in_test_harness) millisleep(millisec);
 #endif
 }
 
 #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_ */
 #endif /* !MACRO_PREDEF */
 
 #endif  /* _FUNCTIONS_H_ */
index ef27daf377b2d336ef354979dae2e62f23138dfa..ec2f7c1cfc7681eac5e9a1d34acbb15895bde805 100644 (file)
@@ -791,7 +791,7 @@ if (!malware_ok)
       if (*scanner_options != '/')
        {
        /* calc file size */
       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)),
          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 */
        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;
            malware_name = s;
-         }
        (void)fclose(scanner_record);
        }
       else /* no virus found */
        (void)fclose(scanner_record);
        }
       else /* no virus found */
@@ -1638,7 +1635,7 @@ badseek:  err = errno;
              malware_daemon_ctx.sock);
 
        /* calc file size */
              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,
          {
          int err = errno;
          return m_panic_defer_3(scanent, NULL,
index eba3f7e9de8993c2f01d65dc27f7abe1e5c7b9d2..d652daea3637a1ff3382882456d9efa7daa3894f 100644 (file)
@@ -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 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)
 
 #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)
 #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)
index be70effe9fbda10bc21ed00c72c810971fec65a6..71f48f3798bcbb57c61ea9178c3b1d94d6c8adbd 100644 (file)
@@ -1454,7 +1454,7 @@ for (;;)
       with a flag that fails symlinks. */
 
       {
       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);
       if (fd < 0)
        {
        *error = string_sprintf("failed to open directory %s", directory);
@@ -1470,7 +1470,7 @@ for (;;)
        temp = *p;
        *p = '\0';
 
        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)
        close(fd);
        *p = temp;
        if (fd2 < 0)
index bb2b9b9f325fca9ecff9492672c4ba9c864c728e..4339d1fdd0773efe9bbfd2d5a4f6749d48d721f1 100644 (file)
@@ -134,11 +134,11 @@ else                                      /* use data copy */
     tb->name, srcpath, dstpath);
 
   if (  (s = dstpath,
     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
         < 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";
 
      )
     op = US"opening";