aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-11-06 01:38:46 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-11-06 01:38:46 +0000
commit018b155ad938ed9a1867214e13b166495599d222 (patch)
treecb6b553062b365af521fc27159efa812da59f0bf
parentcb981638f502f4cc5ea830edc7ef62ab71112186 (diff)
downloadbusybox-w32-018b155ad938ed9a1867214e13b166495599d222.tar.gz
busybox-w32-018b155ad938ed9a1867214e13b166495599d222.tar.bz2
busybox-w32-018b155ad938ed9a1867214e13b166495599d222.zip
telnetd: fix problem with zombies (by Paul Fox <pgf@brightstareng.com>)
syslogd: strip trailing NULs
-rw-r--r--archival/unzip.c2
-rw-r--r--networking/telnetd.c34
-rw-r--r--sysklogd/syslogd.c27
3 files changed, 41 insertions, 22 deletions
diff --git a/archival/unzip.c b/archival/unzip.c
index 8462822f1..001f2e128 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -57,7 +57,7 @@ typedef union {
57 uint16_t filename_len; /* 22-23 */ 57 uint16_t filename_len; /* 22-23 */
58 uint16_t extra_len; /* 24-25 */ 58 uint16_t extra_len; /* 24-25 */
59 } formatted ATTRIBUTE_PACKED; 59 } formatted ATTRIBUTE_PACKED;
60} zip_header_t; 60} zip_header_t ATTRIBUTE_PACKED;
61 61
62/* Check the offset of the last element, not the length. This leniency 62/* Check the offset of the last element, not the length. This leniency
63 * allows for poor packing, whereby the overall struct may be too long, 63 * allows for poor packing, whereby the overall struct may be too long,
diff --git a/networking/telnetd.c b/networking/telnetd.c
index cccf03dfd..108bbf44f 100644
--- a/networking/telnetd.c
+++ b/networking/telnetd.c
@@ -279,6 +279,10 @@ make_new_session(
279 /* make new session and process group */ 279 /* make new session and process group */
280 setsid(); 280 setsid();
281 281
282 /* Restore default signal handling */
283 signal(SIGCHLD, SIG_DFL);
284 signal(SIGPIPE, SIG_DFL);
285
282 /* open the child's side of the tty. */ 286 /* open the child's side of the tty. */
283 /* NB: setsid() disconnects from any previous ctty's. Therefore 287 /* NB: setsid() disconnects from any previous ctty's. Therefore
284 * we must open child's side of the tty AFTER setsid! */ 288 * we must open child's side of the tty AFTER setsid! */
@@ -302,14 +306,18 @@ make_new_session(
302 /* Uses FILE-based I/O to stdout, but does fflush(stdout), 306 /* Uses FILE-based I/O to stdout, but does fflush(stdout),
303 * so should be safe with vfork. 307 * so should be safe with vfork.
304 * I fear, though, that some users will have ridiculously big 308 * I fear, though, that some users will have ridiculously big
305 * issue files, and they may block writing to fd 1. */ 309 * issue files, and they may block writing to fd 1,
310 * (parent is supposed to read it, but parent waits
311 * for vforked child to exec!) */
306 print_login_issue(issuefile, NULL); 312 print_login_issue(issuefile, NULL);
307 313
308 /* Exec shell / login / whatever */ 314 /* Exec shell / login / whatever */
309 login_argv[0] = loginpath; 315 login_argv[0] = loginpath;
310 login_argv[1] = NULL; 316 login_argv[1] = NULL;
311 execvp(loginpath, (char **)login_argv); 317 /* exec busybox applet (if PREFER_APPLETS=y), if that fails,
312 /* Safer with vfork, and we shouldn't send message 318 * exec external program */
319 BB_EXECVP(loginpath, (char **)login_argv);
320 /* _exit is safer with vfork, and we shouldn't send message
313 * to remote clients anyway */ 321 * to remote clients anyway */
314 _exit(1); /*bb_perror_msg_and_die("execv %s", loginpath);*/ 322 _exit(1); /*bb_perror_msg_and_die("execv %s", loginpath);*/
315} 323}
@@ -374,7 +382,7 @@ free_session(struct tsession *ts)
374 382
375#else /* !FEATURE_TELNETD_STANDALONE */ 383#else /* !FEATURE_TELNETD_STANDALONE */
376 384
377/* Used in main() only, thus exits. */ 385/* Used in main() only, thus "return 0" actually is exit(0). */
378#define free_session(ts) return 0 386#define free_session(ts) return 0
379 387
380#endif 388#endif
@@ -384,20 +392,22 @@ static void handle_sigchld(int sig)
384 pid_t pid; 392 pid_t pid;
385 struct tsession *ts; 393 struct tsession *ts;
386 394
387 pid = waitpid(-1, &sig, WNOHANG); 395 /* Looping: more than one child may have exited */
388 if (pid > 0) { 396 while (1) {
397 pid = waitpid(-1, NULL, WNOHANG);
398 if (pid <= 0)
399 break;
389 ts = sessions; 400 ts = sessions;
390 while (ts) { 401 while (ts) {
391 if (ts->shell_pid == pid) { 402 if (ts->shell_pid == pid) {
392 ts->shell_pid = -1; 403 ts->shell_pid = -1;
393 return; 404 break;
394 } 405 }
395 ts = ts->next; 406 ts = ts->next;
396 } 407 }
397 } 408 }
398} 409}
399 410
400
401int telnetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 411int telnetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
402int telnetd_main(int argc, char **argv) 412int telnetd_main(int argc, char **argv)
403{ 413{
@@ -430,7 +440,7 @@ int telnetd_main(int argc, char **argv)
430 if (!(opt & OPT_FOREGROUND)) { 440 if (!(opt & OPT_FOREGROUND)) {
431 /* DAEMON_CHDIR_ROOT was giving inconsistent 441 /* DAEMON_CHDIR_ROOT was giving inconsistent
432 * behavior with/without -F, -i */ 442 * behavior with/without -F, -i */
433 bb_daemonize_or_rexec(0 /*DAEMON_CHDIR_ROOT*/, argv); 443 bb_daemonize_or_rexec(0 /*was DAEMON_CHDIR_ROOT*/, argv);
434 } 444 }
435 } 445 }
436 /* Redirect log to syslog early, if needed */ 446 /* Redirect log to syslog early, if needed */
@@ -466,6 +476,8 @@ int telnetd_main(int argc, char **argv)
466 476
467 if (opt & OPT_WATCHCHILD) 477 if (opt & OPT_WATCHCHILD)
468 signal(SIGCHLD, handle_sigchld); 478 signal(SIGCHLD, handle_sigchld);
479 else /* prevent dead children from becoming zombies */
480 signal(SIGCHLD, SIG_IGN);
469 481
470/* 482/*
471 This is how the buffers are used. The arrows indicate the movement 483 This is how the buffers are used. The arrows indicate the movement
@@ -497,7 +509,7 @@ int telnetd_main(int argc, char **argv)
497 while (ts) { 509 while (ts) {
498 struct tsession *next = ts->next; /* in case we free ts. */ 510 struct tsession *next = ts->next; /* in case we free ts. */
499 if (ts->shell_pid == -1) { 511 if (ts->shell_pid == -1) {
500 /* Child died ad we detected that */ 512 /* Child died and we detected that */
501 free_session(ts); 513 free_session(ts);
502 } else { 514 } else {
503 if (ts->size1 > 0) /* can write to pty */ 515 if (ts->size1 > 0) /* can write to pty */
@@ -514,7 +526,7 @@ int telnetd_main(int argc, char **argv)
514 if (!IS_INETD) { 526 if (!IS_INETD) {
515 FD_SET(master_fd, &rdfdset); 527 FD_SET(master_fd, &rdfdset);
516 /* This is needed because free_session() does not 528 /* This is needed because free_session() does not
517 * take into account master_fd when it finds new 529 * take master_fd into account when it finds new
518 * maxfd among remaining fd's */ 530 * maxfd among remaining fd's */
519 if (master_fd > maxfd) 531 if (master_fd > maxfd)
520 maxfd = master_fd; 532 maxfd = master_fd;
diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c
index ba46792b6..2bf5b5c80 100644
--- a/sysklogd/syslogd.c
+++ b/sysklogd/syslogd.c
@@ -381,8 +381,8 @@ static void parse_fac_prio_20(int pri, char *res20)
381} 381}
382 382
383/* len parameter is used only for "is there a timestamp?" check. 383/* len parameter is used only for "is there a timestamp?" check.
384 * NB: some callers cheat and supply 0 when they know 384 * NB: some callers cheat and supply len==0 when they know
385 * that there is no timestamp, short-cutting the test. */ 385 * that there is no timestamp, short-circuiting the test. */
386static void timestamp_and_log(int pri, char *msg, int len) 386static void timestamp_and_log(int pri, char *msg, int len)
387{ 387{
388 char *timestamp; 388 char *timestamp;
@@ -427,10 +427,10 @@ static void split_escape_and_log(char *tmpbuf, int len)
427 if (*p == '<') { 427 if (*p == '<') {
428 /* Parse the magic priority number */ 428 /* Parse the magic priority number */
429 pri = bb_strtou(p + 1, &p, 10); 429 pri = bb_strtou(p + 1, &p, 10);
430 if (*p == '>') p++; 430 if (*p == '>')
431 if (pri & ~(LOG_FACMASK | LOG_PRIMASK)) { 431 p++;
432 if (pri & ~(LOG_FACMASK | LOG_PRIMASK))
432 pri = (LOG_USER | LOG_NOTICE); 433 pri = (LOG_USER | LOG_NOTICE);
433 }
434 } 434 }
435 435
436 while ((c = *p++)) { 436 while ((c = *p++)) {
@@ -526,14 +526,22 @@ static void do_syslogd(void)
526 526
527 for (;;) { 527 for (;;) {
528 size_t sz; 528 size_t sz;
529 529 read_again:
530 sz = safe_read(sock_fd, G.recvbuf, MAX_READ - 1); 530 sz = safe_read(sock_fd, G.recvbuf, MAX_READ - 1);
531 if (sz <= 0) { 531 if (sz < 0) {
532 //if (sz == 0)
533 // continue; /* EOF from unix socket??? */
534 bb_perror_msg_and_die("read from /dev/log"); 532 bb_perror_msg_and_die("read from /dev/log");
535 } 533 }
536 534
535 /* Drop trailing NULs (typically there is one NUL) */
536 while (1) {
537 if (sz == 0)
538 goto read_again;
539 if (G.recvbuf[sz-1])
540 break;
541 sz--;
542 }
543 G.recvbuf[sz] = '\0'; /* make sure it *is* NUL terminated */
544
537 /* TODO: maybe suppress duplicates? */ 545 /* TODO: maybe suppress duplicates? */
538#if ENABLE_FEATURE_REMOTE_LOG 546#if ENABLE_FEATURE_REMOTE_LOG
539 /* We are not modifying log messages in any way before send */ 547 /* We are not modifying log messages in any way before send */
@@ -549,7 +557,6 @@ static void do_syslogd(void)
549 } 557 }
550 } 558 }
551#endif 559#endif
552 G.recvbuf[sz] = '\0';
553 split_escape_and_log(G.recvbuf, sz); 560 split_escape_and_log(G.recvbuf, sz);
554 } /* for */ 561 } /* for */
555} 562}