mirror of
git://git.openembedded.org/meta-openembedded
synced 2026-05-18 22:51:53 +00:00
telnetd: Fix deadlock on cleanup
The cleanup function in telnetd is called both directly and on SIGCHLD signals. This triggered a deadlock in glibc and was reproduced in glibc 2.27 while running on a 4.14.30 kernel. Signed-off-by: Seiichi Ishitsuka <ishitsuka.sc@ncos.nec.co.jp> Signed-off-by: Khem Raj <raj.khem@gmail.com>
This commit is contained in:
parent
d3bd6dac44
commit
d9e257abbe
@ -0,0 +1,114 @@
|
||||
From 06ed6a6bf25a22902846097d6b6c97e070c2c326 Mon Sep 17 00:00:00 2001
|
||||
From: Seiichi Ishitsuka <ishitsuka.sc@ncos.nec.co.jp>
|
||||
Date: Fri, 1 Jun 2018 14:27:35 +0900
|
||||
Subject: [PATCH] telnetd: Fix deadlock on cleanup
|
||||
|
||||
The cleanup function in telnetd is called both directly and on SIGCHLD
|
||||
signals. This, unfortunately, triggered a deadlock in eglibc 2.9 while
|
||||
running on a 2.6.31.11 kernel.
|
||||
|
||||
What we were seeing is hangs like these:
|
||||
|
||||
(gdb) bt
|
||||
#0 0xb7702424 in __kernel_vsyscall ()
|
||||
#1 0xb7658e61 in __lll_lock_wait_private () from ./lib/libc.so.6
|
||||
#2 0xb767e7b5 in _L_lock_15 () from ./lib/libc.so.6
|
||||
#3 0xb767e6e0 in utmpname () from ./lib/libc.so.6
|
||||
#4 0xb76bcde7 in logout () from ./lib/libutil.so.1
|
||||
#5 0x0804c827 in cleanup ()
|
||||
#6 <signal handler called>
|
||||
#7 0xb7702424 in __kernel_vsyscall ()
|
||||
#8 0xb7641003 in __fcntl_nocancel () from ./lib/libc.so.6
|
||||
#9 0xb767e0c3 in getutline_r_file () from ./lib/libc.so.6
|
||||
#10 0xb767d675 in getutline_r () from ./lib/libc.so.6
|
||||
#11 0xb76bce42 in logout () from ./lib/libutil.so.1
|
||||
#12 0x0804c827 in cleanup ()
|
||||
#13 0x0804a0b5 in telnet ()
|
||||
#14 0x0804a9c3 in main ()
|
||||
|
||||
and what has happened here is that the user closes the telnet session
|
||||
via the escape character. This causes telnetd to call cleanup in frame
|
||||
the SIGCHLD signal is delivered while telnetd is executing cleanup.
|
||||
|
||||
Telnetd then calls the signal handler for SIGCHLD, which is cleanup().
|
||||
Ouch. The actual deadlock is in libc. getutline_r in frame #10 gets the
|
||||
__libc_utmp_lock lock, and utmpname above does the same thing in frame
|
||||
|
||||
The fix registers the SIGCHLD handler as cleanup_sighandler, and makes
|
||||
cleanup disable the SIGCHLD signal before calling cleanup_sighandler.
|
||||
|
||||
Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
|
||||
|
||||
The patch was imported from the Ubuntu netkit-telnet package.
|
||||
(https://bugs.launchpad.net/ubuntu/+source/netkit-telnet/+bug/507455)
|
||||
|
||||
A previous patch declaring attributes of functions, but it is not used
|
||||
in upstream.
|
||||
|
||||
Signed-off-by: Seiichi Ishitsuka <ishitsuka.sc@ncos.nec.co.jp>
|
||||
---
|
||||
telnetd/ext.h | 1 +
|
||||
telnetd/sys_term.c | 17 ++++++++++++++++-
|
||||
telnetd/telnetd.c | 2 +-
|
||||
3 files changed, 18 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/telnetd/ext.h b/telnetd/ext.h
|
||||
index b98d6ec..08f9d07 100644
|
||||
--- a/telnetd/ext.h
|
||||
+++ b/telnetd/ext.h
|
||||
@@ -97,6 +97,7 @@ void add_slc(int, int, int);
|
||||
void check_slc(void);
|
||||
void change_slc(int, int, int);
|
||||
void cleanup(int);
|
||||
+void cleanup_sighandler(int);
|
||||
void clientstat(int, int, int);
|
||||
void copy_termbuf(char *, int);
|
||||
void deferslc(void);
|
||||
diff --git a/telnetd/sys_term.c b/telnetd/sys_term.c
|
||||
index 5b4aa84..c4fb0f7 100644
|
||||
--- a/telnetd/sys_term.c
|
||||
+++ b/telnetd/sys_term.c
|
||||
@@ -719,7 +719,7 @@ static void addarg(struct argv_stuff *avs, const char *val) {
|
||||
* This is the routine to call when we are all through, to
|
||||
* clean up anything that needs to be cleaned up.
|
||||
*/
|
||||
-void cleanup(int sig) {
|
||||
+void cleanup_sighandler(int sig) {
|
||||
char *p;
|
||||
(void)sig;
|
||||
|
||||
@@ -742,3 +742,18 @@ void cleanup(int sig) {
|
||||
shutdown(net, 2);
|
||||
exit(0);
|
||||
}
|
||||
+
|
||||
+void cleanup(int sig) {
|
||||
+ sigset_t mask, oldmask;
|
||||
+
|
||||
+ /* Set up the mask of signals to temporarily block. */
|
||||
+ sigemptyset (&mask);
|
||||
+ sigaddset (&mask, SIGCHLD);
|
||||
+
|
||||
+ /* Block SIGCHLD while running cleanup */
|
||||
+ sigprocmask (SIG_BLOCK, &mask, &oldmask);
|
||||
+
|
||||
+ cleanup_sighandler(sig);
|
||||
+ /* Technically not needed since cleanup_sighandler exits */
|
||||
+ sigprocmask (SIG_UNBLOCK, &mask, NULL);
|
||||
+}
|
||||
diff --git a/telnetd/telnetd.c b/telnetd/telnetd.c
|
||||
index 9ace838..788919c 100644
|
||||
--- a/telnetd/telnetd.c
|
||||
+++ b/telnetd/telnetd.c
|
||||
@@ -833,7 +833,7 @@ void telnet(int f, int p)
|
||||
signal(SIGTTOU, SIG_IGN);
|
||||
#endif
|
||||
|
||||
- signal(SIGCHLD, cleanup);
|
||||
+ signal(SIGCHLD, cleanup_sighandler);
|
||||
|
||||
#ifdef TIOCNOTTY
|
||||
{
|
||||
--
|
||||
2.7.4
|
||||
|
||||
@ -11,6 +11,7 @@ SRC_URI = "ftp://ftp.uk.linux.org/pub/linux/Networking/netkit/${BP}.tar.gz \
|
||||
file://telnet-xinetd \
|
||||
file://cross-compile.patch \
|
||||
file://0001-telnet-telnetd-Fix-print-format-strings.patch \
|
||||
file://0001-telnet-telnetd-Fix-deadlock-on-cleanup.patch \
|
||||
"
|
||||
|
||||
UPSTREAM_CHECK_URI = "${DEBIAN_MIRROR}/main/n/netkit-telnet/"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user