mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-26 19:23:34 +08:00
elf: Handle static PIE with non-zero load address [BZ #31799]
For a static PIE with non-zero load address, its PT_DYNAMIC segment entries contain the relocated values for the load address in static PIE. Since static PIE usually doesn't have PT_PHDR segment, use p_vaddr of the PT_LOAD segment with offset == 0 as the load address in static PIE and adjust the entries of PT_DYNAMIC segment in static PIE by properly setting the l_addr field for static PIE. This fixes BZ #31799. Signed-off-by: H.J. Lu <hjl.tools@gmail.com> Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>
This commit is contained in:
parent
713d6d7e78
commit
e7b5532721
74
configure
vendored
74
configure
vendored
@ -8107,6 +8107,80 @@ printf "%s\n" "$libc_cv_cc_pie_default" >&6; }
|
|||||||
config_vars="$config_vars
|
config_vars="$config_vars
|
||||||
cc-pie-default = $libc_cv_cc_pie_default"
|
cc-pie-default = $libc_cv_cc_pie_default"
|
||||||
|
|
||||||
|
# Get Position Dependent Executable (PDE) load address to be used to
|
||||||
|
# load static Position Independent Executable (PIE) at a known working
|
||||||
|
# non-zero load address. This is only used by glibc tests to verify
|
||||||
|
# that PIE and static PIE with non-zero load address work correctly.
|
||||||
|
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking PDE load address" >&5
|
||||||
|
printf %s "checking PDE load address... " >&6; }
|
||||||
|
if test ${libc_cv_pde_load_address+y}
|
||||||
|
then :
|
||||||
|
printf %s "(cached) " >&6
|
||||||
|
else case e in #(
|
||||||
|
e) cat > conftest.S <<EOF
|
||||||
|
.globl _start
|
||||||
|
_start:
|
||||||
|
.globl __start
|
||||||
|
__start:
|
||||||
|
EOF
|
||||||
|
if test $libc_cv_cc_pie_default = yes; then
|
||||||
|
pde_ld_flags="-no-pie"
|
||||||
|
fi
|
||||||
|
if ${CC-cc} $pde_ld_flags $CFLAGS $CPPFLAGS $LDFLAGS \
|
||||||
|
-nostartfiles -nostdlib $no_ssp \
|
||||||
|
-o conftest conftest.S 1>&5 2>&5; then
|
||||||
|
# Get the load address of the first PT_LOAD segment.
|
||||||
|
libc_cv_pde_load_address=$(LC_ALL=C $READELF -Wl conftest \
|
||||||
|
| $AWK '/LOAD/ { print $3; exit 0; }')
|
||||||
|
else
|
||||||
|
as_fn_error $? "${CC-cc} can not create PDE" "$LINENO" 5
|
||||||
|
fi
|
||||||
|
rm -f conftest* ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_pde_load_address" >&5
|
||||||
|
printf "%s\n" "$libc_cv_pde_load_address" >&6; }
|
||||||
|
config_vars="$config_vars
|
||||||
|
pde-load-address = $libc_cv_pde_load_address"
|
||||||
|
|
||||||
|
# Get the linker command-line option to load executable at a non-zero
|
||||||
|
# load address. This is only used by glibc tests to verify that PIE and
|
||||||
|
# static PIE with non-zero load address work correctly.
|
||||||
|
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for linker that supports -Ttext-segment=$libc_cv_pde_load_address" >&5
|
||||||
|
printf %s "checking for linker that supports -Ttext-segment=$libc_cv_pde_load_address... " >&6; }
|
||||||
|
libc_linker_feature=no
|
||||||
|
cat > conftest.c <<EOF
|
||||||
|
int _start (void) { return 42; }
|
||||||
|
EOF
|
||||||
|
if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp
|
||||||
|
-Wl,-Ttext-segment=$libc_cv_pde_load_address -nostdlib -nostartfiles
|
||||||
|
-fPIC -shared -o conftest.so conftest.c
|
||||||
|
1>&5'
|
||||||
|
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
|
||||||
|
(eval $ac_try) 2>&5
|
||||||
|
ac_status=$?
|
||||||
|
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
|
||||||
|
test $ac_status = 0; }; }
|
||||||
|
then
|
||||||
|
if ${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS $no_ssp -Wl,-Ttext-segment=$libc_cv_pde_load_address -nostdlib \
|
||||||
|
-nostartfiles -fPIC -shared -o conftest.so conftest.c 2>&1 \
|
||||||
|
| grep "warning: -Ttext-segment=$libc_cv_pde_load_address ignored" > /dev/null 2>&1; then
|
||||||
|
true
|
||||||
|
else
|
||||||
|
libc_linker_feature=yes
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
rm -f conftest*
|
||||||
|
if test $libc_linker_feature = yes; then
|
||||||
|
libc_cv_load_address_ldflag=-Wl,-Ttext-segment
|
||||||
|
else
|
||||||
|
libc_cv_load_address_ldflag=
|
||||||
|
fi
|
||||||
|
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_linker_feature" >&5
|
||||||
|
printf "%s\n" "$libc_linker_feature" >&6; }
|
||||||
|
config_vars="$config_vars
|
||||||
|
load-address-ldflag = $libc_cv_load_address_ldflag"
|
||||||
|
|
||||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can build programs as PIE" >&5
|
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if we can build programs as PIE" >&5
|
||||||
printf %s "checking if we can build programs as PIE... " >&6; }
|
printf %s "checking if we can build programs as PIE... " >&6; }
|
||||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||||
|
36
configure.ac
36
configure.ac
@ -1763,6 +1763,42 @@ fi
|
|||||||
rm -f conftest.*])
|
rm -f conftest.*])
|
||||||
LIBC_CONFIG_VAR([cc-pie-default], [$libc_cv_cc_pie_default])
|
LIBC_CONFIG_VAR([cc-pie-default], [$libc_cv_cc_pie_default])
|
||||||
|
|
||||||
|
# Get Position Dependent Executable (PDE) load address to be used to
|
||||||
|
# load static Position Independent Executable (PIE) at a known working
|
||||||
|
# non-zero load address. This is only used by glibc tests to verify
|
||||||
|
# that PIE and static PIE with non-zero load address work correctly.
|
||||||
|
AC_CACHE_CHECK([PDE load address],
|
||||||
|
libc_cv_pde_load_address, [dnl
|
||||||
|
cat > conftest.S <<EOF
|
||||||
|
.globl _start
|
||||||
|
_start:
|
||||||
|
.globl __start
|
||||||
|
__start:
|
||||||
|
EOF
|
||||||
|
if test $libc_cv_cc_pie_default = yes; then
|
||||||
|
pde_ld_flags="-no-pie"
|
||||||
|
fi
|
||||||
|
if ${CC-cc} $pde_ld_flags $CFLAGS $CPPFLAGS $LDFLAGS \
|
||||||
|
-nostartfiles -nostdlib $no_ssp \
|
||||||
|
-o conftest conftest.S 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD; then
|
||||||
|
# Get the load address of the first PT_LOAD segment.
|
||||||
|
libc_cv_pde_load_address=$(LC_ALL=C $READELF -Wl conftest \
|
||||||
|
| $AWK '/LOAD/ { print $3; exit 0; }')
|
||||||
|
else
|
||||||
|
AC_MSG_ERROR([${CC-cc} can not create PDE])
|
||||||
|
fi
|
||||||
|
rm -f conftest*])
|
||||||
|
LIBC_CONFIG_VAR([pde-load-address], [$libc_cv_pde_load_address])
|
||||||
|
|
||||||
|
# Get the linker command-line option to load executable at a non-zero
|
||||||
|
# load address. This is only used by glibc tests to verify that PIE and
|
||||||
|
# static PIE with non-zero load address work correctly.
|
||||||
|
LIBC_LINKER_FEATURE([-Ttext-segment=$libc_cv_pde_load_address],
|
||||||
|
[-Wl,-Ttext-segment=$libc_cv_pde_load_address],
|
||||||
|
[libc_cv_load_address_ldflag=-Wl,-Ttext-segment],
|
||||||
|
[libc_cv_load_address_ldflag=])
|
||||||
|
LIBC_CONFIG_VAR([load-address-ldflag], [$libc_cv_load_address_ldflag])
|
||||||
|
|
||||||
AC_MSG_CHECKING(if we can build programs as PIE)
|
AC_MSG_CHECKING(if we can build programs as PIE)
|
||||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#ifdef PIE_UNSUPPORTED
|
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[#ifdef PIE_UNSUPPORTED
|
||||||
# error PIE is not supported
|
# error PIE is not supported
|
||||||
|
20
elf/Makefile
20
elf/Makefile
@ -1091,6 +1091,25 @@ tests-pie += \
|
|||||||
tst-pie1 \
|
tst-pie1 \
|
||||||
tst-pie2 \
|
tst-pie2 \
|
||||||
# tests-pie
|
# tests-pie
|
||||||
|
ifneq (,$(load-address-ldflag))
|
||||||
|
tests += \
|
||||||
|
tst-pie-address \
|
||||||
|
# tests
|
||||||
|
tests-pie += \
|
||||||
|
tst-pie-address \
|
||||||
|
# tests-pie
|
||||||
|
LDFLAGS-tst-pie-address += $(load-address-ldflag)=$(pde-load-address)
|
||||||
|
ifeq (yes,$(enable-static-pie))
|
||||||
|
tests += \
|
||||||
|
tst-pie-address-static \
|
||||||
|
# tests
|
||||||
|
tests-static += \
|
||||||
|
tst-pie-address-static \
|
||||||
|
# tests-static
|
||||||
|
LDFLAGS-tst-pie-address-static += \
|
||||||
|
$(load-address-ldflag)=$(pde-load-address)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
ifeq (yes,$(have-protected-data))
|
ifeq (yes,$(have-protected-data))
|
||||||
tests += vismain
|
tests += vismain
|
||||||
tests-pie += vismain
|
tests-pie += vismain
|
||||||
@ -1937,6 +1956,7 @@ $(objpfx)tst-array5-static-cmp.out: tst-array5-static.exp \
|
|||||||
|
|
||||||
CFLAGS-tst-pie1.c += $(pie-ccflag)
|
CFLAGS-tst-pie1.c += $(pie-ccflag)
|
||||||
CFLAGS-tst-pie2.c += $(pie-ccflag)
|
CFLAGS-tst-pie2.c += $(pie-ccflag)
|
||||||
|
CFLAGS-tst-pie-address.c += $(pie-ccflag)
|
||||||
|
|
||||||
$(objpfx)tst-piemod1.so: $(libsupport)
|
$(objpfx)tst-piemod1.so: $(libsupport)
|
||||||
$(objpfx)tst-pie1: $(objpfx)tst-piemod1.so
|
$(objpfx)tst-pie1: $(objpfx)tst-piemod1.so
|
||||||
|
@ -37,21 +37,37 @@ _dl_relocate_static_pie (void)
|
|||||||
{
|
{
|
||||||
struct link_map *main_map = _dl_get_dl_main_map ();
|
struct link_map *main_map = _dl_get_dl_main_map ();
|
||||||
|
|
||||||
/* Figure out the run-time load address of static PIE. */
|
/* NB: elf_machine_load_address () returns the run-time load address
|
||||||
main_map->l_addr = elf_machine_load_address ();
|
of static PIE. The l_addr field contains the difference between the
|
||||||
|
link-time load address in the ELF file and the run-time load address
|
||||||
/* Read our own dynamic section and fill in the info array. */
|
in memory. We must subtract the link-time load address of static PIE,
|
||||||
main_map->l_ld = ((void *) main_map->l_addr + elf_machine_dynamic ());
|
which can be non-zero, when computing the l_addr field. Since static
|
||||||
|
PIE usually doesn't have PT_PHDR segment, use p_vaddr of the PT_LOAD
|
||||||
|
segment with offset == 0 as the load address of static PIE. */
|
||||||
|
ElfW(Addr) file_p_vaddr = 0;
|
||||||
const ElfW(Phdr) *ph, *phdr = GL(dl_phdr);
|
const ElfW(Phdr) *ph, *phdr = GL(dl_phdr);
|
||||||
size_t phnum = GL(dl_phnum);
|
size_t phnum = GL(dl_phnum);
|
||||||
for (ph = phdr; ph < &phdr[phnum]; ++ph)
|
for (ph = phdr; ph < &phdr[phnum]; ++ph)
|
||||||
if (ph->p_type == PT_DYNAMIC)
|
switch (ph->p_type)
|
||||||
{
|
{
|
||||||
|
case PT_LOAD:
|
||||||
|
if (ph->p_offset == 0)
|
||||||
|
file_p_vaddr = ph->p_vaddr;
|
||||||
|
break;
|
||||||
|
case PT_DYNAMIC:
|
||||||
main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
|
main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Figure out the run-time load address of static PIE. */
|
||||||
|
ElfW(Addr) l_addr = elf_machine_load_address ();
|
||||||
|
main_map->l_addr = l_addr - file_p_vaddr;
|
||||||
|
|
||||||
|
/* Read our own dynamic section and fill in the info array. */
|
||||||
|
main_map->l_ld = ((void *) l_addr + elf_machine_dynamic ());
|
||||||
|
|
||||||
elf_get_dynamic_info (main_map, false, true);
|
elf_get_dynamic_info (main_map, false, true);
|
||||||
|
|
||||||
# ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
|
# ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
|
||||||
|
19
elf/tst-pie-address-static.c
Normal file
19
elf/tst-pie-address-static.c
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
/* Test static PIE with non-zero load address.
|
||||||
|
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 "tst-pie-address.c"
|
28
elf/tst-pie-address.c
Normal file
28
elf/tst-pie-address.c
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/* Test PIE with non-zero load address.
|
||||||
|
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 <stdio.h>
|
||||||
|
|
||||||
|
static int
|
||||||
|
do_test (void)
|
||||||
|
{
|
||||||
|
printf ("Hello\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <support/test-driver.c>
|
Loading…
Reference in New Issue
Block a user