Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nullmailer-smtpd fails to handle SIGPIPE, closes unexpectedly #97

Open
schongallam opened this issue Sep 10, 2024 · 0 comments
Open

nullmailer-smtpd fails to handle SIGPIPE, closes unexpectedly #97

schongallam opened this issue Sep 10, 2024 · 0 comments

Comments

@schongallam
Copy link

Brief Description:

Steps to reproduce (see issue #95):

  • Give nullmailer-smtpd a malformed payload, where either the MAIL FROM or the RCPT TO target is invalid
  • For example:
HELO a\n
MAIL FROM:<b>\n
RCPT TO:<c>\n
DATA\n
line 1\r\n
\r\n.\r\n

Expected behavior: any of the following.

  • nullmailer-smtpd should report an SMTP error message.
  • reject invalid MAIL FROM or RCPT TO
  • report to ferr that write to stream has failed

Resulting behavior:

/app# nullmailer-smtpd
220 nullmailer-smtpd ready
HELO a
250 2.3.0 OK
MAIL FROM:<b>
250 2.1.0 Sender accepted
RCPT TO:<[email protected]>
250 2.1.5 Recipient accepted
DATA
354 End your message with a period on a line by itself
line 1
/app# echo $?
141

(141 = 128 + SIGPIPE)

Root cause:
Running in gdb shows that src/smtpd.cc, qwrite attempts to write to a closed file descriptor (line 118). Verified with signal handling patch (see fix below).

Impact:

  • SMTP clients are able to cause failure of nullmailer-smtpd.
  • nullmailer-smtpd exits without providing useful information why.

Fix(es):
Implementing a signal handler to catch SIGPIPE in src/smtpd.cc avoids a program crash. Here is a hacky proof of concept:

@@ -111,9 +111,16 @@
   return fout;
 }
 
+static void pipe_handler(const int signal_num)
+{
+  ferr << "signal " << signal_num << ".\n"; 
+  respond(resp_qwrite_err);
+}
+
 static bool qwrite(int qfd, const char* data, size_t len)
 {
   ssize_t wr;
+  signal(SIGPIPE, pipe_handler);
   while (len > 0) {
     wr = write(qfd, data, len);
     if (wr <= 0)

Resulting behavior, avoiding a crash:

/app# nullmailer-smtpd
220 nullmailer-smtpd ready
HELO me
250 2.3.0 OK
MAIL FROM:<a>
250 2.1.0 Sender accepted
RCPT TO:<[email protected]>
250 2.1.5 Recipient accepted
DATA
354 End your message with a period on a line by itself
line 1
451 4.3.0 Write to nullmailer-queue failed
451 4.3.0 Write to nullmailer-queue failed
signal 13.
nullmailer-smtpd: nullmailer-queue failed: 1
QUIT
221 2.0.0 Good bye
``
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant