[RFC PATCH] Little hardening DSOs/executables against exploits (take 2)

Jakub Jelinek jakub@redhat.com
Wed Jan 14 10:16:00 GMT 2004


On Tue, Jan 13, 2004 at 09:11:31AM +1030, Alan Modra wrote:
> On Mon, Jan 12, 2004 at 12:38:51PM +0100, Jakub Jelinek wrote:
> > Below is an updated patch for the ELF DSO/executable section reshuffling
> > to make life harder for data section buffer overflows.
> 
> OK, provided you also fix any testsuite breakage this might cause.

Thanks.

I'd like to avoid fixing up testsuite breakages twice on !NO_SMALL_DATA
architectures though, which means deciding and implementing section order
on !NO_SMALL_DATA arches as well.

The logic could be written as (on ppc32 example (BTW, shouldn't elf32ppc.sh
define COMMONPAGESIZE=0x1000 ?)).
I.e. if RW segment size (distance between DATA_SEGMENT_ALIGN and DATA_SEGMENT_END
is smaller than certain arch dependent value or .sbss is small enough, move
GOT sections into RELRO area.  If RW segment size is bigger than the arch dependent
value, .sdata2/.sbss2/.sdata/.sbss sections would need to be moved together with
.got (right after the end of RELRO area) to remain reachable from the PIC register.

Either the linker can have constraints for the 3 cases which matter for NO_SMALL_DATA
arches, or the linker script can allow to write various constraints, or the sections
would need to be removed from the linker script and moved to orphan handling.
The last option seems worse to me, since linker script completely looses control over
the placement of the sections that way, one cannot easily add sections which ought to
be handled similarly to say .got, .sdata etc.

...
  .jcr            : { KEEP (*(.jcr)) }
  .data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) }
  .dynamic        : { *(.dynamic) }
  .fixup          : ONLY_IF (SIZE (.sbss) < 1024 || THIS_SEGMENT_SIZE <= 32768) { *(.fixup) }
  .got1           : ONLY_IF (SIZE (.sbss) < 1024 || THIS_SEGMENT_SIZE <= 32768) { *(.got1) }
  .got2           : ONLY_IF (SIZE (.sbss) < 1024 || THIS_SEGMENT_SIZE <= 32768) { *(.got2) }
  .got            : ONLY_IF (SIZE (.sbss) < 1024 || THIS_SEGMENT_SIZE <= 32768) { *(.got.plt) *(.got) }
  . = DATA_SEGMENT_RELRO_END (.);
  .sdata2         : ONLY_IF (THIS_SEGMENT_SIZE > 32768 && SIZE (.sbss) < 1024) { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }
  .sbss2          : ONLY_IF (THIS_SEGMENT_SIZE > 32768 && SIZE (.sbss) < 1024) { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
  .sdata          : ONLY_IF (THIS_SEGMENT_SIZE > 32768 && SIZE (.sbss) < 1024) 
  {
    *(.sdata .sdata.* .gnu.linkonce.s.*)
  }
  .sbss           : ONLY_IF (THIS_SEGMENT_SIZE > 32768 && SIZE (.sbss) < 1024) 
  {
    PROVIDE (__sbss_start = .);
    PROVIDE (___sbss_start = .);
    *(.dynsbss)
    *(.sbss .sbss.* .gnu.linkonce.sb.*)
    *(.scommon)
    PROVIDE (__sbss_end = .);
    PROVIDE (___sbss_end = .);
  }
  .data           :
  {
    *(.data .data.* .gnu.linkonce.d.*)
    SORT(CONSTRUCTORS)
  }
  .data1          : { *(.data1) }
  .fixup          : ONLY_IF (SIZE (.sbss) >= 1024 && THIS_SEGMENT_SIZE > 32768) { *(.fixup) }
  .got1           : ONLY_IF (SIZE (.sbss) >= 1024 && THIS_SEGMENT_SIZE > 32768) { *(.got1) }
  .got2           : ONLY_IF (SIZE (.sbss) >= 1024 && THIS_SEGMENT_SIZE > 32768) { *(.got2) }
  .got            : ONLY_IF (SIZE (.sbss) >= 1024 && THIS_SEGMENT_SIZE > 32768) { *(.got.plt) *(.got) }
  .sdata2         : ONLY_IF (THIS_SEGMENT_SIZE <= 32768 || SIZE (.sbss) >= 1024) { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }
  .sbss2          : ONLY_IF (THIS_SEGMENT_SIZE <= 32768 || SIZE (.sbss) >= 1024) { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
  /* We want the small data sections together, so single-instruction offsets
     can access them all, and initialized data all before uninitialized, so
     we can shorten the on-disk segment size.  */
  .sdata          : ONLY_IF (THIS_SEGMENT_SIZE <= 32768 || SIZE (.sbss) >= 1024) 
  {
    *(.sdata .sdata.* .gnu.linkonce.s.*)
  }
  _edata = .;
  PROVIDE (edata = .);
  __bss_start = .;
  .sbss           : ONLY_IF (THIS_SEGMENT_SIZE <= 32768 || SIZE (.sbss) >= 1024) 
  {
    PROVIDE (__sbss_start = .);
    PROVIDE (___sbss_start = .);
    *(.dynsbss)
    *(.sbss .sbss.* .gnu.linkonce.sb.*)
    *(.scommon)
    PROVIDE (__sbss_end = .);
    PROVIDE (___sbss_end = .);
  }
  .plt            : { *(.plt) }
...

	Jakub



More information about the Binutils mailing list