telnetd: fix problem with zombies (by Paul Fox <pgf@brightstareng.com>)
syslogd: strip trailing NULs
This commit is contained in:
parent
cb981638f5
commit
018b155ad9
@ -57,7 +57,7 @@ typedef union {
|
|||||||
uint16_t filename_len; /* 22-23 */
|
uint16_t filename_len; /* 22-23 */
|
||||||
uint16_t extra_len; /* 24-25 */
|
uint16_t extra_len; /* 24-25 */
|
||||||
} formatted ATTRIBUTE_PACKED;
|
} formatted ATTRIBUTE_PACKED;
|
||||||
} zip_header_t;
|
} zip_header_t ATTRIBUTE_PACKED;
|
||||||
|
|
||||||
/* Check the offset of the last element, not the length. This leniency
|
/* Check the offset of the last element, not the length. This leniency
|
||||||
* allows for poor packing, whereby the overall struct may be too long,
|
* allows for poor packing, whereby the overall struct may be too long,
|
||||||
|
@ -279,6 +279,10 @@ make_new_session(
|
|||||||
/* make new session and process group */
|
/* make new session and process group */
|
||||||
setsid();
|
setsid();
|
||||||
|
|
||||||
|
/* Restore default signal handling */
|
||||||
|
signal(SIGCHLD, SIG_DFL);
|
||||||
|
signal(SIGPIPE, SIG_DFL);
|
||||||
|
|
||||||
/* open the child's side of the tty. */
|
/* open the child's side of the tty. */
|
||||||
/* NB: setsid() disconnects from any previous ctty's. Therefore
|
/* NB: setsid() disconnects from any previous ctty's. Therefore
|
||||||
* we must open child's side of the tty AFTER setsid! */
|
* we must open child's side of the tty AFTER setsid! */
|
||||||
@ -302,14 +306,18 @@ make_new_session(
|
|||||||
/* Uses FILE-based I/O to stdout, but does fflush(stdout),
|
/* Uses FILE-based I/O to stdout, but does fflush(stdout),
|
||||||
* so should be safe with vfork.
|
* so should be safe with vfork.
|
||||||
* I fear, though, that some users will have ridiculously big
|
* I fear, though, that some users will have ridiculously big
|
||||||
* issue files, and they may block writing to fd 1. */
|
* issue files, and they may block writing to fd 1,
|
||||||
|
* (parent is supposed to read it, but parent waits
|
||||||
|
* for vforked child to exec!) */
|
||||||
print_login_issue(issuefile, NULL);
|
print_login_issue(issuefile, NULL);
|
||||||
|
|
||||||
/* Exec shell / login / whatever */
|
/* Exec shell / login / whatever */
|
||||||
login_argv[0] = loginpath;
|
login_argv[0] = loginpath;
|
||||||
login_argv[1] = NULL;
|
login_argv[1] = NULL;
|
||||||
execvp(loginpath, (char **)login_argv);
|
/* exec busybox applet (if PREFER_APPLETS=y), if that fails,
|
||||||
/* Safer with vfork, and we shouldn't send message
|
* exec external program */
|
||||||
|
BB_EXECVP(loginpath, (char **)login_argv);
|
||||||
|
/* _exit is safer with vfork, and we shouldn't send message
|
||||||
* to remote clients anyway */
|
* to remote clients anyway */
|
||||||
_exit(1); /*bb_perror_msg_and_die("execv %s", loginpath);*/
|
_exit(1); /*bb_perror_msg_and_die("execv %s", loginpath);*/
|
||||||
}
|
}
|
||||||
@ -374,7 +382,7 @@ free_session(struct tsession *ts)
|
|||||||
|
|
||||||
#else /* !FEATURE_TELNETD_STANDALONE */
|
#else /* !FEATURE_TELNETD_STANDALONE */
|
||||||
|
|
||||||
/* Used in main() only, thus exits. */
|
/* Used in main() only, thus "return 0" actually is exit(0). */
|
||||||
#define free_session(ts) return 0
|
#define free_session(ts) return 0
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -384,20 +392,22 @@ static void handle_sigchld(int sig)
|
|||||||
pid_t pid;
|
pid_t pid;
|
||||||
struct tsession *ts;
|
struct tsession *ts;
|
||||||
|
|
||||||
pid = waitpid(-1, &sig, WNOHANG);
|
/* Looping: more than one child may have exited */
|
||||||
if (pid > 0) {
|
while (1) {
|
||||||
|
pid = waitpid(-1, NULL, WNOHANG);
|
||||||
|
if (pid <= 0)
|
||||||
|
break;
|
||||||
ts = sessions;
|
ts = sessions;
|
||||||
while (ts) {
|
while (ts) {
|
||||||
if (ts->shell_pid == pid) {
|
if (ts->shell_pid == pid) {
|
||||||
ts->shell_pid = -1;
|
ts->shell_pid = -1;
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
ts = ts->next;
|
ts = ts->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int telnetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
int telnetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
|
||||||
int telnetd_main(int argc, char **argv)
|
int telnetd_main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -430,7 +440,7 @@ int telnetd_main(int argc, char **argv)
|
|||||||
if (!(opt & OPT_FOREGROUND)) {
|
if (!(opt & OPT_FOREGROUND)) {
|
||||||
/* DAEMON_CHDIR_ROOT was giving inconsistent
|
/* DAEMON_CHDIR_ROOT was giving inconsistent
|
||||||
* behavior with/without -F, -i */
|
* behavior with/without -F, -i */
|
||||||
bb_daemonize_or_rexec(0 /*DAEMON_CHDIR_ROOT*/, argv);
|
bb_daemonize_or_rexec(0 /*was DAEMON_CHDIR_ROOT*/, argv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Redirect log to syslog early, if needed */
|
/* Redirect log to syslog early, if needed */
|
||||||
@ -466,6 +476,8 @@ int telnetd_main(int argc, char **argv)
|
|||||||
|
|
||||||
if (opt & OPT_WATCHCHILD)
|
if (opt & OPT_WATCHCHILD)
|
||||||
signal(SIGCHLD, handle_sigchld);
|
signal(SIGCHLD, handle_sigchld);
|
||||||
|
else /* prevent dead children from becoming zombies */
|
||||||
|
signal(SIGCHLD, SIG_IGN);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This is how the buffers are used. The arrows indicate the movement
|
This is how the buffers are used. The arrows indicate the movement
|
||||||
@ -497,7 +509,7 @@ int telnetd_main(int argc, char **argv)
|
|||||||
while (ts) {
|
while (ts) {
|
||||||
struct tsession *next = ts->next; /* in case we free ts. */
|
struct tsession *next = ts->next; /* in case we free ts. */
|
||||||
if (ts->shell_pid == -1) {
|
if (ts->shell_pid == -1) {
|
||||||
/* Child died ad we detected that */
|
/* Child died and we detected that */
|
||||||
free_session(ts);
|
free_session(ts);
|
||||||
} else {
|
} else {
|
||||||
if (ts->size1 > 0) /* can write to pty */
|
if (ts->size1 > 0) /* can write to pty */
|
||||||
@ -514,7 +526,7 @@ int telnetd_main(int argc, char **argv)
|
|||||||
if (!IS_INETD) {
|
if (!IS_INETD) {
|
||||||
FD_SET(master_fd, &rdfdset);
|
FD_SET(master_fd, &rdfdset);
|
||||||
/* This is needed because free_session() does not
|
/* This is needed because free_session() does not
|
||||||
* take into account master_fd when it finds new
|
* take master_fd into account when it finds new
|
||||||
* maxfd among remaining fd's */
|
* maxfd among remaining fd's */
|
||||||
if (master_fd > maxfd)
|
if (master_fd > maxfd)
|
||||||
maxfd = master_fd;
|
maxfd = master_fd;
|
||||||
|
@ -381,8 +381,8 @@ static void parse_fac_prio_20(int pri, char *res20)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* len parameter is used only for "is there a timestamp?" check.
|
/* len parameter is used only for "is there a timestamp?" check.
|
||||||
* NB: some callers cheat and supply 0 when they know
|
* NB: some callers cheat and supply len==0 when they know
|
||||||
* that there is no timestamp, short-cutting the test. */
|
* that there is no timestamp, short-circuiting the test. */
|
||||||
static void timestamp_and_log(int pri, char *msg, int len)
|
static void timestamp_and_log(int pri, char *msg, int len)
|
||||||
{
|
{
|
||||||
char *timestamp;
|
char *timestamp;
|
||||||
@ -427,11 +427,11 @@ static void split_escape_and_log(char *tmpbuf, int len)
|
|||||||
if (*p == '<') {
|
if (*p == '<') {
|
||||||
/* Parse the magic priority number */
|
/* Parse the magic priority number */
|
||||||
pri = bb_strtou(p + 1, &p, 10);
|
pri = bb_strtou(p + 1, &p, 10);
|
||||||
if (*p == '>') p++;
|
if (*p == '>')
|
||||||
if (pri & ~(LOG_FACMASK | LOG_PRIMASK)) {
|
p++;
|
||||||
|
if (pri & ~(LOG_FACMASK | LOG_PRIMASK))
|
||||||
pri = (LOG_USER | LOG_NOTICE);
|
pri = (LOG_USER | LOG_NOTICE);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
while ((c = *p++)) {
|
while ((c = *p++)) {
|
||||||
if (c == '\n')
|
if (c == '\n')
|
||||||
@ -526,14 +526,22 @@ static void do_syslogd(void)
|
|||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
size_t sz;
|
size_t sz;
|
||||||
|
read_again:
|
||||||
sz = safe_read(sock_fd, G.recvbuf, MAX_READ - 1);
|
sz = safe_read(sock_fd, G.recvbuf, MAX_READ - 1);
|
||||||
if (sz <= 0) {
|
if (sz < 0) {
|
||||||
//if (sz == 0)
|
|
||||||
// continue; /* EOF from unix socket??? */
|
|
||||||
bb_perror_msg_and_die("read from /dev/log");
|
bb_perror_msg_and_die("read from /dev/log");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Drop trailing NULs (typically there is one NUL) */
|
||||||
|
while (1) {
|
||||||
|
if (sz == 0)
|
||||||
|
goto read_again;
|
||||||
|
if (G.recvbuf[sz-1])
|
||||||
|
break;
|
||||||
|
sz--;
|
||||||
|
}
|
||||||
|
G.recvbuf[sz] = '\0'; /* make sure it *is* NUL terminated */
|
||||||
|
|
||||||
/* TODO: maybe suppress duplicates? */
|
/* TODO: maybe suppress duplicates? */
|
||||||
#if ENABLE_FEATURE_REMOTE_LOG
|
#if ENABLE_FEATURE_REMOTE_LOG
|
||||||
/* We are not modifying log messages in any way before send */
|
/* We are not modifying log messages in any way before send */
|
||||||
@ -549,7 +557,6 @@ static void do_syslogd(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
G.recvbuf[sz] = '\0';
|
|
||||||
split_escape_and_log(G.recvbuf, sz);
|
split_escape_and_log(G.recvbuf, sz);
|
||||||
} /* for */
|
} /* for */
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user