diff options
author | Damien Miller <djm@mindrot.org> | 2001-01-30 09:14:00 +1100 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2001-01-30 09:14:00 +1100 |
commit | 5e953217f13b340d8a5fbcd771a1dbaf43354f20 (patch) | |
tree | c138151966b6e8299f4c291cfb1b3ca006e1984c /serverloop.c | |
parent | b71eb58ff44f0f2d9c918dc2d17e765269d21c8c (diff) |
- (djm) OpenBSD CVS Sync:
- markus@cvs.openbsd.org 2001/01/29 09:55:37
[channels.c channels.h clientloop.c serverloop.c]
fix select overflow; ok deraadt@ and stevesk@
Diffstat (limited to 'serverloop.c')
-rw-r--r-- | serverloop.c | 85 |
1 files changed, 42 insertions, 43 deletions
diff --git a/serverloop.c b/serverloop.c index a7f8e72b5..bdac6a0d2 100644 --- a/serverloop.c +++ b/serverloop.c | |||
@@ -35,7 +35,7 @@ | |||
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include "includes.h" | 37 | #include "includes.h" |
38 | RCSID("$OpenBSD: serverloop.c,v 1.42 2001/01/21 19:05:55 markus Exp $"); | 38 | RCSID("$OpenBSD: serverloop.c,v 1.43 2001/01/29 16:55:37 markus Exp $"); |
39 | 39 | ||
40 | #include "xmalloc.h" | 40 | #include "xmalloc.h" |
41 | #include "packet.h" | 41 | #include "packet.h" |
@@ -73,7 +73,6 @@ static int fderr_eof = 0; /* EOF encountered readung from fderr. */ | |||
73 | static int connection_in; /* Connection to client (input). */ | 73 | static int connection_in; /* Connection to client (input). */ |
74 | static int connection_out; /* Connection to client (output). */ | 74 | static int connection_out; /* Connection to client (output). */ |
75 | static u_int buffer_high;/* "Soft" max buffer size. */ | 75 | static u_int buffer_high;/* "Soft" max buffer size. */ |
76 | static int max_fd; /* Max file descriptor number for select(). */ | ||
77 | 76 | ||
78 | /* | 77 | /* |
79 | * This SIGCHLD kludge is used to detect when the child exits. The server | 78 | * This SIGCHLD kludge is used to detect when the child exits. The server |
@@ -180,8 +179,8 @@ make_packets_from_stdout_data() | |||
180 | * for the duration of the wait (0 = infinite). | 179 | * for the duration of the wait (0 = infinite). |
181 | */ | 180 | */ |
182 | void | 181 | void |
183 | wait_until_can_do_something(fd_set * readset, fd_set * writeset, | 182 | wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, int *maxfdp, |
184 | u_int max_time_milliseconds) | 183 | u_int max_time_milliseconds) |
185 | { | 184 | { |
186 | struct timeval tv, *tvp; | 185 | struct timeval tv, *tvp; |
187 | int ret; | 186 | int ret; |
@@ -189,14 +188,13 @@ wait_until_can_do_something(fd_set * readset, fd_set * writeset, | |||
189 | /* When select fails we restart from here. */ | 188 | /* When select fails we restart from here. */ |
190 | retry_select: | 189 | retry_select: |
191 | 190 | ||
192 | /* Initialize select() masks. */ | 191 | /* Allocate and update select() masks for channel descriptors. */ |
193 | FD_ZERO(readset); | 192 | channel_prepare_select(readsetp, writesetp, maxfdp); |
194 | FD_ZERO(writeset); | ||
195 | 193 | ||
196 | if (compat20) { | 194 | if (compat20) { |
197 | /* wrong: bad condition XXX */ | 195 | /* wrong: bad condition XXX */ |
198 | if (channel_not_very_much_buffered_data()) | 196 | if (channel_not_very_much_buffered_data()) |
199 | FD_SET(connection_in, readset); | 197 | FD_SET(connection_in, *readsetp); |
200 | } else { | 198 | } else { |
201 | /* | 199 | /* |
202 | * Read packets from the client unless we have too much | 200 | * Read packets from the client unless we have too much |
@@ -204,37 +202,31 @@ retry_select: | |||
204 | */ | 202 | */ |
205 | if (buffer_len(&stdin_buffer) < buffer_high && | 203 | if (buffer_len(&stdin_buffer) < buffer_high && |
206 | channel_not_very_much_buffered_data()) | 204 | channel_not_very_much_buffered_data()) |
207 | FD_SET(connection_in, readset); | 205 | FD_SET(connection_in, *readsetp); |
208 | /* | 206 | /* |
209 | * If there is not too much data already buffered going to | 207 | * If there is not too much data already buffered going to |
210 | * the client, try to get some more data from the program. | 208 | * the client, try to get some more data from the program. |
211 | */ | 209 | */ |
212 | if (packet_not_very_much_data_to_write()) { | 210 | if (packet_not_very_much_data_to_write()) { |
213 | if (!fdout_eof) | 211 | if (!fdout_eof) |
214 | FD_SET(fdout, readset); | 212 | FD_SET(fdout, *readsetp); |
215 | if (!fderr_eof) | 213 | if (!fderr_eof) |
216 | FD_SET(fderr, readset); | 214 | FD_SET(fderr, *readsetp); |
217 | } | 215 | } |
218 | /* | 216 | /* |
219 | * If we have buffered data, try to write some of that data | 217 | * If we have buffered data, try to write some of that data |
220 | * to the program. | 218 | * to the program. |
221 | */ | 219 | */ |
222 | if (fdin != -1 && buffer_len(&stdin_buffer) > 0) | 220 | if (fdin != -1 && buffer_len(&stdin_buffer) > 0) |
223 | FD_SET(fdin, writeset); | 221 | FD_SET(fdin, *writesetp); |
224 | } | 222 | } |
225 | /* Set masks for channel descriptors. */ | ||
226 | channel_prepare_select(readset, writeset); | ||
227 | 223 | ||
228 | /* | 224 | /* |
229 | * If we have buffered packet data going to the client, mark that | 225 | * If we have buffered packet data going to the client, mark that |
230 | * descriptor. | 226 | * descriptor. |
231 | */ | 227 | */ |
232 | if (packet_have_data_to_write()) | 228 | if (packet_have_data_to_write()) |
233 | FD_SET(connection_out, writeset); | 229 | FD_SET(connection_out, *writesetp); |
234 | |||
235 | /* Update the maximum descriptor number if appropriate. */ | ||
236 | if (channel_max_fd() > max_fd) | ||
237 | max_fd = channel_max_fd(); | ||
238 | 230 | ||
239 | /* | 231 | /* |
240 | * If child has terminated and there is enough buffer space to read | 232 | * If child has terminated and there is enough buffer space to read |
@@ -255,7 +247,7 @@ retry_select: | |||
255 | debug2("tvp!=NULL kid %d mili %d", child_terminated, max_time_milliseconds); | 247 | debug2("tvp!=NULL kid %d mili %d", child_terminated, max_time_milliseconds); |
256 | 248 | ||
257 | /* Wait for something to happen, or the timeout to expire. */ | 249 | /* Wait for something to happen, or the timeout to expire. */ |
258 | ret = select(max_fd + 1, readset, writeset, NULL, tvp); | 250 | ret = select((*maxfdp)+1, *readsetp, *writesetp, NULL, tvp); |
259 | 251 | ||
260 | if (ret < 0) { | 252 | if (ret < 0) { |
261 | if (errno != EINTR) | 253 | if (errno != EINTR) |
@@ -400,7 +392,8 @@ process_buffered_input_packets() | |||
400 | void | 392 | void |
401 | server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) | 393 | server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) |
402 | { | 394 | { |
403 | fd_set readset, writeset; | 395 | fd_set *readset = NULL, *writeset = NULL; |
396 | int max_fd; | ||
404 | int wait_status; /* Status returned by wait(). */ | 397 | int wait_status; /* Status returned by wait(). */ |
405 | pid_t wait_pid; /* pid returned by wait(). */ | 398 | pid_t wait_pid; /* pid returned by wait(). */ |
406 | int waiting_termination = 0; /* Have displayed waiting close message. */ | 399 | int waiting_termination = 0; /* Have displayed waiting close message. */ |
@@ -441,15 +434,11 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) | |||
441 | buffer_high = 64 * 1024; | 434 | buffer_high = 64 * 1024; |
442 | 435 | ||
443 | /* Initialize max_fd to the maximum of the known file descriptors. */ | 436 | /* Initialize max_fd to the maximum of the known file descriptors. */ |
444 | max_fd = fdin; | 437 | max_fd = MAX(fdin, fdout); |
445 | if (fdout > max_fd) | 438 | if (fderr != -1) |
446 | max_fd = fdout; | 439 | max_fd = MAX(max_fd, fderr); |
447 | if (fderr != -1 && fderr > max_fd) | 440 | max_fd = MAX(max_fd, connection_in); |
448 | max_fd = fderr; | 441 | max_fd = MAX(max_fd, connection_out); |
449 | if (connection_in > max_fd) | ||
450 | max_fd = connection_in; | ||
451 | if (connection_out > max_fd) | ||
452 | max_fd = connection_out; | ||
453 | 442 | ||
454 | /* Initialize Initialize buffers. */ | 443 | /* Initialize Initialize buffers. */ |
455 | buffer_init(&stdin_buffer); | 444 | buffer_init(&stdin_buffer); |
@@ -536,18 +525,22 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) | |||
536 | } | 525 | } |
537 | } | 526 | } |
538 | /* Sleep in select() until we can do something. */ | 527 | /* Sleep in select() until we can do something. */ |
539 | wait_until_can_do_something(&readset, &writeset, | 528 | wait_until_can_do_something(&readset, &writeset, &max_fd, |
540 | max_time_milliseconds); | 529 | max_time_milliseconds); |
541 | 530 | ||
542 | /* Process any channel events. */ | 531 | /* Process any channel events. */ |
543 | channel_after_select(&readset, &writeset); | 532 | channel_after_select(readset, writeset); |
544 | 533 | ||
545 | /* Process input from the client and from program stdout/stderr. */ | 534 | /* Process input from the client and from program stdout/stderr. */ |
546 | process_input(&readset); | 535 | process_input(readset); |
547 | 536 | ||
548 | /* Process output to the client and to program stdin. */ | 537 | /* Process output to the client and to program stdin. */ |
549 | process_output(&writeset); | 538 | process_output(writeset); |
550 | } | 539 | } |
540 | if (readset) | ||
541 | xfree(readset); | ||
542 | if (writeset) | ||
543 | xfree(writeset); | ||
551 | 544 | ||
552 | /* Cleanup and termination code. */ | 545 | /* Cleanup and termination code. */ |
553 | 546 | ||
@@ -638,7 +631,8 @@ server_loop(pid_t pid, int fdin_arg, int fdout_arg, int fderr_arg) | |||
638 | void | 631 | void |
639 | server_loop2(void) | 632 | server_loop2(void) |
640 | { | 633 | { |
641 | fd_set readset, writeset; | 634 | fd_set *readset = NULL, *writeset = NULL; |
635 | int max_fd; | ||
642 | int had_channel = 0; | 636 | int had_channel = 0; |
643 | int status; | 637 | int status; |
644 | pid_t pid; | 638 | pid_t pid; |
@@ -650,9 +644,9 @@ server_loop2(void) | |||
650 | child_terminated = 0; | 644 | child_terminated = 0; |
651 | connection_in = packet_get_connection_in(); | 645 | connection_in = packet_get_connection_in(); |
652 | connection_out = packet_get_connection_out(); | 646 | connection_out = packet_get_connection_out(); |
653 | max_fd = connection_in; | 647 | |
654 | if (connection_out > max_fd) | 648 | max_fd = MAX(connection_in, connection_out); |
655 | max_fd = connection_out; | 649 | |
656 | server_init_dispatch(); | 650 | server_init_dispatch(); |
657 | 651 | ||
658 | for (;;) { | 652 | for (;;) { |
@@ -665,16 +659,21 @@ server_loop2(void) | |||
665 | } | 659 | } |
666 | if (packet_not_very_much_data_to_write()) | 660 | if (packet_not_very_much_data_to_write()) |
667 | channel_output_poll(); | 661 | channel_output_poll(); |
668 | wait_until_can_do_something(&readset, &writeset, 0); | 662 | wait_until_can_do_something(&readset, &writeset, &max_fd, 0); |
669 | if (child_terminated) { | 663 | if (child_terminated) { |
670 | while ((pid = waitpid(-1, &status, WNOHANG)) > 0) | 664 | while ((pid = waitpid(-1, &status, WNOHANG)) > 0) |
671 | session_close_by_pid(pid, status); | 665 | session_close_by_pid(pid, status); |
672 | child_terminated = 0; | 666 | child_terminated = 0; |
673 | } | 667 | } |
674 | channel_after_select(&readset, &writeset); | 668 | channel_after_select(readset, writeset); |
675 | process_input(&readset); | 669 | process_input(readset); |
676 | process_output(&writeset); | 670 | process_output(writeset); |
677 | } | 671 | } |
672 | if (readset) | ||
673 | xfree(readset); | ||
674 | if (writeset) | ||
675 | xfree(writeset); | ||
676 | |||
678 | signal(SIGCHLD, SIG_DFL); | 677 | signal(SIGCHLD, SIG_DFL); |
679 | while ((pid = waitpid(-1, &status, WNOHANG)) > 0) | 678 | while ((pid = waitpid(-1, &status, WNOHANG)) > 0) |
680 | session_close_by_pid(pid, status); | 679 | session_close_by_pid(pid, status); |