[git commit] httpd: treat errors from stdin correctly.

Denys Vlasenko vda.linux at googlemail.com
Wed Sep 11 12:59:21 UTC 2013


commit: http://git.busybox.net/busybox/commit/?id=fbe250db76b409a99457b47486a09b57677d5108
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

Fron bug report:

If a CGI or proxied connection is rudely aborted (SIG_{KILL,BUS,SEGV})
then httpd will spin madly the poll loop in:

networking/httpd.c:1080
cgi_io_loop_and_exit()

Upon investigation I found that pfd[0].revents == 0x0018 (POLLHUP|POLLERR),
which leads to empty read, but the pfd[0].fd (STDIN_FILENO) is left open,
and in the FD list given to poll() which immediately returns to once
again inform the loop of (POLLHUP|POLLERR) condition of pfd[0].fd.
This continues until pfd[FROM_CGI].revents != 0

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 networking/httpd.c |   21 +++++++++++++--------
 1 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/networking/httpd.c b/networking/httpd.c
index cef9b8b..1433313 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -1105,16 +1105,21 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post
 	/* NB: breaking out of this loop jumps to log_and_exit() */
 	out_cnt = 0;
 	while (1) {
-		memset(pfd, 0, sizeof(pfd));
+		/* Note: even pfd[0].events == 0 won't prevent
+		 * revents == POLLHUP|POLLERR reports from closed stdin.
+		 * This works: */
+		pfd[0].fd = -1;
 
 		pfd[FROM_CGI].fd = fromCgi_rd;
 		pfd[FROM_CGI].events = POLLIN;
 
-		if (toCgi_wr) {
-			pfd[TO_CGI].fd = toCgi_wr;
-			if (hdr_cnt > 0) {
-				pfd[TO_CGI].events = POLLOUT;
-			} else if (post_len > 0) {
+		pfd[TO_CGI].fd = toCgi_wr;
+		pfd[TO_CGI].events = POLLOUT;
+
+		if (toCgi_wr && hdr_cnt <= 0) {
+			if (post_len > 0) {
+				/* Expect more POST data from network */
+				pfd[0].fd = 0;
 				pfd[0].events = POLLIN;
 			} else {
 				/* post_len <= 0 && hdr_cnt <= 0:
@@ -1127,7 +1132,7 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post
 		}
 
 		/* Now wait on the set of sockets */
-		count = safe_poll(pfd, toCgi_wr ? TO_CGI+1 : FROM_CGI+1, -1);
+		count = safe_poll(pfd, hdr_cnt > 0 ? TO_CGI+1 : FROM_CGI+1, -1);
 		if (count <= 0) {
 #if 0
 			if (safe_waitpid(pid, &status, WNOHANG) <= 0) {
@@ -1144,7 +1149,7 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post
 		}
 
 		if (pfd[TO_CGI].revents) {
-			/* hdr_cnt > 0 here due to the way pfd[TO_CGI].events set */
+			/* hdr_cnt > 0 here due to the way poll() called */
 			/* Have data from peer and can write to CGI */
 			count = safe_write(toCgi_wr, hdr_ptr, hdr_cnt);
 			/* Doesn't happen, we dont use nonblocking IO here


More information about the busybox-cvs mailing list