[PATCH] D43819: [ELF] - Restrict section offsets that exceeds file size.
Rafael Avila de Espindola via llvm-commits
llvm-commits at lists.llvm.org
Mon Mar 12 09:15:02 PDT 2018
LGTM.
I think the comment can probably be simplified, but that can be a
followup.
Cheers,
Rafael
George Rimar via Phabricator <reviews at reviews.llvm.org> writes:
> grimar updated this revision to Diff 137976.
> grimar added a comment.
>
> - Addressed review comment.
>
>
> https://reviews.llvm.org/D43819
>
> Files:
> ELF/Writer.cpp
> test/ELF/linkerscript/Inputs/sections-va-overflow.s
> test/ELF/linkerscript/sections-va-overflow.test
>
>
> Index: test/ELF/linkerscript/sections-va-overflow.test
> ===================================================================
> --- test/ELF/linkerscript/sections-va-overflow.test
> +++ test/ELF/linkerscript/sections-va-overflow.test
> @@ -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
> Index: test/ELF/linkerscript/Inputs/sections-va-overflow.s
> ===================================================================
> --- test/ELF/linkerscript/Inputs/sections-va-overflow.s
> +++ test/ELF/linkerscript/Inputs/sections-va-overflow.s
> @@ -0,0 +1,6 @@
> +.global _start
> +_start:
> + retq
> +
> +.bss
> +.space 0x2000
> Index: ELF/Writer.cpp
> ===================================================================
> --- ELF/Writer.cpp
> +++ ELF/Writer.cpp
> @@ -1873,6 +1873,12 @@
> 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 @@
>
> 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 @@
> }
> }
>
> -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).
> //
>
>
> Index: test/ELF/linkerscript/sections-va-overflow.test
> ===================================================================
> --- test/ELF/linkerscript/sections-va-overflow.test
> +++ test/ELF/linkerscript/sections-va-overflow.test
> @@ -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
> Index: test/ELF/linkerscript/Inputs/sections-va-overflow.s
> ===================================================================
> --- test/ELF/linkerscript/Inputs/sections-va-overflow.s
> +++ test/ELF/linkerscript/Inputs/sections-va-overflow.s
> @@ -0,0 +1,6 @@
> +.global _start
> +_start:
> + retq
> +
> +.bss
> +.space 0x2000
> Index: ELF/Writer.cpp
> ===================================================================
> --- ELF/Writer.cpp
> +++ ELF/Writer.cpp
> @@ -1873,6 +1873,12 @@
> 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 @@
>
> 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 @@
> }
> }
>
> -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).
> //
More information about the llvm-commits
mailing list