diff --git a/include/setjmp.h b/include/setjmp.h index d2353be71b..4997d0d7d2 100644 --- a/include/setjmp.h +++ b/include/setjmp.h @@ -12,7 +12,7 @@ extern void ____longjmp_chk (__jmp_buf __env, int __val) __attribute__ ((__noreturn__)) attribute_hidden; extern void __longjmp_chk (sigjmp_buf env, int val) - __attribute__ ((noreturn)) attribute_hidden; + __attribute__ ((noreturn)); /* The redirection in the installed header does not work with libc_hidden_proto. */ #define longjmp __longjmp_chk diff --git a/nptl/tst-guard1.c b/nptl/tst-guard1.c index e3e06df0fc..6732b09017 100644 --- a/nptl/tst-guard1.c +++ b/nptl/tst-guard1.c @@ -26,54 +26,22 @@ #include #include #include +#include #include #include static long int pagesz; -/* To check if the guard region is inaccessible, the thread tries read/writes - on it and checks if a SIGSEGV is generated. */ - -static volatile sig_atomic_t signal_jump_set; -static sigjmp_buf signal_jmp_buf; - -static void -sigsegv_handler (int sig) -{ - if (signal_jump_set == 0) - return; - - siglongjmp (signal_jmp_buf, sig); -} - -static bool -try_access_buf (char *ptr, bool write) -{ - signal_jump_set = true; - - bool failed = sigsetjmp (signal_jmp_buf, 0) != 0; - if (!failed) - { - if (write) - *(volatile char *)(ptr) = 'x'; - else - *(volatile char *)(ptr); - } - - signal_jump_set = false; - return !failed; -} - static bool try_read_buf (char *ptr) { - return try_access_buf (ptr, false); + return check_mem_access (ptr, false); } static bool try_write_buf (char *ptr) { - return try_access_buf (ptr, true); + return check_mem_access (ptr, true); } static bool @@ -332,18 +300,6 @@ do_test (void) { pagesz = sysconf (_SC_PAGESIZE); - { - struct sigaction sa = { - .sa_handler = sigsegv_handler, - .sa_flags = SA_NODEFER, - }; - sigemptyset (&sa.sa_mask); - xsigaction (SIGSEGV, &sa, NULL); - /* Some system generates SIGBUS accessing the guard area when it is - setup with madvise. */ - xsigaction (SIGBUS, &sa, NULL); - } - static const struct { const char *descr; void (*test)(void); diff --git a/support/Makefile b/support/Makefile index f67f38130a..f0a1e1ca44 100644 --- a/support/Makefile +++ b/support/Makefile @@ -66,6 +66,7 @@ libsupport-routines = \ support_format_netent \ support_fuse \ support_isolate_in_subprocess \ + support_mem_access \ support_mutex_pi_monotonic \ support_need_proc \ support_open_and_compare_file_bytes \ diff --git a/support/check_mem_access.h b/support/check_mem_access.h new file mode 100644 index 0000000000..116e1f7c8a --- /dev/null +++ b/support/check_mem_access.h @@ -0,0 +1,36 @@ +/* Test verification functions for memory access checks. + Copyright (C) 2025 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef SUPPORT_CHECK_MEM_ACCESS_H +#define SUPPORT_CHECK_MEM_ACCESS_H + +#include + +__BEGIN_DECLS + +/* To check if the a memory region is inaccessible, this function tries + read / write on the provided address ADDR and checks if a SIGSEGV is + generated. This function is not thread-safe and it changes signal + handlers for SIGSEGV and SIGBUS. + If WRITE is true, only the write operation is checked, otherwise only + the read operation is checked. */ +bool check_mem_access (const void *addr, bool write); + +__END_DECLS + +#endif // SUPPORT_CHECK_MEM_ACCESS_H diff --git a/support/support_mem_access.c b/support/support_mem_access.c new file mode 100644 index 0000000000..aa5127b41f --- /dev/null +++ b/support/support_mem_access.c @@ -0,0 +1,61 @@ +/* Implementation of the test verification functions for memory access + checks. + Copyright (C) 2025 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +static sigjmp_buf sigsegv_jmp_buf; + +static void +__sigsegv_handler (int signum) +{ + siglongjmp (sigsegv_jmp_buf, signum); +} + +bool check_mem_access (const void *addr, bool write) +{ + /* This is obviously not thread-safe. */ + static bool handler_set_up; + if (!handler_set_up) + { + struct sigaction sa = { + .sa_handler = __sigsegv_handler, + .sa_flags = SA_NODEFER, + }; + sigemptyset (&sa.sa_mask); + xsigaction (SIGSEGV, &sa, NULL); + /* Some system generates SIGBUS accessing the guard area when it is + setup with madvise. */ + xsigaction (SIGBUS, &sa, NULL); + handler_set_up = true; + } + int r = sigsetjmp (sigsegv_jmp_buf, 0); + if (r == 0) + { + if (write) + *(volatile char *)addr = 'x'; + else + *(volatile char *)addr; + return true; + } + if (r == SIGSEGV || r == SIGBUS) + return false; + return true; +}