From 267205149587595e956db25a12252835a51cd372 Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Fri, 20 Sep 2019 15:03:21 +0000 Subject: [PATCH] [ELF] Error if the linked-to section of a SHF_LINK_ORDER section is discarded Summary: If st_link(A)=B, and A has the SHF_LINK_ORDER flag, we may dereference a null pointer if B is garbage collected (PR43147): 1. In Wrter.cpp:compareByFilePosition, `aOut->sectionIndex` or `bOut->sectionIndex` 2. In OutputSections::finalize, `d->getParent()->sectionIndex` Simply error and bail out to avoid null pointer dereferences. ld.bfd has a similar error: sh_link of section `.bar' points to discarded section `.foo0' of `a.o' ld.bfd is more permissive in that it just checks whether the linked-to section of the first input section is discarded. This is likely because it sets sh_link of the output section according to the first input section. Reviewed By: grimar Differential Revision: https://reviews.llvm.org/D67761 llvm-svn: 372400 --- lld/ELF/Writer.cpp | 18 ++++++++++++---- lld/test/ELF/gc-sections-metadata-err.s | 37 +++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 lld/test/ELF/gc-sections-metadata-err.s diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 9a61883..f033447 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1500,6 +1500,12 @@ template void Writer::resolveShfLinkOrder() { if (!(sec->flags & SHF_LINK_ORDER)) continue; + // The ARM.exidx section use SHF_LINK_ORDER, but we have consolidated + // this processing inside the ARMExidxsyntheticsection::finalizeContents(). + if (!config->relocatable && config->emachine == EM_ARM && + sec->type == SHT_ARM_EXIDX) + continue; + // Link order may be distributed across several InputSectionDescriptions // but sort must consider them all at once. std::vector scriptSections; @@ -1509,14 +1515,16 @@ template void Writer::resolveShfLinkOrder() { for (InputSection *&isec : isd->sections) { scriptSections.push_back(&isec); sections.push_back(isec); + + InputSection *link = isec->getLinkOrderDep(); + if (!link->getParent()) + error(toString(isec) + ": sh_link points to discarded section " + + toString(link)); } } } - // The ARM.exidx section use SHF_LINK_ORDER, but we have consolidated - // this processing inside the ARMExidxsyntheticsection::finalizeContents(). - if (!config->relocatable && config->emachine == EM_ARM && - sec->type == SHT_ARM_EXIDX) + if (errorCount()) continue; llvm::stable_sort(sections, compareByFilePosition); @@ -1894,6 +1902,8 @@ template void Writer::finalizeSections() { // SHFLinkOrder processing must be processed after relative section placements are // known but before addresses are allocated. resolveShfLinkOrder(); + if (errorCount()) + return; // This is used to: // 1) Create "thunks": diff --git a/lld/test/ELF/gc-sections-metadata-err.s b/lld/test/ELF/gc-sections-metadata-err.s new file mode 100644 index 0000000..0f96e41 --- /dev/null +++ b/lld/test/ELF/gc-sections-metadata-err.s @@ -0,0 +1,37 @@ +# REQUIRES: x86 + +## Error if the linked-to section of an input section is discarded. + +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o +# RUN: not ld.lld --gc-sections --print-gc-sections %t.o -o /dev/null 2>&1 | FileCheck %s + +# CHECK: removing unused section {{.*}}.o:(.foo0) +# CHECK-NEXT: error: {{.*}}.o:(.bar): sh_link points to discarded section {{.*}}.o:(.foo0) +# CHECK-NEXT: error: {{.*}}.o:(.baz): sh_link points to discarded section {{.*}}.o:(.foo0) + +.globl _start +_start: + call .foo1 + call bar0 + call bar1 + call baz0 + call baz1 + +.section .foo0,"a" +.section .foo1,"a" + +## The linked-to section of the first input section is discarded. +.section .bar,"ao",@progbits,.foo0,unique,0 +bar0: +.byte 0 +.section .bar,"ao",@progbits,.foo1,unique,1 +bar1: +.byte 1 + +## Another case: the linked-to section of the second input section is discarded. +.section .baz,"ao",@progbits,.foo1,unique,0 +baz0: +.byte 0 +.section .baz,"ao",@progbits,.foo0,unique,1 +baz1: +.byte 1 -- 2.7.4