mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-24 22:10:13 +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))
|
ifeq (yes,$(have-z-mark-plt))
|
||||||
tests += \
|
tests += \
|
||||||
tst-plt-rewrite1 \
|
tst-plt-rewrite1 \
|
||||||
|
tst-plt-rewrite2 \
|
||||||
# tests
|
# tests
|
||||||
modules-names += \
|
modules-names += \
|
||||||
tst-plt-rewritemod1 \
|
tst-plt-rewritemod1 \
|
||||||
|
tst-plt-rewritemod2 \
|
||||||
# modules-names
|
# modules-names
|
||||||
|
|
||||||
tst-plt-rewrite1-no-pie = yes
|
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; \
|
$(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" $@; \
|
grep -q -E "changing 'bar' PLT entry in .*/elf/tst-plt-rewritemod1.so' to direct branch" $@; \
|
||||||
$(evaluate-test)
|
$(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
|
||||||
|
|
||||||
endif # $(subdir) == elf
|
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. */
|
/* Skip ENDBR64 if IBT isn't enabled. */
|
||||||
if (!ibt_enabled_p)
|
if (!ibt_enabled_p)
|
||||||
branch_start = ALIGN_DOWN (branch_start, pltent);
|
branch_start = ALIGN_DOWN (branch_start, pltent);
|
||||||
/* Get the displacement from the branch target. */
|
/* Get the displacement from the branch target. NB: We must use
|
||||||
ElfW(Addr) disp = value - branch_start - JMP32_INSN_SIZE;
|
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) plt_end;
|
||||||
ElfW(Addr) pad;
|
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