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
This commit is contained in:
parent
2949e13237
commit
680ee615fa
@ -47,6 +47,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <semaphore.h>
|
#include <semaphore.h>
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -104,6 +105,10 @@ static int telnetd_daemon(int argc, char *argv[])
|
|||||||
#ifdef CONFIG_NET_SOLINGER
|
#ifdef CONFIG_NET_SOLINGER
|
||||||
struct linger ling;
|
struct linger ling;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONFIG_SCHED_HAVE_PARENT
|
||||||
|
struct sigaction sa;
|
||||||
|
sigset_t blockset;
|
||||||
|
#endif
|
||||||
socklen_t addrlen;
|
socklen_t addrlen;
|
||||||
FAR char *devpath;
|
FAR char *devpath;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
@ -121,13 +126,45 @@ static int telnetd_daemon(int argc, char *argv[])
|
|||||||
sem_post(&g_telnetdcommon.startsem);
|
sem_post(&g_telnetdcommon.startsem);
|
||||||
DEBUGASSERT(daemon != NULL);
|
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 */
|
/* Create a new TCP socket to use to listen for connections */
|
||||||
|
|
||||||
listensd = socket(PF_INET, SOCK_STREAM, 0);
|
listensd = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
if (listensd < 0)
|
if (listensd < 0)
|
||||||
{
|
{
|
||||||
int errval = errno;
|
int errval = errno;
|
||||||
ndbg("socket failure: %d\n", errval);
|
ndbg("ERROR: socket failure: %d\n", errval);
|
||||||
return -errval;
|
return -errval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +174,7 @@ static int telnetd_daemon(int argc, char *argv[])
|
|||||||
optval = 1;
|
optval = 1;
|
||||||
if (setsockopt(listensd, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof(int)) < 0)
|
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;
|
goto errout_with_socket;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -150,7 +187,7 @@ static int telnetd_daemon(int argc, char *argv[])
|
|||||||
|
|
||||||
if (bind(listensd, (struct sockaddr*)&myaddr, sizeof(struct sockaddr_in)) < 0)
|
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;
|
goto errout_with_socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,7 +195,7 @@ static int telnetd_daemon(int argc, char *argv[])
|
|||||||
|
|
||||||
if (listen(listensd, 5) < 0)
|
if (listen(listensd, 5) < 0)
|
||||||
{
|
{
|
||||||
ndbg("listen failure %d\n", errno);
|
ndbg("ERROR: listen failure %d\n", errno);
|
||||||
goto errout_with_socket;
|
goto errout_with_socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,8 +220,21 @@ static int telnetd_daemon(int argc, char *argv[])
|
|||||||
acceptsd = accept(listensd, (struct sockaddr*)&myaddr, &addrlen);
|
acceptsd = accept(listensd, (struct sockaddr*)&myaddr, &addrlen);
|
||||||
if (acceptsd < 0)
|
if (acceptsd < 0)
|
||||||
{
|
{
|
||||||
nlldbg("accept failed: %d\n", errno);
|
/* Accept failed */
|
||||||
goto errout_with_socket;
|
|
||||||
|
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 */
|
/* 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 */
|
ling.l_linger = 30; /* timeout is seconds */
|
||||||
if (setsockopt(acceptsd, SOL_SOCKET, SO_LINGER, &ling, sizeof(struct linger)) < 0)
|
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;
|
goto errout_with_acceptsd;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -205,7 +255,7 @@ static int telnetd_daemon(int argc, char *argv[])
|
|||||||
devpath = telnetd_driver(acceptsd, daemon);
|
devpath = telnetd_driver(acceptsd, daemon);
|
||||||
if (devpath < 0)
|
if (devpath < 0)
|
||||||
{
|
{
|
||||||
nlldbg("telnetd_driver failed\n");
|
nlldbg("ERROR: telnetd_driver failed\n");
|
||||||
goto errout_with_acceptsd;
|
goto errout_with_acceptsd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +265,7 @@ static int telnetd_daemon(int argc, char *argv[])
|
|||||||
drvrfd = open(devpath, O_RDWR);
|
drvrfd = open(devpath, O_RDWR);
|
||||||
if (drvrfd < 0)
|
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;
|
goto errout_with_acceptsd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,7 +295,7 @@ static int telnetd_daemon(int argc, char *argv[])
|
|||||||
daemon->entry, NULL);
|
daemon->entry, NULL);
|
||||||
if (pid < 0)
|
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;
|
goto errout_with_acceptsd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,7 +377,7 @@ int telnetd_start(FAR struct telnetd_config_s *config)
|
|||||||
{
|
{
|
||||||
int errval = errno;
|
int errval = errno;
|
||||||
free(daemon);
|
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;
|
return -errval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user