mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 12:30:06 +00:00
x32: Handle displacement overflow in PLT rewrite [BZ #31218]
PLT rewrite calculated displacement with ElfW(Addr) disp = value - branch_start - JMP32_INSN_SIZE; On x32, displacement from 0xf7fbe060 to 0x401030 was calculated as unsigned int disp = 0x401030 - 0xf7fbe060 - 5; with disp == 0x8442fcb and caused displacement overflow. The PLT entry was changed to: 0xf7fbe060 <+0>: e9 cb 2f 44 08 jmp 0x401030 0xf7fbe065 <+5>: cc int3 0xf7fbe066 <+6>: cc int3 0xf7fbe067 <+7>: cc int3 0xf7fbe068 <+8>: cc int3 0xf7fbe069 <+9>: cc int3 0xf7fbe06a <+10>: cc int3 0xf7fbe06b <+11>: cc int3 0xf7fbe06c <+12>: cc int3 0xf7fbe06d <+13>: cc int3 0xf7fbe06e <+14>: cc int3 0xf7fbe06f <+15>: cc int3 x32 has 32-bit address range, but it doesn't wrap address around at 4GB, JMP target was changed to 0x100401030 (0xf7fbe060LL + 0x8442fcbLL + 5), which is above 4GB. Always use uint64_t to calculate displacement. This fixes BZ #31218. Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>
This commit is contained in:
parent
b96a2eba2f
commit
0f9afc265a
@ -186,9 +186,11 @@ endif
|
||||
ifeq (yes,$(have-z-mark-plt))
|
||||
tests += \
|
||||
tst-plt-rewrite1 \
|
||||
tst-plt-rewrite2 \
|
||||
# tests
|
||||
modules-names += \
|
||||
tst-plt-rewritemod1 \
|
||||
tst-plt-rewritemod2 \
|
||||
# modules-names
|
||||
|
||||
tst-plt-rewrite1-no-pie = yes
|
||||
@ -200,6 +202,12 @@ $(objpfx)tst-plt-rewrite1.out: /dev/null $(objpfx)tst-plt-rewrite1
|
||||
$(tst-plt-rewrite1-ENV) $(make-test-out) > $@ 2>&1; \
|
||||
grep -q -E "changing 'bar' PLT entry in .*/elf/tst-plt-rewritemod1.so' to direct branch" $@; \
|
||||
$(evaluate-test)
|
||||
|
||||
tst-plt-rewrite2-no-pie = yes
|
||||
LDFLAGS-tst-plt-rewrite2 = -Wl,-z,now
|
||||
LDFLAGS-tst-plt-rewritemod2.so = -Wl,-z,now,-z,undefs
|
||||
tst-plt-rewrite2-ENV = GLIBC_TUNABLES=glibc.cpu.plt_rewrite=2
|
||||
$(objpfx)tst-plt-rewrite2: $(objpfx)tst-plt-rewritemod2.so
|
||||
endif
|
||||
|
||||
endif # $(subdir) == elf
|
||||
|
@ -607,8 +607,9 @@ x86_64_rewrite_plt (struct link_map *map, ElfW(Addr) plt_rewrite)
|
||||
/* Skip ENDBR64 if IBT isn't enabled. */
|
||||
if (!ibt_enabled_p)
|
||||
branch_start = ALIGN_DOWN (branch_start, pltent);
|
||||
/* Get the displacement from the branch target. */
|
||||
ElfW(Addr) disp = value - branch_start - JMP32_INSN_SIZE;
|
||||
/* Get the displacement from the branch target. NB: We must use
|
||||
64-bit integer on x32 to avoid overflow. */
|
||||
uint64_t disp = (uint64_t) value - branch_start - JMP32_INSN_SIZE;
|
||||
ElfW(Addr) plt_end;
|
||||
ElfW(Addr) pad;
|
||||
|
||||
|
46
sysdeps/x86_64/tst-plt-rewrite2.c
Normal file
46
sysdeps/x86_64/tst-plt-rewrite2.c
Normal file
@ -0,0 +1,46 @@
|
||||
/* Test PLT rewrite with 32-bit displacement overflow.
|
||||
Copyright (C) 2024 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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
#include <support/check.h>
|
||||
|
||||
extern int (*func_p) (void);
|
||||
extern void foo (void);
|
||||
|
||||
int
|
||||
func (void)
|
||||
{
|
||||
return 0xbadbeef;
|
||||
}
|
||||
|
||||
void
|
||||
bar (void)
|
||||
{
|
||||
TEST_VERIFY (func_p == &func);
|
||||
TEST_VERIFY (func_p () == 0xbadbeef);
|
||||
}
|
||||
|
||||
static int
|
||||
do_test (void)
|
||||
{
|
||||
func_p = &func;
|
||||
foo ();
|
||||
bar ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include <support/test-driver.c>
|
32
sysdeps/x86_64/tst-plt-rewritemod2.c
Normal file
32
sysdeps/x86_64/tst-plt-rewritemod2.c
Normal file
@ -0,0 +1,32 @@
|
||||
/* Check PLT rewrite with 32-bit displacement overflow.
|
||||
Copyright (C) 2024 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
|
||||
<https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* foo calls func with indirect branch via PLT. PLT rewrite shouldn't
|
||||
change it to direct branch if func is too far way. */
|
||||
|
||||
#include <support/check.h>
|
||||
|
||||
int (*func_p) (void);
|
||||
extern int func (void);
|
||||
|
||||
void
|
||||
foo (void)
|
||||
{
|
||||
TEST_VERIFY (func () == 0xbadbeef);
|
||||
TEST_VERIFY (func_p () == 0xbadbeef);
|
||||
}
|
Loading…
Reference in New Issue
Block a user