Message ID | 20240111155849.8976-1-hjl.tools@gmail.com |
---|---|
State | New |
Headers | show |
Series | x86-64: Check if mprotect works before rewriting PLT | expand |
On Thu, Jan 11, 2024 at 7:58 AM H.J. Lu <hjl.tools@gmail.com> wrote: > > Systemd execution environment configuration may prohibit changing a memory > mapping to become executable: > > MemoryDenyWriteExecute= > Takes a boolean argument. If set, attempts to create memory mappings > that are writable and executable at the same time, or to change existing > memory mappings to become executable, or mapping shared memory segments > as executable, are prohibited. > > When it is set, systemd service stops working if PLT rewrite is enabled. > Check if mprotect works before rewriting PLT. This fixes BZ #31230. > --- > .../unix/sysv/linux/x86_64/dl-plt-rewrite.h | 43 +++++++++++++++++++ > sysdeps/x86/cpu-features.c | 4 +- > sysdeps/x86_64/dl-plt-rewrite.h | 25 +++++++++++ > 3 files changed, 71 insertions(+), 1 deletion(-) > create mode 100644 sysdeps/unix/sysv/linux/x86_64/dl-plt-rewrite.h > create mode 100644 sysdeps/x86_64/dl-plt-rewrite.h > > diff --git a/sysdeps/unix/sysv/linux/x86_64/dl-plt-rewrite.h b/sysdeps/unix/sysv/linux/x86_64/dl-plt-rewrite.h > new file mode 100644 > index 0000000000..6401b7b2f2 > --- /dev/null > +++ b/sysdeps/unix/sysv/linux/x86_64/dl-plt-rewrite.h > @@ -0,0 +1,43 @@ > +/* PLT rewrite help function. Linux/x86-64 version. > + Copyright (C) 2024 Free Software Foundation, Inc. > + > + 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 > + <https://www.gnu.org/licenses/>. */ > + > +#include <stdbool.h> > +#include <sys/mman.h> > + > +static __always_inline bool > +dl_plt_rewrite_supported (void) > +{ > + /* PLT rewrite is enabled. Check if mprotect works. */ > + void *plt = (void *) INTERNAL_SYSCALL_CALL (mmap, NULL, 4096, > + PROT_READ | PROT_WRITE, > + MAP_PRIVATE | MAP_ANONYMOUS, > + -1, 0); > + if (__glibc_unlikely (plt == MAP_FAILED)) > + return false; > + > + /* Touch the PROT_READ | PROT_WRITE page. */ > + *(int32_t *) plt = 1; > + > + /* If the updated PROT_READ | PROT_WRITE page can be changed to > + PROT_EXEC | PROT_READ, rewrite PLT. */ > + bool status = (INTERNAL_SYSCALL_CALL (mprotect, plt, 4096, > + PROT_EXEC | PROT_READ) == 0); > + > + INTERNAL_SYSCALL_CALL (munmap, plt, 4096); > + > + return status; > +} > diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c > index 46bdaffbc2..6aaa750e20 100644 > --- a/sysdeps/x86/cpu-features.c > +++ b/sysdeps/x86/cpu-features.c > @@ -28,10 +28,12 @@ extern void TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *) > attribute_hidden; > > #if defined SHARED && defined __x86_64__ > +# include <dl-plt-rewrite.h> > + > static void > TUNABLE_CALLBACK (set_plt_rewrite) (tunable_val_t *valp) > { > - if (valp->numval != 0) > + if (valp->numval != 0 && dl_plt_rewrite_supported ()) > { > /* Use JMPABS only on APX processors. */ > const struct cpu_features *cpu_features = __get_cpu_features (); > diff --git a/sysdeps/x86_64/dl-plt-rewrite.h b/sysdeps/x86_64/dl-plt-rewrite.h > new file mode 100644 > index 0000000000..7eaae8f457 > --- /dev/null > +++ b/sysdeps/x86_64/dl-plt-rewrite.h > @@ -0,0 +1,25 @@ > +/* PLT rewrite help function. x86-64 version. > + Copyright (C) 2024 Free Software Foundation, Inc. > + > + 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 > + <https://www.gnu.org/licenses/>. */ > + > +#include <stdbool.h> > +#include <sys/mman.h> > + > +static __always_inline bool > +dl_plt_rewrite_supported (void) > +{ > + return true; > +} > -- > 2.43.0 > I'm in favor of this as I see little downside, but others may feel differently. Going to wait a bit to review to allow others to chime in.
On 1/11/24 10:58, H.J. Lu wrote: Looking forward to a v2 so we can resolve this for 2.39. > Systemd execution environment configuration may prohibit changing a memory > mapping to become executable: Agreed. > MemoryDenyWriteExecute= > Takes a boolean argument. If set, attempts to create memory mappings > that are writable and executable at the same time, or to change existing > memory mappings to become executable, or mapping shared memory segments > as executable, are prohibited. Does this also work for SELinux deny_execmem? What does `getsebool -a | grep deny_execmem` say? What does your patched glibc do with `semanage boolean --modify deny_execmem --on`? WARNING: Do not attempt deny_execmen on anything but a VM you can spare having crash to just a terminal. > When it is set, systemd service stops working if PLT rewrite is enabled. > Check if mprotect works before rewriting PLT. This fixes BZ #31230. > --- > .../unix/sysv/linux/x86_64/dl-plt-rewrite.h | 43 +++++++++++++++++++ > sysdeps/x86/cpu-features.c | 4 +- > sysdeps/x86_64/dl-plt-rewrite.h | 25 +++++++++++ > 3 files changed, 71 insertions(+), 1 deletion(-) > create mode 100644 sysdeps/unix/sysv/linux/x86_64/dl-plt-rewrite.h > create mode 100644 sysdeps/x86_64/dl-plt-rewrite.h > > diff --git a/sysdeps/unix/sysv/linux/x86_64/dl-plt-rewrite.h b/sysdeps/unix/sysv/linux/x86_64/dl-plt-rewrite.h > new file mode 100644 > index 0000000000..6401b7b2f2 > --- /dev/null > +++ b/sysdeps/unix/sysv/linux/x86_64/dl-plt-rewrite.h > @@ -0,0 +1,43 @@ > +/* PLT rewrite help function. Linux/x86-64 version. s/help/helper/g > + Copyright (C) 2024 Free Software Foundation, Inc. > + > + 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 > + <https://www.gnu.org/licenses/>. */ > + > +#include <stdbool.h> > +#include <sys/mman.h> > + > +static __always_inline bool > +dl_plt_rewrite_supported (void) > +{ > + /* PLT rewrite is enabled. Check if mprotect works. */ > + void *plt = (void *) INTERNAL_SYSCALL_CALL (mmap, NULL, 4096, > + PROT_READ | PROT_WRITE, > + MAP_PRIVATE | MAP_ANONYMOUS, > + -1, 0); > + if (__glibc_unlikely (plt == MAP_FAILED)) > + return false; > + > + /* Touch the PROT_READ | PROT_WRITE page. */ > + *(int32_t *) plt = 1; > + > + /* If the updated PROT_READ | PROT_WRITE page can be changed to > + PROT_EXEC | PROT_READ, rewrite PLT. */ > + bool status = (INTERNAL_SYSCALL_CALL (mprotect, plt, 4096, > + PROT_EXEC | PROT_READ) == 0); Is it specifically required that you go from RW to RWE? Could you start with just an RWE page and go to RE? > + > + INTERNAL_SYSCALL_CALL (munmap, plt, 4096); > + > + return status; > +} > diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c > index 46bdaffbc2..6aaa750e20 100644 > --- a/sysdeps/x86/cpu-features.c > +++ b/sysdeps/x86/cpu-features.c > @@ -28,10 +28,12 @@ extern void TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *) > attribute_hidden; > > #if defined SHARED && defined __x86_64__ > +# include <dl-plt-rewrite.h> > + > static void > TUNABLE_CALLBACK (set_plt_rewrite) (tunable_val_t *valp) > { > - if (valp->numval != 0) > + if (valp->numval != 0 && dl_plt_rewrite_supported ()) Suggest comment here: /* We must be careful about where we put the call to dl_plt_rewrite_supported() since it may generate spurious SELinux log entries. It should only be attempted if the user requested a PLT rewrite. */ The && short-circuit means we won't test the page support unless the tunable is non-zero. This is important because we don't want logging to SELinux or systemd for the rewrite test if the feature isn't being used. > { > /* Use JMPABS only on APX processors. */ > const struct cpu_features *cpu_features = __get_cpu_features (); > diff --git a/sysdeps/x86_64/dl-plt-rewrite.h b/sysdeps/x86_64/dl-plt-rewrite.h > new file mode 100644 > index 0000000000..7eaae8f457 > --- /dev/null > +++ b/sysdeps/x86_64/dl-plt-rewrite.h > @@ -0,0 +1,25 @@ > +/* PLT rewrite help function. x86-64 version. s/help/helper/g > + Copyright (C) 2024 Free Software Foundation, Inc. > + > + 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 > + <https://www.gnu.org/licenses/>. */ > + > +#include <stdbool.h> > +#include <sys/mman.h> > + > +static __always_inline bool > +dl_plt_rewrite_supported (void) > +{ > + return true; > +}
On Fri, Jan 12, 2024 at 9:18 AM Carlos O'Donell <carlos@redhat.com> wrote: > > On 1/11/24 10:58, H.J. Lu wrote: > > Looking forward to a v2 so we can resolve this for 2.39. > > > Systemd execution environment configuration may prohibit changing a memory > > mapping to become executable: > > Agreed. > > > MemoryDenyWriteExecute= > > Takes a boolean argument. If set, attempts to create memory mappings > > that are writable and executable at the same time, or to change existing > > memory mappings to become executable, or mapping shared memory segments > > as executable, are prohibited. > > Does this also work for SELinux deny_execmem? Yes. > What does `getsebool -a | grep deny_execmem` say? [hjl@vm-fedora-1 ~]$ getsebool -a | grep deny_execmem deny_execmem --> on [hjl@vm-fedora-1 ~]$ export GLIBC_TUNABLES=glibc.cpu.plt_rewrite=2 [hjl@vm-fedora-1 ~]$ strace ls 2>&1 | grep -E "(mprotect|mmap|munmap)" mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x556e12978000 mprotect(0x556e12978000, 4096, PROT_READ|PROT_EXEC) = -1 EACCES (Permission denied) munmap(0x556e12978000, 4096) = 0 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x556e12977000 mmap(NULL, 80651, PROT_READ, MAP_PRIVATE, 3, 0) = 0x556e12963000 mmap(NULL, 181880, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x556e12936000 mmap(0x556e1293d000, 114688, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x7000) = 0x556e1293d000 mmap(0x556e12959000, 24576, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x23000) = 0x556e12959000 mmap(0x556e1295f000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x29000) = 0x556e1295f000 mmap(0x556e12961000, 5752, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x556e12961000 mmap(NULL, 36920, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x556e1292c000 mmap(0x556e1292e000, 16384, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x556e1292e000 mmap(0x556e12932000, 8192, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x6000) = 0x556e12932000 mmap(0x556e12934000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x7000) = 0x556e12934000 mmap(NULL, 1973104, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x556e1274a000 mmap(0x556e12770000, 1441792, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x26000) = 0x556e12770000 mmap(0x556e128d0000, 319488, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x186000) = 0x556e128d0000 mmap(0x556e1291e000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1d3000) = 0x556e1291e000 mmap(0x556e12924000, 31600, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x556e12924000 mmap(NULL, 631344, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x556e126af000 mmap(0x556e126b2000, 450560, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x3000) = 0x556e126b2000 mmap(0x556e12720000, 163840, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x71000) = 0x556e12720000 mmap(0x556e12748000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x98000) = 0x556e12748000 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x556e126ad000 mprotect(0x556e1291e000, 16384, PROT_READ) = 0 mprotect(0x556e12748000, 4096, PROT_READ) = 0 mprotect(0x556e12934000, 4096, PROT_READ) = 0 mprotect(0x556e1295f000, 4096, PROT_READ) = 0 mprotect(0x556e1299b000, 8192, PROT_READ) = 0 mprotect(0x7f11917fa000, 8192, PROT_READ) = 0 munmap(0x556e12963000, 80651) = 0 mmap(NULL, 224366320, PROT_READ, MAP_PRIVATE, 3, 0) = 0x556e05000000 [hjl@vm-fedora-1 ~]$ > What does your patched glibc do with `semanage boolean --modify deny_execmem --on`? > > WARNING: Do not attempt deny_execmen on anything but a VM you can spare having crash > to just a terminal. > > > When it is set, systemd service stops working if PLT rewrite is enabled. > > Check if mprotect works before rewriting PLT. This fixes BZ #31230. > > --- > > .../unix/sysv/linux/x86_64/dl-plt-rewrite.h | 43 +++++++++++++++++++ > > sysdeps/x86/cpu-features.c | 4 +- > > sysdeps/x86_64/dl-plt-rewrite.h | 25 +++++++++++ > > 3 files changed, 71 insertions(+), 1 deletion(-) > > create mode 100644 sysdeps/unix/sysv/linux/x86_64/dl-plt-rewrite.h > > create mode 100644 sysdeps/x86_64/dl-plt-rewrite.h > > > > diff --git a/sysdeps/unix/sysv/linux/x86_64/dl-plt-rewrite.h b/sysdeps/unix/sysv/linux/x86_64/dl-plt-rewrite.h > > new file mode 100644 > > index 0000000000..6401b7b2f2 > > --- /dev/null > > +++ b/sysdeps/unix/sysv/linux/x86_64/dl-plt-rewrite.h > > @@ -0,0 +1,43 @@ > > +/* PLT rewrite help function. Linux/x86-64 version. > > s/help/helper/g Fixed. > > + Copyright (C) 2024 Free Software Foundation, Inc. > > + > > + 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 > > + <https://www.gnu.org/licenses/>. */ > > + > > +#include <stdbool.h> > > +#include <sys/mman.h> > > + > > +static __always_inline bool > > +dl_plt_rewrite_supported (void) > > +{ > > + /* PLT rewrite is enabled. Check if mprotect works. */ > > + void *plt = (void *) INTERNAL_SYSCALL_CALL (mmap, NULL, 4096, > > + PROT_READ | PROT_WRITE, > > + MAP_PRIVATE | MAP_ANONYMOUS, > > + -1, 0); > > + if (__glibc_unlikely (plt == MAP_FAILED)) > > + return false; > > + > > + /* Touch the PROT_READ | PROT_WRITE page. */ > > + *(int32_t *) plt = 1; > > + > > + /* If the updated PROT_READ | PROT_WRITE page can be changed to > > + PROT_EXEC | PROT_READ, rewrite PLT. */ > > + bool status = (INTERNAL_SYSCALL_CALL (mprotect, plt, 4096, > > + PROT_EXEC | PROT_READ) == 0); > > Is it specifically required that you go from RW to RWE? That simulates what PLT rewrite does: static inline void x86_64_rewrite_plt_in_place (struct link_map *map) { /* Adjust DT_X86_64_PLT address and DT_X86_64_PLTSZ values. */ ElfW(Addr) plt = (map->l_info[DT_X86_64 (PLT)]->d_un.d_ptr + map->l_addr); size_t pagesize = GLRO(dl_pagesize); ElfW(Addr) plt_aligned = ALIGN_DOWN (plt, pagesize); size_t pltsz = (map->l_info[DT_X86_64 (PLTSZ)]->d_un.d_val + plt - plt_aligned); if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) _dl_debug_printf ("\nchanging PLT in '%s' to writable\n", DSO_FILENAME (map->l_name)); if (__glibc_unlikely (__mprotect ((void *) plt_aligned, pltsz, PROT_WRITE | PROT_READ) < 0)) { if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) _dl_debug_printf ("\nfailed to change PLT in '%s' to writable\n", DSO_FILENAME (map->l_name)); return; } x86_64_rewrite_plt (map, plt_aligned); if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)) _dl_debug_printf ("\nchanging PLT in '%s' back to read-only\n", DSO_FILENAME (map->l_name)); if (__glibc_unlikely (__mprotect ((void *) plt_aligned, pltsz, PROT_EXEC | PROT_READ) < 0)) _dl_signal_error (0, DSO_FILENAME (map->l_name), NULL, "failed to change PLT back to read-only"); } > Could you start with just an RWE page and go to RE? I'd like to make it as close to PLT rewrite steps as possible. > > + > > + INTERNAL_SYSCALL_CALL (munmap, plt, 4096); > > + > > + return status; > > +} > > diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c > > index 46bdaffbc2..6aaa750e20 100644 > > --- a/sysdeps/x86/cpu-features.c > > +++ b/sysdeps/x86/cpu-features.c > > @@ -28,10 +28,12 @@ extern void TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *) > > attribute_hidden; > > > > #if defined SHARED && defined __x86_64__ > > +# include <dl-plt-rewrite.h> > > + > > static void > > TUNABLE_CALLBACK (set_plt_rewrite) (tunable_val_t *valp) > > { > > - if (valp->numval != 0) > > + if (valp->numval != 0 && dl_plt_rewrite_supported ()) > > Suggest comment here: > > /* We must be careful about where we put the call to > dl_plt_rewrite_supported() since it may generate > spurious SELinux log entries. It should only be > attempted if the user requested a PLT rewrite. */ Fixed. > The && short-circuit means we won't test the page support unless the tunable > is non-zero. This is important because we don't want logging to SELinux or > systemd for the rewrite test if the feature isn't being used. > > > { > > /* Use JMPABS only on APX processors. */ > > const struct cpu_features *cpu_features = __get_cpu_features (); > > diff --git a/sysdeps/x86_64/dl-plt-rewrite.h b/sysdeps/x86_64/dl-plt-rewrite.h > > new file mode 100644 > > index 0000000000..7eaae8f457 > > --- /dev/null > > +++ b/sysdeps/x86_64/dl-plt-rewrite.h > > @@ -0,0 +1,25 @@ > > +/* PLT rewrite help function. x86-64 version. > > s/help/helper/g Fixed. > > + Copyright (C) 2024 Free Software Foundation, Inc. > > + > > + 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 > > + <https://www.gnu.org/licenses/>. */ > > + > > +#include <stdbool.h> > > +#include <sys/mman.h> > > + > > +static __always_inline bool > > +dl_plt_rewrite_supported (void) > > +{ > > + return true; > > +} > > -- > Cheers, > Carlos. > Will send the v2 shortly. Thanks.
On Fri, Jan 12, 2024 at 10:09 AM H.J. Lu <hjl.tools@gmail.com> wrote: > > Will send the v2 shortly. Here it is: https://patchwork.sourceware.org/project/glibc/list/?series=29649
diff --git a/sysdeps/unix/sysv/linux/x86_64/dl-plt-rewrite.h b/sysdeps/unix/sysv/linux/x86_64/dl-plt-rewrite.h new file mode 100644 index 0000000000..6401b7b2f2 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86_64/dl-plt-rewrite.h @@ -0,0 +1,43 @@ +/* PLT rewrite help function. Linux/x86-64 version. + Copyright (C) 2024 Free Software Foundation, Inc. + + 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 + <https://www.gnu.org/licenses/>. */ + +#include <stdbool.h> +#include <sys/mman.h> + +static __always_inline bool +dl_plt_rewrite_supported (void) +{ + /* PLT rewrite is enabled. Check if mprotect works. */ + void *plt = (void *) INTERNAL_SYSCALL_CALL (mmap, NULL, 4096, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); + if (__glibc_unlikely (plt == MAP_FAILED)) + return false; + + /* Touch the PROT_READ | PROT_WRITE page. */ + *(int32_t *) plt = 1; + + /* If the updated PROT_READ | PROT_WRITE page can be changed to + PROT_EXEC | PROT_READ, rewrite PLT. */ + bool status = (INTERNAL_SYSCALL_CALL (mprotect, plt, 4096, + PROT_EXEC | PROT_READ) == 0); + + INTERNAL_SYSCALL_CALL (munmap, plt, 4096); + + return status; +} diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c index 46bdaffbc2..6aaa750e20 100644 --- a/sysdeps/x86/cpu-features.c +++ b/sysdeps/x86/cpu-features.c @@ -28,10 +28,12 @@ extern void TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *) attribute_hidden; #if defined SHARED && defined __x86_64__ +# include <dl-plt-rewrite.h> + static void TUNABLE_CALLBACK (set_plt_rewrite) (tunable_val_t *valp) { - if (valp->numval != 0) + if (valp->numval != 0 && dl_plt_rewrite_supported ()) { /* Use JMPABS only on APX processors. */ const struct cpu_features *cpu_features = __get_cpu_features (); diff --git a/sysdeps/x86_64/dl-plt-rewrite.h b/sysdeps/x86_64/dl-plt-rewrite.h new file mode 100644 index 0000000000..7eaae8f457 --- /dev/null +++ b/sysdeps/x86_64/dl-plt-rewrite.h @@ -0,0 +1,25 @@ +/* PLT rewrite help function. x86-64 version. + Copyright (C) 2024 Free Software Foundation, Inc. + + 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 + <https://www.gnu.org/licenses/>. */ + +#include <stdbool.h> +#include <sys/mman.h> + +static __always_inline bool +dl_plt_rewrite_supported (void) +{ + return true; +}