Skip to content

Commit

Permalink
[yaml2obj] - Program headers: add an additional check for Offset
Browse files Browse the repository at this point in the history
The `Offset` field is used to set the file offset of a program header.
In a normal object it should not be greater than the minimal offset
of sections included into segment.

This patch adds a check for that and adds tests.

Differential revision: https://reviews.llvm.org/D78304
  • Loading branch information
Georgii Rymar committed Apr 22, 2020
1 parent 87d33d9 commit 2bf5674
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 36 deletions.
16 changes: 10 additions & 6 deletions llvm/lib/ObjectYAML/ELFEmitter.cpp
Expand Up @@ -759,12 +759,16 @@ void ELFState<ELFT>::setProgramHeaderLayout(std::vector<Elf_Phdr> &PHeaders,
reportError("sections in the program header with index " +
Twine(PhdrIdx) + " are not sorted by their file offset");

if (YamlPhdr.Offset)
PHeader.p_offset = *YamlPhdr.Offset;
else if (!Fragments.empty())
PHeader.p_offset = Fragments.front().Offset;
else
PHeader.p_offset = 0;
uint64_t PhdrFileOffset = Fragments.empty() ? 0 : Fragments.front().Offset;
if (YamlPhdr.Offset) {
if (!Fragments.empty() && *YamlPhdr.Offset > PhdrFileOffset)
reportError("'Offset' for segment with index " + Twine(PhdrIdx) +
" must be less than or equal to the minimum file offset of "
"all included sections (0x" +
Twine::utohexstr(PhdrFileOffset) + ")");
PhdrFileOffset = *YamlPhdr.Offset;
}
PHeader.p_offset = PhdrFileOffset;

// Find the maximum offset of the end of a section in order to set p_filesz
// and p_memsz. When setting p_filesz, trailing SHT_NOBITS sections are not
Expand Down
8 changes: 0 additions & 8 deletions llvm/test/Object/invalid.test
Expand Up @@ -485,17 +485,9 @@ FileHeader:
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
Sections:
- Name: .dynamic
Type: SHT_DYNAMIC
Entries:
- Tag: DT_NULL
Value: 0
ProgramHeaders:
- Type: PT_DYNAMIC
Offset: 0xffff0000
Sections:
- Section: .dynamic

## PT_DYNAMIC's p_filesz field is so large that p_offset + p_filesz is larger
## than the object size. Check llvm-readobj reports it.
Expand Down
12 changes: 3 additions & 9 deletions llvm/test/tools/llvm-objcopy/ELF/invalid-p_filesz-p_offset.test
Expand Up @@ -33,13 +33,7 @@ FileHeader:
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
Sections:
- Name: .foo
Type: SHT_PROGBITS
Size: 1
ProgramHeaders:
- Type: PT_LOAD
Offset: 0x100000
FileSize: 1
Sections:
- Section: .foo
- Type: PT_LOAD
Offset: 0x100000
FileSize: 1
8 changes: 1 addition & 7 deletions llvm/test/tools/llvm-readobj/ELF/gnu-notes.test
Expand Up @@ -165,15 +165,9 @@ FileHeader:
Data: ELFDATA2LSB
Type: ET_CORE
Machine: EM_X86_64
Sections:
- Name: .note
Type: SHT_NOTE
Notes: []
ProgramHeaders:
- Type: PT_NOTE
- Type: PT_NOTE
Offset: 0xffff0000
Sections:
- Section: .note

## Test tools report an error if a note program header has an invalid size that
## goes past the end of file.
Expand Down
120 changes: 114 additions & 6 deletions llvm/test/tools/yaml2obj/ELF/program-header-size-offset.yaml
@@ -1,8 +1,8 @@
## Show that yaml2obj properly emits program headers with explicit file size,
## memory size and offset parameters.

# RUN: yaml2obj %s -o %t
# RUN: llvm-readobj %t --program-headers | FileCheck %s
# RUN: yaml2obj --docnum=1 %s -o %t1
# RUN: llvm-readobj %t1 --program-headers | FileCheck %s

# CHECK: ProgramHeaders [
# CHECK: Offset: 0x1234
Expand Down Expand Up @@ -34,7 +34,7 @@
# CHECK: MemSize: 6
# CHECK: ]

!ELF
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Expand Down Expand Up @@ -92,17 +92,125 @@ ProgramHeaders:
MemSize: 9
Sections:
- Section: .text
# Program header with sections, invalid properties.
# Program header with invalid properties.
- Type: 0x6abcdef0
Offset: 0x3000
FileSize: 3
MemSize: 2
Sections:
- Section: .data
# Program header with 2 SHT_NOBITS sections.
- Type: 0x6abcdef0
Offset: 0x2004
Sections:
- Section: .data
- Section: .nobits1
- Section: .nobits2

## Test the "Offset" property.

## Check that by default the p_offset field of a segment is set to the
## offset of the section with the minimum offset.
# RUN: yaml2obj --docnum=2 %s -o %t2
# RUN: llvm-readelf %t2 --sections --program-headers | \
# RUN: FileCheck %s --check-prefixes=DEFAULT-OFFSET

# DEFAULT-OFFSET: [Nr] Name Type Address Off
# DEFAULT-OFFSET: [ 1] .foo PROGBITS 0000000000001000 0000b0
# DEFAULT-OFFSET-NEXT: [ 2] .bar PROGBITS 0000000000001001 0000b1

# DEFAULT-OFFSET: Type Offset
# DEFAULT-OFFSET-NEXT: LOAD 0x0000b0
# DEFAULT-OFFSET-NEXT: LOAD 0x0000b1

--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
Sections:
- Name: .foo
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC ]
Size: 0x1
Address: 0x1000
- Name: .bar
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC ]
Size: 0x1
ProgramHeaders:
- Type: PT_LOAD
Sections:
- Section: .foo
- Section: .bar
- Type: PT_LOAD
Sections:
- Section: .bar

## Check we can set the "Offset" value explicitly to be less than or equal to
## the offset of a section in the segment.
# RUN: yaml2obj --docnum=3 -DOFFSET=0x77 %s -o %t3
# RUN: llvm-readelf %t3 --sections --program-headers | \
# RUN: FileCheck %s --check-prefixes=VALID-OFFSET,VALID-OFFSET-LESS
# RUN: yaml2obj --docnum=3 -DOFFSET=0x78 %s -o %t4
# RUN: llvm-readelf %t4 --sections --program-headers | \
# RUN: FileCheck %s --check-prefixes=VALID-OFFSET,VALID-OFFSET-EQ

# VALID-OFFSET: [Nr] Name Type Address Off
# VALID-OFFSET: [ 1] .foo PROGBITS 0000000000000000 000078

# VALID-OFFSET: Type Offset
# VALID-OFFSET-EQ: LOAD 0x000078
# VALID-OFFSET-LESS: LOAD 0x000077

--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
Sections:
- Name: .foo
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC ]
Size: 0x1
ProgramHeaders:
- Type: PT_LOAD
Offset: [[OFFSET]]
Sections:
- Section: .foo

## Check we report an error when the "Offset" value is larger than the offset of a section in the segment.
# RUN: not yaml2obj --docnum=3 -DOFFSET=0x79 %s -o /dev/null 2>&1 | \
# RUN: FileCheck %s --check-prefix=INVALID-OFFSET

# INVALID-OFFSET: yaml2obj: error: 'Offset' for segment with index 1 must be less than or equal to the minimum file offset of all included sections (0x78)

## Document that the "Offset" value is checked after the section offset is overriden using "ShOffset".
# RUN: yaml2obj --docnum=4 %s -o %t5
# RUN: llvm-readelf %t5 --sections --program-headers | FileCheck %s --check-prefix=SHOFFSET

# SHOFFSET: [Nr] Name Type Address Off
# SHOFFSET: [ 1] .foo PROGBITS 0000000000000000 ffffffff

# SHOFFSET: Type Offset
# SHOFFSET-NEXT: LOAD 0xffffff00

--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
Sections:
- Name: .foo
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC ]
Size: 0x1
## Note: the real .foo offset is much less than 0xFFFFFFFF or
## 0xFFFFFF00, but no error is reported.
ShOffset: 0xFFFFFFFF
ProgramHeaders:
- Type: PT_LOAD
Offset: 0xFFFFFF00
Sections:
- Section: .foo

0 comments on commit 2bf5674

Please sign in to comment.