[lld] r327376 - [ELF] - Restrict section offsets that exceeds file size.

George Rimar via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 13 01:47:17 PDT 2018


Author: grimar
Date: Tue Mar 13 01:47:17 2018
New Revision: 327376

URL: http://llvm.org/viewvc/llvm-project?rev=327376&view=rev
Log:
[ELF] - Restrict section offsets that exceeds file size.

This is part of PR36515.

With some linkerscripts it is possible to get file offset overlaps
and overflows. Currently LLD checks overlaps in checkNoOverlappingSections().
And also we allow broken output with --no-inhibit-exec.
Problem is that sometimes final offset of sections is completely broken
and we calculate output file size wrong and might crash.

Patch implements check to verify that there is no output section
which offset exceeds file size.

Differential revision: https://reviews.llvm.org/D43819

Added:
    lld/trunk/test/ELF/linkerscript/Inputs/sections-va-overflow.s
    lld/trunk/test/ELF/linkerscript/sections-va-overflow.test
Modified:
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=327376&r1=327375&r2=327376&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Tue Mar 13 01:47:17 2018
@@ -1873,6 +1873,12 @@ template <class ELFT> void Writer<ELFT>:
   FileSize = alignTo(Off, Config->Wordsize);
 }
 
+static std::string rangeToString(uint64_t Addr, uint64_t Len) {
+  if (Len == 0)
+    return "<empty range at 0x" + utohexstr(Addr) + ">";
+  return "[0x" + utohexstr(Addr) + ", 0x" + utohexstr(Addr + Len - 1) + "]";
+}
+
 // Assign file offsets to output sections.
 template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
   uint64_t Off = 0;
@@ -1897,6 +1903,25 @@ template <class ELFT> void Writer<ELFT>:
 
   SectionHeaderOff = alignTo(Off, Config->Wordsize);
   FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr);
+
+  // Our logic assumes that sections have rising VA within the same segment.
+  // With use of linker scripts it is possible to violate this rule and get file
+  // offset overlaps or overflows. That should never happen with a valid script
+  // which does not move the location counter backwards and usually scripts do
+  // not do that. Unfortunately, there are apps in the wild, for example, Linux
+  // kernel, which control segment distribution explicitly and move the counter
+  // backwards, so we have to allow doing that to support linking them. We
+  // perform non-critical checks for overlaps in checkNoOverlappingSections(),
+  // but here we want to prevent file size overflows because it would crash the
+  // linker.
+  for (OutputSection *Sec : OutputSections) {
+    if (Sec->Type == SHT_NOBITS)
+      continue;
+    if ((Sec->Offset > FileSize) || (Sec->Offset + Sec->Size > FileSize))
+      error("unable to place section " + Sec->Name + " at file offset " +
+            rangeToString(Sec->Offset, Sec->Offset + Sec->Size) +
+            "; check your linker script for overflows");
+  }
 }
 
 // Finalize the program headers. We call this function after we assign
@@ -1935,12 +1960,6 @@ template <class ELFT> void Writer<ELFT>:
   }
 }
 
-static std::string rangeToString(uint64_t Addr, uint64_t Len) {
-  if (Len == 0)
-    return "<empty range at 0x" + utohexstr(Addr) + ">";
-  return "[0x" + utohexstr(Addr) + ", 0x" + utohexstr(Addr + Len - 1) + "]";
-}
-
 // Check whether sections overlap for a specific address range (file offsets,
 // load and virtual adresses).
 //

Added: lld/trunk/test/ELF/linkerscript/Inputs/sections-va-overflow.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/Inputs/sections-va-overflow.s?rev=327376&view=auto
==============================================================================
--- lld/trunk/test/ELF/linkerscript/Inputs/sections-va-overflow.s (added)
+++ lld/trunk/test/ELF/linkerscript/Inputs/sections-va-overflow.s Tue Mar 13 01:47:17 2018
@@ -0,0 +1,6 @@
+.global _start
+_start:
+  retq
+
+.bss
+.space 0x2000

Added: lld/trunk/test/ELF/linkerscript/sections-va-overflow.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/linkerscript/sections-va-overflow.test?rev=327376&view=auto
==============================================================================
--- lld/trunk/test/ELF/linkerscript/sections-va-overflow.test (added)
+++ lld/trunk/test/ELF/linkerscript/sections-va-overflow.test Tue Mar 13 01:47:17 2018
@@ -0,0 +1,22 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/sections-va-overflow.s -o %t.o
+# RUN: not ld.lld -o /dev/null --script %s %t.o 2>&1 | FileCheck %s -check-prefix=ERR
+
+PHDRS {
+  ph_headers PT_PHDR PHDRS;
+  ph_text PT_LOAD FILEHDR PHDRS FLAGS (0x1 | 0x4);
+}
+
+SECTIONS { 
+ . = 0xffffffff20000000;
+ .text : { *(.text*) } : ph_text
+ .test 0x1000 : { BYTE(0) }
+ .bss : { *(.bss*) }
+}
+
+## Section .test has VA 0x1000 and placed in the same segment as section .text
+## with VA 0xffffffff20000000. That might be technically correct, but most probably
+## is a result of a broken script file and causes file offset calculation overflow.
+## It seems we do not have to support it, so we don't and we report an error in this case.
+# ERR: error: unable to place section .text at file offset [0xFFFFFFFF20000000, 0xFFFFFFFE40000000]; check your linker script for overflows
+# ERR-NOT: unable to place section .bss




More information about the llvm-commits mailing list