linux/arch/um/os-Linux
Johannes Berg 42b15c72db um: time-travel: fix signal blocking race/hang
[ Upstream commit 2cf3a3c4b8 ]

When signals are hard-blocked in order to do time-travel
socket processing, we set signals_blocked and then handle
SIGIO signals by setting the SIGIO bit in signals_pending.
When unblocking, we first set signals_blocked to 0, and
then handle all pending signals. We have to set it first,
so that we can again properly block/unblock inside the
unblock, if the time-travel handlers need to be processed.

Unfortunately, this is racy. We can get into this situation:

// signals_pending = SIGIO_MASK

unblock_signals_hard()
   signals_blocked = 0;
   if (signals_pending && signals_enabled) {
     block_signals();
     unblock_signals()
       ...
       sig_handler_common(SIGIO, NULL, NULL);
         sigio_handler()
           ...
           sigio_reg_handler()
             irq_do_timetravel_handler()
               reg->timetravel_handler() ==
               vu_req_interrupt_comm_handler()
                 vu_req_read_message()
                   vhost_user_recv_req()
                     vhost_user_recv()
                       vhost_user_recv_header()
                         // reads 12 bytes header of
                         // 20 bytes message
<-- receive SIGIO here <--
sig_handler()
   int enabled = signals_enabled; // 1
   if ((signals_blocked || !enabled) && (sig == SIGIO)) {
     if (!signals_blocked && time_travel_mode == TT_MODE_EXTERNAL)
       sigio_run_timetravel_handlers()
         _sigio_handler()
           sigio_reg_handler()
             ... as above ...
               vhost_user_recv_header()
                 // reads 8 bytes that were message payload
                 // as if it were header - but aborts since
                 // it then gets -EAGAIN
...
--> end signal handler -->
                       // continue in vhost_user_recv()
                       // full_read() for 8 bytes payload busy loops
                       // entire process hangs here

Conceptually, to fix this, we need to ensure that the
signal handler cannot run while we hard-unblock signals.
The thing that makes this more complex is that we can be
doing hard-block/unblock while unblocking. Introduce a
new signals_blocked_pending variable that we can keep at
non-zero as long as pending signals are being processed,
then we only need to ensure it's decremented safely and
the signal handler will only increment it if it's already
non-zero (or signals_blocked is set, of course.)

Note also that only the outermost call to hard-unblock is
allowed to decrement signals_blocked_pending, since it
could otherwise reach zero in an inner call, and leave
the same race happening if the timetravel_handler loops,
but that's basically required of it.

Fixes: d6b399a0e0 ("um: time-travel/signals: fix ndelay() in interrupt")
Link: https://patch.msgid.link/20240703110144.28034-2-johannes@sipsolutions.net
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
2024-08-03 09:01:00 +02:00
..
drivers um: Make local functions and variables static 2024-04-22 21:43:03 +02:00
skas um: Add an internal header shared among the user code 2024-04-30 14:16:44 +02:00
elf_aux.c um: Add an internal header shared among the user code 2024-04-30 14:16:44 +02:00
execvp.c um: Allow builds with Clang 2022-03-21 08:13:03 -07:00
file.c um: Fix WRITE_ZEROES in the UBD Driver 2022-03-11 10:46:34 +01:00
helper.c um: Fix naming clash between UML and scheduler 2024-01-04 21:22:27 +01:00
internal.h um: Add an internal header shared among the user code 2024-04-30 14:16:44 +02:00
irq.c um: Remove the unneeded result variable 2023-02-01 22:11:24 +01:00
main.c um: Add an internal header shared among the user code 2024-04-30 14:16:44 +02:00
Makefile kbuild: remove --include-dir MAKEFLAG from top Makefile 2023-02-05 18:51:22 +09:00
mem.c um: Add an internal header shared among the user code 2024-04-30 14:16:44 +02:00
process.c um: Add SPDX headers for files in arch/um/os-Linux 2019-09-15 21:37:17 +02:00
registers.c um: Remove unused register save/restore functions 2024-01-05 16:28:57 +01:00
sigio.c Revert "um: Use swap() to make code cleaner" 2023-07-27 13:07:03 -07:00
signal.c um: time-travel: fix signal blocking race/hang 2024-08-03 09:01:00 +02:00
start_up.c um: Add an internal header shared among the user code 2024-04-30 14:16:44 +02:00
time.c um: Remove unused timeval_to_ns() function 2022-03-11 10:49:50 +01:00
tty.c um: Add SPDX headers for files in arch/um/os-Linux 2019-09-15 21:37:17 +02:00
umid.c um: Convert strscpy() usage to 2-argument style 2024-02-20 20:47:32 -08:00
user_syms.c Revert "[PATCH] uml: export symbols added by GCC hardened" 2023-06-15 04:47:04 +09:00
util.c um: Don't use vfprintf() for os_info() 2024-01-04 23:45:17 +01:00