Here's a patch that should apply against MIMEDefang 2.80. Again, I cannot see any way to completely close this hole as long as we're holding an fcnrtl(F_SETLCK)-style lock, since the descriptor must be kept open. I do as much as I can to mitigate this by destroying the variable containing the fd, but an attacker could pretty quickly discover which fd is pointing to the lock file.
Since an exploit requires compromising the daemon, I would say this is not a super-urgent problem. Regards, Dianne. diff --git a/Changelog b/Changelog index da1a867..d056e4f 100644 --- a/Changelog +++ b/Changelog @@ -2,6 +2,11 @@ WARNING: Before upgrading MIMEDefang, please search this file for *** NOTE INCOMPATIBILITY ** to see if anything has changed that might affect your filter. +2017-08-31 Dianne Skoll <d...@roaringpenguin.com> + + * Make mimedefang and mimedefang-multiplexor write their PID files + as root to avoid an unprivileged user tampering with the pidfiles. + 2017-07-24 Dianne Skoll <d...@roaringpenguin.com> * MIMEDefang 2.80 RELEASED diff --git a/mimedefang-multiplexor.c b/mimedefang-multiplexor.c index 13b77b9..3dbf6e0 100644 --- a/mimedefang-multiplexor.c +++ b/mimedefang-multiplexor.c @@ -566,6 +566,7 @@ main(int argc, char *argv[], char **env) int c; int n; char *pidfile = NULL; + int pidfile_fd = -1; char *user = NULL; char *options; int facility = LOG_MAIL; @@ -919,6 +920,17 @@ main(int argc, char *argv[], char **env) strcat((char *) Settings.sockName, "/mimedefang-multiplexor.sock"); } + /* Open the pidfile as root. We'll lock it later in the grandchild */ + if (pidfile) { + pidfile_fd = open(pidfile, O_RDWR|O_CREAT, 0666); + if (pidfile_fd < 0) { + syslog(LOG_ERR, "Could not open PID file %s: %m", pidfile); + exit(EXIT_FAILURE); + } + /* It needs to be world-readable */ + fchmod(pidfile_fd, 0644); + } + /* Drop privileges */ if (user) { pw = getpwnam(user); @@ -1134,7 +1146,7 @@ main(int argc, char *argv[], char **env) } for (i=0; i<256; i++) { - if (i == unpriv_sock || i == sock || i == Pipe[0] || i == Pipe[1]) continue; + if (i == pidfile_fd || i == unpriv_sock || i == sock || i == Pipe[0] || i == Pipe[1]) continue; (void) close(i); } @@ -1155,10 +1167,12 @@ main(int argc, char *argv[], char **env) /* Write pid */ if (pidfile) { - if (write_and_lock_pidfile(pidfile) < 0) { + if (write_and_lock_pidfile(pidfile, pidfile_fd) < 0) { exit(1); } free(pidfile); + /* Forget the fd */ + pidfile_fd = -1; } /* Set up SIGHUP handler */ diff --git a/mimedefang.c b/mimedefang.c index 7e74137..5d545c4 100644 --- a/mimedefang.c +++ b/mimedefang.c @@ -2331,6 +2331,7 @@ main(int argc, char **argv) int got_p_option = 0; int kidpipe[2]; char kidmsg[256]; + int pidfile_fd = -1; mode_t socket_umask = 077; mode_t file_umask = 077; @@ -2611,6 +2612,17 @@ main(int argc, char **argv) exit(EXIT_FAILURE); } + /* Open the pidfile as root. We'll lock it later in the grandchild */ + if (pidfile) { + pidfile_fd = open(pidfile, O_RDWR|O_CREAT, 0666); + if (pidfile_fd < 0) { + syslog(LOG_ERR, "Could not open PID file %s: %m", pidfile); + exit(EXIT_FAILURE); + } + /* It needs to be world-readable */ + fchmod(pidfile_fd, 0644); + } + /* Look up user */ if (user) { pw = getpwnam(user); @@ -2715,12 +2727,14 @@ main(int argc, char **argv) /* Write pid */ if (pidfile) { - if (write_and_lock_pidfile(pidfile) < 0) { + if (write_and_lock_pidfile(pidfile, pidfile_fd) < 0) { /* Signal the waiting parent */ REPORT_FAILURE("Cannot lock pidfile: Is another copy running?", 45); exit(1); } free(pidfile); + /* Forget the fd */ + pidfile_fd = -1; } (void) closelog(); diff --git a/mimedefang.h b/mimedefang.h index 381316d..608c2e6 100644 --- a/mimedefang.h +++ b/mimedefang.h @@ -66,7 +66,7 @@ extern int make_listening_socket(char const *str, int backlog, int must_be_unix) extern void do_delay(char const *sleepstr); extern int is_localhost(struct sockaddr *); extern int remove_local_socket(char const *str); -extern int write_and_lock_pidfile(char const *pidfile); +extern int write_and_lock_pidfile(char const *pidfile, int fd); #ifdef EMBED_PERL extern int make_embedded_interpreter(char const *progPath, char const *subFilter, diff --git a/utils.c b/utils.c index 7d4f9c1..1ca3db6 100644 --- a/utils.c +++ b/utils.c @@ -1300,9 +1300,8 @@ free_debug(void *ctx, void *x, char const *fname, int line) #endif int -write_and_lock_pidfile(char const *pidfile) +write_and_lock_pidfile(char const *pidfile, int fd) { - int fd; struct flock fl; char buf[64]; @@ -1311,11 +1310,6 @@ write_and_lock_pidfile(char const *pidfile) fl.l_start = 0; fl.l_len = 0; - fd = open(pidfile, O_RDWR|O_CREAT, 0666); - if (fd < 0) { - syslog(LOG_ERR, "Could not open PID file %s: %m", pidfile); - return -1; - } if (fcntl(fd, F_SETLK, &fl) < 0) { syslog(LOG_ERR, "Could not lock PID file %s: %m. Is another copy running?", pidfile); return -1; _______________________________________________ NOTE: If there is a disclaimer or other legal boilerplate in the above message, it is NULL AND VOID. You may ignore it. Visit http://www.mimedefang.org and http://www.roaringpenguin.com MIMEDefang mailing list MIMEDefang@lists.roaringpenguin.com http://lists.roaringpenguin.com/mailman/listinfo/mimedefang