Daniel Roethlisberger wrote:
When delivering mail to multiple recipients, dma(8) will fork for
each recipient and attempt parallel delivery. Separate delivery
processes for multiple recipients of the same message all use the
same FILE* on the same file descriptor. If a process is loosing
the CPU during the delivery process, another delivery process for
the same message will wreak havoc on the file descriptor. The
symptom is dma(8) logging a failed delivery and bouncing the
message for some or all of the recipients:
Jul 3 20:57:21 marvin dma[32640]: 15c.284010d0: remote delivery
failed:corrupted queue file
Thanks for your submission! I've taken a different approach, could you please
test whether it works for you? (Untested patch).
thanks,
simon
>From 2396669f0116cda9d5f2e0e19ce38c840731bc17 Mon Sep 17 00:00:00 2001
From: Simon Schubert <[email protected]>
Date: Thu, 9 Jul 2009 23:24:35 +0200
Subject: [PATCH] dma: prevent races from sharing fd between children
On fork, fds are shared between children. If two processes work on
different recipients, but on the same queue file, they might get
confused when the fd (and thus the offset) is shared. Prevent this by
re-opening the fd after fork.
Reported-by: Daniel Roethlisberger <[email protected]>
---
libexec/dma/dma.c | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/libexec/dma/dma.c b/libexec/dma/dma.c
index 4633b0c..793e327 100644
--- a/libexec/dma/dma.c
+++ b/libexec/dma/dma.c
@@ -484,6 +484,7 @@ go_background(struct queue *queue)
{
struct sigaction sa;
struct qitem *it;
+ FILE *newqf;
pid_t pid;
if (daemonize && daemon(0, 0) != 0) {
@@ -515,6 +516,17 @@ go_background(struct queue *queue)
*
* return and deliver mail
*/
+ /*
+ * We have to prevent sharing of fds between children, so
+ * we have to dup the queue fd.
+ */
+ newqf = fdopen(fileno(it->queuef), "r");
+ if (newqf == NULL) {
+ syslog(LOG_ERR, "can not dup queue fd: %m");
+ exit(1);
+ }
+ fclose(it->queuef);
+ it->queuef = newqf;
return (it);
default:
--
1.6.2.149.g6462