>Synopsis:      Locked tmux session can be escaped from by using ctrl+\
>Category:      user
>Environment:
        System      : OpenBSD 6.7
        Details     : OpenBSD 6.7-current (GENERIC.MP) #1: Mon Aug  3 14:30:52 
MDT 2020
                         
[email protected]:/usr/src/sys/arch/amd64/compile/GENERIC.MP

        Architecture: OpenBSD.amd64
        Machine     : amd64
>Description:
        After pressing ^\ inside a locked tmux session, tmux dumps core
        but doesn't exit, instead detaching from the terminal. After
        reattaching, the session will not be locked anymore.

        If using the default "lock-command" which is lock(1), shortly
        afterwards the screen will be flooded with lock(1)'s prompts,
        but you can enter commands in the parent shell and kill the
        lock process.

        When ran normally (even inside tmux), lock(1) ignores the
        SIGQUIT from ^\, therefore this bug only affects tmux's
        "locked" state. I tested this with an empty ~/.tmux.conf.

        Also reproduced on OpenBSD-stable 6.7 (GENERIC.MP) #5 amd64, and
        tmux 3.1b on Linux.
        
        gdb(1) backtrace of the tmux core dump (on -current):

        #0  _thread_sys_wait4 () at /tmp/-:3
        #1  0x000006a794ac582e in _libc_wait4_cancel (wpid=Variable "wpid" is 
not available.) at /usr/src/lib/libc/sys/w_wait4.c:27
        #2  0x000006a794b2e00d in _libc_system (command=Variable "command" is 
not available.) at /usr/src/lib/libc/stdlib/system.c:69
        #3  0x000006a4caac7a00 in client_dispatch_attached 
(imsg=0x7f7ffffd3c70) at client.c:1006
        #4  0x000006a4caac7270 in client_dispatch (imsg=0x7f7ffffd3c70, 
arg=0x0) at client.c:807
        #5  0x000006a4cab1dc66 in proc_event_cb (fd=6, events=2, 
arg=0x6a7ac809000) at proc.c:95
        #6  0x000006a75cf3f0cf in event_base_loop (base=0x6a7a516a000, 
flags=Variable "flags" is not available.) at /usr/src/lib/libevent/event.c:333
        #7  0x000006a4cab1e093 in proc_loop (tp=0x6a775441000, loopcb=0) at 
proc.c:202
        #8  0x000006a4caac6130 in client_main (base=0x6a7a516a000, argc=0, 
argv=0x7f7ffffd3f90, flags=402718720, feat=0) at client.c:385
        #9  0x000006a4cab3ec48 in main (argc=0, argv=0x7f7ffffd3f90) at 
tmux.c:502

>How-To-Repeat:
        1. Launch tmux
        2. Lock the tmux session using ctrl+b :lock
        3. Press ctrl+\
        4. Blindly run "pkill lock" to stop the flood of text
>Fix:
        The following patch seems to fix it. The server correctly shuts
        down if it receives a SIGQUIT while not locked, or after lock(1)
        exits if it was locked when the signal arrived, the latter being
        the same behavior as other terminating signals.

Index: proc.c
===================================================================
RCS file: /cvs/src/usr.bin/tmux/proc.c,v
retrieving revision 1.17
diff -u -p -r1.17 proc.c
--- proc.c      16 May 2020 16:07:55 -0000      1.17
+++ proc.c      3 Aug 2020 22:15:46 -0000
@@ -42,6 +42,7 @@ struct tmuxproc {
        struct event      ev_sigchld;
        struct event      ev_sigcont;
        struct event      ev_sigterm;
+       struct event      ev_sigquit;
        struct event      ev_sigusr1;
        struct event      ev_sigusr2;
        struct event      ev_sigwinch;
@@ -237,6 +238,8 @@ proc_set_signals(struct tmuxproc *tp, vo
        signal_add(&tp->ev_sigcont, NULL);
        signal_set(&tp->ev_sigterm, SIGTERM, proc_signal_cb, tp);
        signal_add(&tp->ev_sigterm, NULL);
+       signal_set(&tp->ev_sigquit, SIGQUIT, proc_signal_cb, tp);
+       signal_add(&tp->ev_sigquit, NULL);
        signal_set(&tp->ev_sigusr1, SIGUSR1, proc_signal_cb, tp);
        signal_add(&tp->ev_sigusr1, NULL);
        signal_set(&tp->ev_sigusr2, SIGUSR2, proc_signal_cb, tp);
Index: server.c
===================================================================
RCS file: /cvs/src/usr.bin/tmux/server.c,v
retrieving revision 1.194
diff -u -p -r1.194 server.c
--- server.c    18 Jun 2020 08:34:22 -0000      1.194
+++ server.c    3 Aug 2020 22:15:46 -0000
@@ -407,6 +407,7 @@ server_signal(int sig)
        switch (sig) {
        case SIGINT:
        case SIGTERM:
+       case SIGQUIT:
                server_exit = 1;
                server_send_exit();
                break;

Reply via email to