bug-binutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Bug ld/31795] ld.bfd makes ELFs of type ET_EXEC for static PIEs when lo


From: mintsuki at protonmail dot com
Subject: [Bug ld/31795] ld.bfd makes ELFs of type ET_EXEC for static PIEs when load address is non-0
Date: Tue, 28 May 2024 16:22:24 +0000

https://sourceware.org/bugzilla/show_bug.cgi?id=31795

--- Comment #59 from mintsuki <mintsuki at protonmail dot com> ---
(In reply to Adhemerval Zanella from comment #58)
> (In reply to mintsuki from comment #41)
> > (In reply to Adhemerval Zanella from comment #39)
> > > (In reply to Fangrui Song from comment #37)
> > > > I agree with mintsuki . The "-pie -Ttext-segment=non-zero => ET_EXEC" 
> > > > hack
> > > > should not be needed.
> > > > 
> > > > From https://sourceware.org/pipermail/binutils/2013-December/083381.html
> > > > 
> > > > > Linker sets e_type in ELF header to ET_DYN for -pie 
> > > > > -Ttext-segment=0xXXX.
> > > > > When I added -Ttext-segment=0xXXX, one goal was to load
> > > > > small model executable above 4GB on Linux/x86-64, which
> > > > > was done with -pie -Ttext-segment=0xXXX.  But -pie sets
> > > > > e_type in ELF header to ET_DYN and kernel may ignore
> > > > > p_vaddr in ELF header to load ET_DYN binary at a random
> > > > > address.  This patch changes ld to set e_type in ELF header
> > > > > to ET_EXEC if the first PT_LOAD segment has non-zero
> > > > > p_vaddr.  If this is unacceptable as generic ELF change,
> > > > > I can make it specific to x86.
> > > > 
> > > > Was the intention for the following command to load the text segment at 
> > > > an
> > > > address >= 0x600000000000 ?
> > > > 
> > > > ```
> > > > % cat a.c
> > > > #include <stdio.h>
> > > > int main() { printf("%p\n", main); }
> > > > % gcc -pie -Wl,-no-pie a.c -fuse-ld=bfd
> > > > -Wl,--no-relax,-Ttext-segment=0x600000000000 -o a
> > > > % ./a
> > > > 0x600000001139
> > > > % ./a
> > > > 0x600000001139  # no ASLR
> > > > ```
> > > > 
> > > > Changing ET_DYN to ET_EXEC fulfills the address requirement but disables
> > > > ASLR.
> > > > Is it intentional?
> > > 
> > > That's my understanding of reading the -Ttext-segment documentation.  The
> > > question is whether we relax the semantic to have it as a minimum address 
> > > or
> > > define it as the expected address (thus disabling ASLR as a consequence). 
> > 
> > My understanding is that the PT_LOAD PHDR addresses could be slid, as long
> > as they are slid above the specified address. The fact that the first
> > PT_LOAD PHDR is 0 or not should be irrelevant. It makes no sense for it to
> > be relevant, let alone for it to dictate the ELF type to be ET_EXEC.
> > 
> > This is how Limine behaves, and how I interpret the ELF format.
> 
> Unfortunately, this is not what binutils documentation states ("When
> creating an ELF executable, it will set the address of the first byte of the
> text segment") nor how Linux handles it (where ET_DYN does not enforce
> e_entry).
> 
> And it seems to be a Linux-specific issue, since on FreeBSD:
> 
> $ cc -pie a.c -fuse-ld=lld -Wl,--no-relax,--image-base=0x600000000000
> -Wl,-z,notext -o a-lld
> $ readelf -h a-lld
> ELF Header:
>   Magic:   7f 45 4c 46 02 01 01 09 00 00 00 00 00 00 00 00
>   Class:                             ELF64
>   Data:                              2's complement, little endian
>   Version:                           1 (current)
>   OS/ABI:                            FreeBSD
>   ABI Version:                       0
>   Type:                              DYN (Shared object file)
>   Machine:                           Advanced Micro Devices x86-64
>   Version:                           0x1
>   Entry point address:               0x6000000016b0
>   Start of program headers:          64 (bytes into file)
>   Start of section headers:          12928 (bytes into file)
>   Flags:                             0
>   Size of this header:               64 (bytes)
>   Size of program headers:           56 (bytes)
>   Number of program headers:         11
>   Size of section headers:           64 (bytes)
>   Number of section headers:         39
>   Section header string table index: 37
> $ readelf -d a-lld  | grep -w FLAGS_1
>  0x000000006ffffffb FLAGS_1              PIE
> $ doas sysctl -w kern.elf64.aslr.pie_enable=1
> kern.elf64.aslr.pie_enable: 0 -> 1
> $ ./a-lld
> 0x6000000019d0
> $ ./a-lld
> 0x6000000019d0
> 
> So maybe we either enable this iff targeting Linux, or check if kernel is
> willing to enforce e_entry even for DYN. 
> 
> I am not sure if the correct approach is relaxing the
> '-Ttext-segment/--image-base' to be a minimum address.  For this, I would
> add another linker option.

I am not sure what you mean with "willing to enforce e_entry".

In any case, how about checking what the generated ELF file's OS/ABI is and
only doing the DYN->EXEC hack if it happens to be GNU/Linux?

-- 
You are receiving this mail because:
You are on the CC list for the bug.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]