Created attachment 132811 [details] [PATCH] Handle signals in epoll_pwait and io_uring_enter SUMMARY I found a couple problems related to signals and the io_uring_enter syscall. First, inside a blocked io_uring_enter#, the traced process will not receive any signals (they remain blocked by Valgrind's internal signal-handling logic). Second, it's possible to crash Valgrind by unblocking signals using the "sig" parameter to io_uring_enter and then sending those signals, as demonstrated below. STEPS TO REPRODUCE cat > valgrind_repro_1.c <<'EOF' #include <stdlib.h> #include <unistd.h> #include <err.h> #include <signal.h> #include <sys/syscall.h> #include <linux/io_uring.h> int main() { struct io_uring_params p = { 0 }; int fd = syscall(SYS_io_uring_setup, 1, &p); if (fd < 0) err(EXIT_FAILURE, "io_uring_setup"); syscall(SYS_io_uring_enter, fd, 0, 1, IORING_ENTER_GETEVENTS, NULL, _NSIG / 8); for (;;); } EOF cat > valgrind_repro_2.c <<'EOF' #include <stdlib.h> #include <unistd.h> #include <err.h> #include <signal.h> #include <sys/syscall.h> #include <linux/io_uring.h> int main() { sigset_t oldmask; struct io_uring_params p = { 0 }; int fd = syscall(SYS_io_uring_setup, 1, &p); if (fd < 0) err(EXIT_FAILURE, "io_uring_setup"); if (sigprocmask(SIG_BLOCK, NULL, &oldmask)) err(EXIT_FAILURE, "sigprocmask"); syscall(SYS_io_uring_enter, fd, 0, 1, IORING_ENTER_GETEVENTS, &oldmask, _NSIG / 8); for (;;); } EOF gcc -o valgrind-repro-1 valgrind-repro-1.c gcc -o valgrind-repro-2 valgrind-repro-2.c OBSERVED RESULT > uname -a Linux linux 5.7.11-100.fc31.x86_64 #1 SMP Wed Jul 29 18:17:53 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux > valgrind --version valgrind-3.16.0 > valgrind ./valgrind_repro_1 ==64542== Memcheck, a memory error detector ==64542== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==64542== Using Valgrind-3.16.0-bf5e647edb-20200519X and LibVEX; rerun with -h for copyright info ==64542== Command: ./valgrind_repro_1 ==64542== --64542-- Valgrind options: --64542-- -v --64542-- Contents of /proc/version: --64542-- Linux version 5.7.11-100.fc31.x86_64 (mockbuild@bkernel01.iad2.fedoraproject.org) (gcc version 9.3.1 20200408 (Red Hat 9.3.1-2) (GCC), GNU ld version 2.32-31.fc31) #1 SMP Wed Jul 29 18:17:53 UTC 2020 --64542-- --64542-- Arch and hwcaps: AMD64, LittleEndian, amd64-cx16-lzcnt-rdtscp-sse3-ssse3-avx-avx2-bmi-f16c-rdrand --64542-- Page sizes: currently 4096, max supported 4096 --64542-- Valgrind library directory: /usr/libexec/valgrind --64542-- Reading syms from /home/andrewsoutar/src/misc/valgrind_repro_1 --64542-- Reading syms from /usr/lib64/ld-2.30.so --64542-- Reading syms from /usr/libexec/valgrind/memcheck-amd64-linux --64542-- object doesn't have a symbol table --64542-- object doesn't have a dynamic symbol table --64542-- Scheduler: using generic scheduler lock implementation. --64542-- Reading suppressions file: /usr/libexec/valgrind/default.supp ==64542== embedded gdbserver: reading from /tmp/vgdb-pipe-from-vgdb-to-64542-by-andrewsoutar-on-linux ==64542== embedded gdbserver: writing to /tmp/vgdb-pipe-to-vgdb-from-64542-by-andrewsoutar-on-linux ==64542== embedded gdbserver: shared mem /tmp/vgdb-pipe-shared-mem-vgdb-64542-by-andrewsoutar-on-linux ==64542== ==64542== TO CONTROL THIS PROCESS USING vgdb (which you probably ==64542== don't want to do, unless you know exactly what you're doing, ==64542== or are doing some strange experiment): ==64542== /usr/libexec/valgrind/../../bin/vgdb --pid=64542 ...command... ==64542== ==64542== TO DEBUG THIS PROCESS USING GDB: start GDB like this ==64542== /path/to/gdb ./valgrind_repro_1 ==64542== and then give GDB the following command ==64542== target remote | /usr/libexec/valgrind/../../bin/vgdb --pid=64542 ==64542== --pid is optional if only one valgrind process is running ==64542== --64542-- REDIR: 0x4021350 (ld-linux-x86-64.so.2:strlen) redirected to 0x580ccdd2 (???) --64542-- REDIR: 0x4021120 (ld-linux-x86-64.so.2:index) redirected to 0x580ccdec (???) --64542-- Reading syms from /usr/libexec/valgrind/vgpreload_core-amd64-linux.so --64542-- Reading syms from /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so ==64542== WARNING: new redirection conflicts with existing -- ignoring it --64542-- old: 0x04021350 (strlen ) R-> (0000.0) 0x580ccdd2 ??? --64542-- new: 0x04021350 (strlen ) R-> (2007.0) 0x0483cd00 strlen --64542-- REDIR: 0x401db30 (ld-linux-x86-64.so.2:strcmp) redirected to 0x483dc70 (strcmp) --64542-- REDIR: 0x40218b0 (ld-linux-x86-64.so.2:mempcpy) redirected to 0x4841790 (mempcpy) --64542-- Reading syms from /usr/lib64/libc-2.30.so --64542-- REDIR: 0x4902000 (libc.so.6:memmove) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x4901380 (libc.so.6:strncpy) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x4902330 (libc.so.6:strcasecmp) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x4900ca0 (libc.so.6:strcat) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x49013e0 (libc.so.6:rindex) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x49036d0 (libc.so.6:rawmemchr) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x491bbf0 (libc.so.6:wmemchr) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x491b730 (libc.so.6:wcscmp) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x4902160 (libc.so.6:mempcpy) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x4901f90 (libc.so.6:bcmp) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x4901310 (libc.so.6:strncmp) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x4900d50 (libc.so.6:strcmp) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x49020c0 (libc.so.6:memset) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x491b6f0 (libc.so.6:wcschr) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x4901270 (libc.so.6:strnlen) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x4900e30 (libc.so.6:strcspn) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x4902380 (libc.so.6:strncasecmp) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x4900dd0 (libc.so.6:strcpy) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x49024d0 (libc.so.6:memcpy@@GLIBC_2.14) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x491ce40 (libc.so.6:wcsnlen) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x491b770 (libc.so.6:wcscpy) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x4901420 (libc.so.6:strpbrk) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x4900d00 (libc.so.6:index) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x4901230 (libc.so.6:strlen) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x4907b50 (libc.so.6:memrchr) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x49023d0 (libc.so.6:strcasecmp_l) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x4901f50 (libc.so.6:memchr) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x491b840 (libc.so.6:wcslen) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x49016e0 (libc.so.6:strspn) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x49022d0 (libc.so.6:stpncpy) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x4902270 (libc.so.6:stpcpy) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x4903710 (libc.so.6:strchrnul) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x4902420 (libc.so.6:strncasecmp_l) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64542-- REDIR: 0x49d2740 (libc.so.6:__strrchr_avx2) redirected to 0x483c6b0 (rindex) ^C^C^C [process does not terminate] > valgrind -v ./valgrind_repro_2 ==64546== Memcheck, a memory error detector ==64546== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==64546== Using Valgrind-3.16.0-bf5e647edb-20200519X and LibVEX; rerun with -h for copyright info ==64546== Command: ./valgrind_repro_2 ==64546== --64546-- Valgrind options: --64546-- -v --64546-- Contents of /proc/version: --64546-- Linux version 5.7.11-100.fc31.x86_64 (mockbuild@bkernel01.iad2.fedoraproject.org) (gcc version 9.3.1 20200408 (Red Hat 9.3.1-2) (GCC), GNU ld version 2.32-31.fc31) #1 SMP Wed Jul 29 18:17:53 UTC 2020 --64546-- --64546-- Arch and hwcaps: AMD64, LittleEndian, amd64-cx16-lzcnt-rdtscp-sse3-ssse3-avx-avx2-bmi-f16c-rdrand --64546-- Page sizes: currently 4096, max supported 4096 --64546-- Valgrind library directory: /usr/libexec/valgrind --64546-- Reading syms from /home/andrewsoutar/src/misc/valgrind_repro_2 --64546-- Reading syms from /usr/lib64/ld-2.30.so --64546-- Reading syms from /usr/libexec/valgrind/memcheck-amd64-linux --64546-- object doesn't have a symbol table --64546-- object doesn't have a dynamic symbol table --64546-- Scheduler: using generic scheduler lock implementation. --64546-- Reading suppressions file: /usr/libexec/valgrind/default.supp ==64546== embedded gdbserver: reading from /tmp/vgdb-pipe-from-vgdb-to-64546-by-andrewsoutar-on-linux ==64546== embedded gdbserver: writing to /tmp/vgdb-pipe-to-vgdb-from-64546-by-andrewsoutar-on-linux ==64546== embedded gdbserver: shared mem /tmp/vgdb-pipe-shared-mem-vgdb-64546-by-andrewsoutar-on-linux ==64546== ==64546== TO CONTROL THIS PROCESS USING vgdb (which you probably ==64546== don't want to do, unless you know exactly what you're doing, ==64546== or are doing some strange experiment): ==64546== /usr/libexec/valgrind/../../bin/vgdb --pid=64546 ...command... ==64546== ==64546== TO DEBUG THIS PROCESS USING GDB: start GDB like this ==64546== /path/to/gdb ./valgrind_repro_2 ==64546== and then give GDB the following command ==64546== target remote | /usr/libexec/valgrind/../../bin/vgdb --pid=64546 ==64546== --pid is optional if only one valgrind process is running ==64546== --64546-- REDIR: 0x4021350 (ld-linux-x86-64.so.2:strlen) redirected to 0x580ccdd2 (???) --64546-- REDIR: 0x4021120 (ld-linux-x86-64.so.2:index) redirected to 0x580ccdec (???) --64546-- Reading syms from /usr/libexec/valgrind/vgpreload_core-amd64-linux.so --64546-- Reading syms from /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so ==64546== WARNING: new redirection conflicts with existing -- ignoring it --64546-- old: 0x04021350 (strlen ) R-> (0000.0) 0x580ccdd2 ??? --64546-- new: 0x04021350 (strlen ) R-> (2007.0) 0x0483cd00 strlen --64546-- REDIR: 0x401db30 (ld-linux-x86-64.so.2:strcmp) redirected to 0x483dc70 (strcmp) --64546-- REDIR: 0x40218b0 (ld-linux-x86-64.so.2:mempcpy) redirected to 0x4841790 (mempcpy) --64546-- Reading syms from /usr/lib64/libc-2.30.so --64546-- REDIR: 0x4902000 (libc.so.6:memmove) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x4901380 (libc.so.6:strncpy) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x4902330 (libc.so.6:strcasecmp) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x4900ca0 (libc.so.6:strcat) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x49013e0 (libc.so.6:rindex) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x49036d0 (libc.so.6:rawmemchr) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x491bbf0 (libc.so.6:wmemchr) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x491b730 (libc.so.6:wcscmp) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x4902160 (libc.so.6:mempcpy) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x4901f90 (libc.so.6:bcmp) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x4901310 (libc.so.6:strncmp) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x4900d50 (libc.so.6:strcmp) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x49020c0 (libc.so.6:memset) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x491b6f0 (libc.so.6:wcschr) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x4901270 (libc.so.6:strnlen) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x4900e30 (libc.so.6:strcspn) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x4902380 (libc.so.6:strncasecmp) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x4900dd0 (libc.so.6:strcpy) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x49024d0 (libc.so.6:memcpy@@GLIBC_2.14) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x491ce40 (libc.so.6:wcsnlen) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x491b770 (libc.so.6:wcscpy) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x4901420 (libc.so.6:strpbrk) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x4900d00 (libc.so.6:index) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x4901230 (libc.so.6:strlen) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x4907b50 (libc.so.6:memrchr) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x49023d0 (libc.so.6:strcasecmp_l) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x4901f50 (libc.so.6:memchr) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x491b840 (libc.so.6:wcslen) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x49016e0 (libc.so.6:strspn) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x49022d0 (libc.so.6:stpncpy) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x4902270 (libc.so.6:stpcpy) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x4903710 (libc.so.6:strchrnul) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x4902420 (libc.so.6:strncasecmp_l) redirected to 0x482f1e1 (_vgnU_ifunc_wrapper) --64546-- REDIR: 0x49d2740 (libc.so.6:__strrchr_avx2) redirected to 0x483c6b0 (rindex) ^C valgrind: m_signals.c:2446 (async_signalhandler): Assertion 'tst->status == VgTs_WaitSys' failed. host stacktrace: ==64546== at 0x580480CA: ??? (in /usr/libexec/valgrind/memcheck-amd64-linux) ==64546== by 0x580481F7: ??? (in /usr/libexec/valgrind/memcheck-amd64-linux) ==64546== by 0x5804839B: ??? (in /usr/libexec/valgrind/memcheck-amd64-linux) ==64546== by 0x5805B674: ??? (in /usr/libexec/valgrind/memcheck-amd64-linux) ==64546== by 0x5805962F: ??? (in /usr/libexec/valgrind/memcheck-amd64-linux) ==64546== by 0x6: ??? sched status: running_tid=1 Thread 1: status = VgTs_Runnable syscall 426 (lwpid 64546) ==64546== at 0x496D1DD: syscall (in /usr/lib64/libc-2.30.so) ==64546== by 0x401207: main (in /home/andrewsoutar/src/misc/valgrind_repro_2) client stack range: [0x1FFEFFD000 0x1FFF000FFF] client SP: 0x1FFEFFF418 valgrind stack range: [0x1002AA6000 0x1002BA5FFF] top usage: 7464 of 1048576 Note: see also the FAQ in the source distribution. It contains workarounds to several common problems. In particular, if Valgrind aborted or crashed after identifying problems in your program, there's a good chance that fixing those problems will prevent Valgrind aborting or crashing, especially if it happened in m_mallocfree.c. If that doesn't help, please report this bug to: www.valgrind.org In the bug report, send all the above text, the valgrind version, and what OS and version you are using. Thanks. EXPECTED RESULT > valgrind ./valgrind_repro_1 ==64252== Memcheck, a memory error detector ==64252== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==64252== Using Valgrind-3.17.0.GIT and LibVEX; rerun with -h for copyright info ==64252== Command: ./valgrind_repro_1 ==64252== ^C==64252== ==64252== Process terminating with default action of signal 2 (SIGINT) ==64252== at 0x496C1DD: syscall (in /usr/lib64/libc-2.30.so) ==64252== by 0x4011B9: main (in /home/andrewsoutar/src/misc/valgrind_repro_1) ==64252== ==64252== HEAP SUMMARY: ==64252== in use at exit: 0 bytes in 0 blocks ==64252== total heap usage: 0 allocs, 0 frees, 0 bytes allocated ==64252== ==64252== All heap blocks were freed -- no leaks are possible ==64252== ==64252== For lists of detected and suppressed errors, rerun with: -s ==64252== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) > valgrind ./valgrind_repro_2 ==64291== Memcheck, a memory error detector ==64291== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al. ==64291== Using Valgrind-3.17.0.GIT and LibVEX; rerun with -h for copyright info ==64291== Command: ./valgrind_repro_2 ==64291== ^C==64291== ==64291== Process terminating with default action of signal 2 (SIGINT) ==64291== at 0x496C1DD: syscall (in /usr/lib64/libc-2.30.so) ==64291== by 0x401207: main (in /home/andrewsoutar/src/misc/valgrind_repro_2) ==64291== ==64291== HEAP SUMMARY: ==64291== in use at exit: 0 bytes in 0 blocks ==64291== total heap usage: 0 allocs, 0 frees, 0 bytes allocated ==64291== ==64291== All heap blocks were freed -- no leaks are possible ==64291== ==64291== For lists of detected and suppressed errors, rerun with: -s ==64291== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) SOFTWARE/OS VERSIONS Fedora 31 Linux linux 5.7.11-100.fc31.x86_64 #1 SMP Wed Jul 29 18:17:53 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux valgrind-3.16.0 (for some reason 3.15-SVN is the latest version available in the version field) ADDITIONAL INFORMATION I've attached a patch against master that fixes the issue for me, as well as making sure SIGVGKILL etc. don't get blocked by io_uring_enter and epoll_pwait. It basically just uses logic factored out of the ppoll syswrap, so there may be a better way to do this.
commit c49efc1cff161a8cfa741900c262f5b1c03f82b3 (HEAD -> master, origin/master, origin/HEAD) Author: Paul Floyd <pjfloyd@wanadoo.fr> Date: Sat Nov 18 13:02:30 2023 +0100 Bug 428364 - Signals inside io_uring_enter not handled Patch provide by Andrew Soutar kdebugtraq@andrewsoutar.com Thanks! I haven't added the reproducers as they require interrupting the Valgrind process. Maybe the tests can be adapted to use fork and have the parent kill the child running io_uring.