123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- 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>
- ---
- Upstream-Status: Pending
- 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
|