From 70243edc4a9811caf2c98334ad2a057efeab10f5 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 22 Jan 2015 06:33:55 -0600 Subject: apps/netutils/telnetd: Add protection when CONFIG_SCHED_HAVE_PARENT is enabled: Call sigaction with SA_NOCLDWAIT so that exit status is not retained (no zombies) and block receipt of SIGCHLD so that accept is not awakened by a signal. Iff accept() is awakened by a signal, do not do anything crazy like exit. Most from Rony Xln --- apps/netutils/telnetd/telnetd_daemon.c | 72 ++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 11 deletions(-) (limited to 'apps/netutils') diff --git a/apps/netutils/telnetd/telnetd_daemon.c b/apps/netutils/telnetd/telnetd_daemon.c index 4d2ab943b..b90ef3207 100644 --- a/apps/netutils/telnetd/telnetd_daemon.c +++ b/apps/netutils/telnetd/telnetd_daemon.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -104,6 +105,10 @@ static int telnetd_daemon(int argc, char *argv[]) #ifdef CONFIG_NET_SOLINGER struct linger ling; #endif +#ifdef CONFIG_SCHED_HAVE_PARENT + struct sigaction sa; + sigset_t blockset; +#endif socklen_t addrlen; FAR char *devpath; pid_t pid; @@ -121,13 +126,45 @@ static int telnetd_daemon(int argc, char *argv[]) sem_post(&g_telnetdcommon.startsem); DEBUGASSERT(daemon != NULL); +#ifdef CONFIG_SCHED_HAVE_PARENT + /* Call sigaction with the SA_NOCLDWAIT flag so that we do not transform + * children into "zombies" when they terminate: Child exit status will + * not be retained. + * + * NOTE: If the SA_NOCLDWAIT flag is set when establishing a handler for + * SIGCHLD, POSIX.1 leaves it unspecified whether a SIGCHLD signal is + * generated when a child process terminates. On both Linux and NuttX, a + * SIGCHLD signal will be generated in this case. + */ + + sa.sa_handler = SIG_IGN; + sa.sa_flags = SA_NOCLDWAIT; + if (sigaction(SIGCHLD, &sa, NULL) < 0) + { + int errval = errno; + ndbg("ERROR: sigaction failed: %d\n", errval); + return -errval; + } + + /* Block receipt of the SIGCHLD signal */ + + sigemptyset(&blockset); + sigaddset(&blockset, SIGCHLD); + if (sigprocmask(SIG_BLOCK, &blockset, NULL) < 0) + { + int errval = errno; + ndbg("ERROR: sigprocmask failed: %d\n", errval); + return -errval; + } +#endif /* CONFIG_SCHED_HAVE_PARENT */ + /* Create a new TCP socket to use to listen for connections */ listensd = socket(PF_INET, SOCK_STREAM, 0); if (listensd < 0) { int errval = errno; - ndbg("socket failure: %d\n", errval); + ndbg("ERROR: socket failure: %d\n", errval); return -errval; } @@ -137,7 +174,7 @@ static int telnetd_daemon(int argc, char *argv[]) optval = 1; if (setsockopt(listensd, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof(int)) < 0) { - ndbg("setsockopt SO_REUSEADDR failure: %d\n", errno); + ndbg("ERROR: setsockopt SO_REUSEADDR failure: %d\n", errno); goto errout_with_socket; } #endif @@ -150,7 +187,7 @@ static int telnetd_daemon(int argc, char *argv[]) if (bind(listensd, (struct sockaddr*)&myaddr, sizeof(struct sockaddr_in)) < 0) { - ndbg("bind failure: %d\n", errno); + ndbg("ERROR: bind failure: %d\n", errno); goto errout_with_socket; } @@ -158,7 +195,7 @@ static int telnetd_daemon(int argc, char *argv[]) if (listen(listensd, 5) < 0) { - ndbg("listen failure %d\n", errno); + ndbg("ERROR: listen failure %d\n", errno); goto errout_with_socket; } @@ -183,8 +220,21 @@ static int telnetd_daemon(int argc, char *argv[]) acceptsd = accept(listensd, (struct sockaddr*)&myaddr, &addrlen); if (acceptsd < 0) { - nlldbg("accept failed: %d\n", errno); - goto errout_with_socket; + /* Accept failed */ + + int errval = errno; + + /* Just continue if a signal was received */ + + if (errval == EINTR) + { + continue; + } + else + { + nlldbg("ERROR: accept failed: %d\n", errval); + goto errout_with_socket; + } } /* Configure to "linger" until all data is sent when the socket is closed */ @@ -194,7 +244,7 @@ static int telnetd_daemon(int argc, char *argv[]) ling.l_linger = 30; /* timeout is seconds */ if (setsockopt(acceptsd, SOL_SOCKET, SO_LINGER, &ling, sizeof(struct linger)) < 0) { - nlldbg("setsockopt failed: %d\n", errno); + nlldbg("ERROR: setsockopt failed: %d\n", errno); goto errout_with_acceptsd; } #endif @@ -205,7 +255,7 @@ static int telnetd_daemon(int argc, char *argv[]) devpath = telnetd_driver(acceptsd, daemon); if (devpath < 0) { - nlldbg("telnetd_driver failed\n"); + nlldbg("ERROR: telnetd_driver failed\n"); goto errout_with_acceptsd; } @@ -215,7 +265,7 @@ static int telnetd_daemon(int argc, char *argv[]) drvrfd = open(devpath, O_RDWR); if (drvrfd < 0) { - nlldbg("Failed to open %s: %d\n", devpath, errno); + nlldbg("ERROR: Failed to open %s: %d\n", devpath, errno); goto errout_with_acceptsd; } @@ -245,7 +295,7 @@ static int telnetd_daemon(int argc, char *argv[]) daemon->entry, NULL); if (pid < 0) { - nlldbg("Failed start the telnet session: %d\n", errno); + nlldbg("ERROR: Failed start the telnet session: %d\n", errno); goto errout_with_acceptsd; } @@ -327,7 +377,7 @@ int telnetd_start(FAR struct telnetd_config_s *config) { int errval = errno; free(daemon); - ndbg("Failed to start the telnet daemon: %d\n", errval); + ndbg("ERROR: Failed to start the telnet daemon: %d\n", errval); return -errval; } -- cgit v1.2.3