[PATCH v7] elf: Handle static PIE with non-zero load address [BZ #31799]
H.J. Lu
hjl.tools@gmail.com
Mon Nov 18 04:12:30 GMT 2024
On Tue, Nov 5, 2024, 5:37 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>
> On Tue, Nov 5, 2024, 12:39 AM Noah Goldstein <goldstein.w.n@gmail.com>
> wrote:
>
>> On Sun, Nov 3, 2024 at 5:19 PM H.J. Lu <hjl.tools@gmail.com> wrote:
>> >
>> > On Thu, Oct 31, 2024 at 7:55 AM H.J. Lu <hjl.tools@gmail.com> wrote:
>> > >
>> > > On Tue, Oct 29, 2024 at 1:33 PM Noah Goldstein <
>> goldstein.w.n@gmail.com> wrote:
>> > > >
>> > > > On Mon, Oct 28, 2024 at 3:11 PM H.J. Lu <hjl.tools@gmail.com>
>> wrote:
>> > > > >
>> > > > > 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>
>> > > > > ---
>> > > > > configure | 74
>> ++++++++++++++++++++++++++++++++++++
>> > > > > configure.ac | 36 ++++++++++++++++++
>> > > > > elf/Makefile | 20 ++++++++++
>> > > > > elf/dl-reloc-static-pie.c | 30 +++++++++++----
>> > > > > elf/tst-pie-address-static.c | 19 +++++++++
>> > > > > elf/tst-pie-address.c | 28 ++++++++++++++
>> > > > > 6 files changed, 200 insertions(+), 7 deletions(-)
>> > > > > create mode 100644 elf/tst-pie-address-static.c
>> > > > > create mode 100644 elf/tst-pie-address.c
>> > > > >
>> > > > > diff --git a/configure b/configure
>> > > > > index 9c0c0dce03..9bcf62dca5 100755
>> > > > > --- a/configure
>> > > > > +++ b/configure
>> > > > > @@ -8107,6 +8107,80 @@ printf "%s\n" "$libc_cv_cc_pie_default"
>> >&6; }
>> > > > > config_vars="$config_vars
>> > > > > 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 "checking if we can build programs as PIE... " >&6; }
>> > > > > cat confdefs.h - <<_ACEOF >conftest.$ac_ext
>> > > > > diff --git a/configure.ac b/configure.ac
>> > > > > index d5a00461ff..895bd5267d 100644
>> > > > > --- a/configure.ac
>> > > > > +++ b/configure.ac
>> > > > > @@ -1763,6 +1763,42 @@ fi
>> > > > > rm -f conftest.*])
>> > > > > 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_COMPILE_IFELSE([AC_LANG_SOURCE([[#ifdef PIE_UNSUPPORTED
>> > > > > # error PIE is not supported
>> > > > > diff --git a/elf/Makefile b/elf/Makefile
>> > > > > index 9cfe738919..4eaca7af67 100644
>> > > > > --- a/elf/Makefile
>> > > > > +++ b/elf/Makefile
>> > > > > @@ -1091,6 +1091,25 @@ tests-pie += \
>> > > > > tst-pie1 \
>> > > > > tst-pie2 \
>> > > > > # 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))
>> > > > > tests += 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-pie2.c += $(pie-ccflag)
>> > > > > +CFLAGS-tst-pie-address.c += $(pie-ccflag)
>> > > > >
>> > > > > $(objpfx)tst-piemod1.so: $(libsupport)
>> > > > > $(objpfx)tst-pie1: $(objpfx)tst-piemod1.so
>> > > > > diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c
>> > > > > index 10c23d0bf0..bfee89dfc3 100644
>> > > > > --- a/elf/dl-reloc-static-pie.c
>> > > > > +++ b/elf/dl-reloc-static-pie.c
>> > > > > @@ -37,21 +37,37 @@ _dl_relocate_static_pie (void)
>> > > > > {
>> > > > > struct link_map *main_map = _dl_get_dl_main_map ();
>> > > > >
>> > > > > - /* Figure out the run-time load address of static PIE. */
>> > > > > - main_map->l_addr = elf_machine_load_address ();
>> > > > > -
>> > > > > - /* Read our own dynamic section and fill in the info array. */
>> > > > > - main_map->l_ld = ((void *) main_map->l_addr +
>> elf_machine_dynamic ());
>> > > > > -
>> > > > > + /* NB: elf_machine_load_address () returns the run-time 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
>> > > > > + in memory. We must subtract the link-time load address of
>> static PIE,
>> > > > > + 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);
>> > > > > size_t phnum = GL(dl_phnum);
>> > > > > 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;
>> > > > > 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);
>> > > > >
>> > > > > # ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
>> > > > > diff --git a/elf/tst-pie-address-static.c
>> b/elf/tst-pie-address-static.c
>> > > > > new file mode 100644
>> > > > > index 0000000000..be2831e9d6
>> > > > > --- /dev/null
>> > > > > +++ b/elf/tst-pie-address-static.c
>> > > > > @@ -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"
>> > > > > diff --git a/elf/tst-pie-address.c b/elf/tst-pie-address.c
>> > > > > new file mode 100644
>> > > > > index 0000000000..aa1ca0a9fd
>> > > > > --- /dev/null
>> > > > > +++ b/elf/tst-pie-address.c
>> > > > > @@ -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>
>> > > > > --
>> > > > > 2.47.0
>> > > > >
>> > > >
>> > > > LGTM.
>> > > >
>> > > > Think Carlos was also going to take a look at this (from monday
>> review
>> > > > minutes), so please wait for Carlos to take a look too before
>> pushing.
>> > >
>> > > Hi Carlos,
>> > >
>> > > Do you have comments?
>> > >
>> > > Thanks.
>> > >
>> >
>> > I will check it in tomorrow.
>> >
>> > Thanks.
>>
>> At least according to meeting notes, Carlos still wants to review this.
>>
>
> Hi Carlos,
>
> Any estimate when you can review it?
>
I will check it in this week.
> >
>> > --
>> > H.J.
>>
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://sourceware.org/pipermail/libc-alpha/attachments/20241118/780ad9f3/attachment-0001.htm>
More information about the Libc-alpha
mailing list