diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2013-09-11 14:59:21 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2013-09-11 14:59:21 +0200 |
commit | fbe250db76b409a99457b47486a09b57677d5108 (patch) | |
tree | 1b222f195c0947502c46d375e35f549eb4cbe9b0 | |
parent | b5352078a7eb16c33404a8b079aaa9c2b994546c (diff) | |
download | busybox-w32-fbe250db76b409a99457b47486a09b57677d5108.tar.gz busybox-w32-fbe250db76b409a99457b47486a09b57677d5108.tar.bz2 busybox-w32-fbe250db76b409a99457b47486a09b57677d5108.zip |
httpd: treat errors from stdin correctly.
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@googlemail.com>
-rw-r--r-- | networking/httpd.c | 21 |
1 files changed, 13 insertions, 8 deletions
diff --git a/networking/httpd.c b/networking/httpd.c index cef9b8baf..143331389 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 | |||
1105 | /* NB: breaking out of this loop jumps to log_and_exit() */ | 1105 | /* NB: breaking out of this loop jumps to log_and_exit() */ |
1106 | out_cnt = 0; | 1106 | out_cnt = 0; |
1107 | while (1) { | 1107 | while (1) { |
1108 | memset(pfd, 0, sizeof(pfd)); | 1108 | /* Note: even pfd[0].events == 0 won't prevent |
1109 | * revents == POLLHUP|POLLERR reports from closed stdin. | ||
1110 | * This works: */ | ||
1111 | pfd[0].fd = -1; | ||
1109 | 1112 | ||
1110 | pfd[FROM_CGI].fd = fromCgi_rd; | 1113 | pfd[FROM_CGI].fd = fromCgi_rd; |
1111 | pfd[FROM_CGI].events = POLLIN; | 1114 | pfd[FROM_CGI].events = POLLIN; |
1112 | 1115 | ||
1113 | if (toCgi_wr) { | 1116 | pfd[TO_CGI].fd = toCgi_wr; |
1114 | pfd[TO_CGI].fd = toCgi_wr; | 1117 | pfd[TO_CGI].events = POLLOUT; |
1115 | if (hdr_cnt > 0) { | 1118 | |
1116 | pfd[TO_CGI].events = POLLOUT; | 1119 | if (toCgi_wr && hdr_cnt <= 0) { |
1117 | } else if (post_len > 0) { | 1120 | if (post_len > 0) { |
1121 | /* Expect more POST data from network */ | ||
1122 | pfd[0].fd = 0; | ||
1118 | pfd[0].events = POLLIN; | 1123 | pfd[0].events = POLLIN; |
1119 | } else { | 1124 | } else { |
1120 | /* post_len <= 0 && hdr_cnt <= 0: | 1125 | /* 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 | |||
1127 | } | 1132 | } |
1128 | 1133 | ||
1129 | /* Now wait on the set of sockets */ | 1134 | /* Now wait on the set of sockets */ |
1130 | count = safe_poll(pfd, toCgi_wr ? TO_CGI+1 : FROM_CGI+1, -1); | 1135 | count = safe_poll(pfd, hdr_cnt > 0 ? TO_CGI+1 : FROM_CGI+1, -1); |
1131 | if (count <= 0) { | 1136 | if (count <= 0) { |
1132 | #if 0 | 1137 | #if 0 |
1133 | if (safe_waitpid(pid, &status, WNOHANG) <= 0) { | 1138 | 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 | |||
1144 | } | 1149 | } |
1145 | 1150 | ||
1146 | if (pfd[TO_CGI].revents) { | 1151 | if (pfd[TO_CGI].revents) { |
1147 | /* hdr_cnt > 0 here due to the way pfd[TO_CGI].events set */ | 1152 | /* hdr_cnt > 0 here due to the way poll() called */ |
1148 | /* Have data from peer and can write to CGI */ | 1153 | /* Have data from peer and can write to CGI */ |
1149 | count = safe_write(toCgi_wr, hdr_ptr, hdr_cnt); | 1154 | count = safe_write(toCgi_wr, hdr_ptr, hdr_cnt); |
1150 | /* Doesn't happen, we dont use nonblocking IO here | 1155 | /* Doesn't happen, we dont use nonblocking IO here |