From b0c0f832896d49f22ba7d952ddfc628a07218fd6 Mon Sep 17 00:00:00 2001 From: Keith Owens Date: Wed, 28 Sep 2011 16:09:59 +1000 Subject: proxsmtpd: [PATCH] Close extra file descriptors for filter command Short form: Passing extra file descriptors to the filter command can prevent it from detecting EOF or EPIPE. Result, dead filter commands that never terminate. Close everything except fd 0, 1, 2 before running the filter command. Long form: At the point that the filter command is forked and executed, proxsmtd may have multiple children with multiple pipes open. fork() bumps the reference count on all the file descriptors that are open at that moment. When the parent closes its part of the pipe, the pipe fd may or may not be removed from the system, depending on how many children have accidentally inherited that pipe. The child code closes fd 0, 1 and 2, calls dup2() to map the pipes to 0, 1 and 2 then runs. If another child has accidentally bumped the reference count on the pipes to this child then fd 0 can have multiple writers. This prevents the filter from detecting EOF or EPIPE when proxsmtpd closes the pipe to this particular child. This bug is particularly evident if the filter program does another fork and uses more pipes to communicate with its own child. awk does this as a matter of course. The result is a dangling filter command just sitting there waiting for input and not detecting that stdin has been closed. The dangling commands are owned by pid 1 rather than proxsmtpd. The only way to get rid of them is to manually kill them. --- NEWS | 1 + src/proxsmtpd.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/NEWS b/NEWS index 31bce38..c87253e 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,6 @@ 1.10 ??? - Fix race issue with waitpid on linux. + - Close all (other than standard) file descriptors when forking filter. 1.9 [2011-01-23] - Fix build warnings. diff --git a/src/proxsmtpd.c b/src/proxsmtpd.c index 8f50d96..963894d 100644 --- a/src/proxsmtpd.c +++ b/src/proxsmtpd.c @@ -425,6 +425,9 @@ static pid_t fork_filter(spctx_t* sp, int* infd, int* outfd, int* errfd) kill_myself(); } + for (r = 3; r < FD_SETSIZE; ++r) + close(r); + /* All the necessary environment vars */ sp_setup_forked(sp, 1); -- cgit v1.2.3