[oe] [PATCH][meta-networking] inetutils: Fix deadlock in telnetd when cleanup
Rongqing Li
rongqing.li at windriver.com
Thu Jul 16 02:41:41 UTC 2015
On 2015年07月16日 00:06, Joe MacDonald wrote:
> Is this fix even relevant? Has anyone seen this or able to trigger it
> (maybe by using the script in the first link? I wasn't.) If someone
> thinks this is still required, I'll merge it, but on the surface it's a
> five year old patch for a different piece of software (netkit-telnet vs.
> inetutils) that causes a deadlock on a much older version of a libc
> library and a five-and-a-half-year-old kernel.
>
> -J.
Ok, please drop it;
Our customer reported a telnetd deadlock issue on our old product,
And Wang fixed it by porting this patch; but I can not reproduce it
whether in old or new product.
-Roy
>
> [[oe] [PATCH][meta-networking] inetutils: Fix deadlock in telnetd when cleanup] On 15.07.06 (Mon 17:16) rongqing.li at windriver.com wrote:
>
>> From: Li Wang <li.wang at windriver.com>
>>
>> the patch comes from:
>> https://bugs.launchpad.net/ubuntu/+source/netkit-telnet/+bug/507455
>> https://launchpadlibrarian.net/37882973/0001-telnetd-Fix-deadlock-on-cleanup.patch
>>
>> 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 at netinsight.net>
>> Signed-off-by: Li Wang <li.wang at windriver.com>
>> ---
>> .../telnetd-Fix-deadlock-on-cleanup.patch | 108 +++++++++++++++++++++
>> .../inetutils/inetutils_1.9.2.bb | 1 +
>> 2 files changed, 109 insertions(+)
>> create mode 100644 meta-networking/recipes-connectivity/inetutils/inetutils-1.9.2/telnetd-Fix-deadlock-on-cleanup.patch
>>
>> diff --git a/meta-networking/recipes-connectivity/inetutils/inetutils-1.9.2/telnetd-Fix-deadlock-on-cleanup.patch b/meta-networking/recipes-connectivity/inetutils/inetutils-1.9.2/telnetd-Fix-deadlock-on-cleanup.patch
>> new file mode 100644
>> index 0000000..3ec7613
>> --- /dev/null
>> +++ b/meta-networking/recipes-connectivity/inetutils/inetutils-1.9.2/telnetd-Fix-deadlock-on-cleanup.patch
>> @@ -0,0 +1,108 @@
>> +telnetd: Fix deadlock on cleanup
>> +
>> +the patch comes from:
>> +https://bugs.launchpad.net/ubuntu/+source/netkit-telnet/+bug/507455
>> +https://launchpadlibrarian.net/37882973/0001-telnetd-Fix-deadlock-on-cleanup.patch
>> +
>> +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 at netinsight.net>
>> +Signed-off-by: Li Wang <li.wang at windriver.com>
>> +---
>> + telnetd/pty.c | 17 ++++++++++++++++-
>> + telnetd/telnetd.c | 2 +-
>> + telnetd/telnetd.h | 1 +
>> + 3 files changed, 18 insertions(+), 2 deletions(-)
>> +
>> +diff --git a/telnetd/pty.c b/telnetd/pty.c
>> +index 21b0b69..22a17c5 100644
>> +--- a/telnetd/pty.c
>> ++++ b/telnetd/pty.c
>> +@@ -145,7 +145,7 @@ start_login (char *host, int autologin, char *name)
>> + * reported exit code.
>> + */
>> + void
>> +-cleanup (int sig)
>> ++cleanup_sighandler (int sig)
>> + {
>> + int status = EXIT_FAILURE;
>> + char *p;
>> +@@ -168,3 +168,18 @@ cleanup (int sig)
>> + shutdown (net, 2);
>> + exit (status);
>> + }
>> ++
>> ++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 cf7ce0f..4fe95b5 100644
>> +--- a/telnetd/telnetd.c
>> ++++ b/telnetd/telnetd.c
>> +@@ -527,7 +527,7 @@ telnetd_setup (int fd)
>> + signal (SIGTTOU, SIG_IGN);
>> + #endif
>> +
>> +- signal (SIGCHLD, cleanup);
>> ++ signal (SIGCHLD, cleanup_sighandler);
>> + }
>> +
>> + int
>> +diff --git a/telnetd/telnetd.h b/telnetd/telnetd.h
>> +index ce90fbc..8bac120 100644
>> +--- a/telnetd/telnetd.h
>> ++++ b/telnetd/telnetd.h
>> +@@ -326,6 +326,7 @@ extern void add_slc (char func, char flag, cc_t val);
>> + extern void check_slc (void);
>> + extern void change_slc (char func, char flag, cc_t val);
>> +
>> ++extern void cleanup_sighandler (int);
>> + extern void cleanup (int);
>> + extern void clientstat (int, int, int);
>> + extern void copy_termbuf ();
>> +--
>> +1.7.9.5
>> +
>> diff --git a/meta-networking/recipes-connectivity/inetutils/inetutils_1.9.2.bb b/meta-networking/recipes-connectivity/inetutils/inetutils_1.9.2.bb
>> index 9bb9fe8..5c5699a 100644
>> --- a/meta-networking/recipes-connectivity/inetutils/inetutils_1.9.2.bb
>> +++ b/meta-networking/recipes-connectivity/inetutils/inetutils_1.9.2.bb
>> @@ -18,6 +18,7 @@ SRC_URI = "${GNU_MIRROR}/inetutils/inetutils-${PV}.tar.gz \
>> file://telnet.xinetd.inetutils \
>> file://tftpd.xinetd.inetutils \
>> file://inetutils-1.9-PATH_PROCNET_DEV.patch \
>> + file://telnetd-Fix-deadlock-on-cleanup.patch \
>> "
>>
>> SRC_URI[md5sum] = "aa1a9a132259db83e66c1f3265065ba2"
>> --
>> 1.9.1
>>
--
Best Reagrds,
Roy | RongQing Li
More information about the Openembedded-devel
mailing list