Skip to content

Commit 305c36a

Browse files
committed
Sanitize ELF Sections API
ELF Sections are kinda 1-indexed in that while there is a Section 0, it is always of type SHT_NULL and is otherwise invalid to reference. Further, later ELF extensions have re-used these unused bits for extensions, notably for ELF files with more than 0xff00 sections. This patch does the following: - Prevents section 0 from being returned by "Sections", since it isn't actually a real section and treating it as such would be incorrect if the section header stores extension data (before it just doesn't make a difference) - As a result indices into `Sections` now actually match the ELF section number rather than being off by one. - For good measure, implement the ELF large sections extension and add a test to make sure we can handle a file with as many sections.
1 parent ee7b200 commit 305c36a

File tree

7 files changed

+196653
-12
lines changed

7 files changed

+196653
-12
lines changed

src/ELF/ELFHandle.jl

+6-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ function readmeta(io::IO, ::Type{H}) where {H <: ELFHandle}
3535
start = position(io)
3636

3737
# Check for magic bytes
38-
magic = [read(io, UInt8) for idx in 1:4]
38+
magic = [read(io, UInt8) for idx in 1:4]
3939
if any(magic .!= elven_magic)
4040
msg = """
4141
Magic Number 0x$(join(string.(magic, base=16),"")) does not match expected ELF
@@ -78,7 +78,11 @@ mangle_symbol_name(oh::ELFHandle, name::AbstractString) = name
7878
format_string(::Type{H}) where {H <: ELFHandle} = "ELF"
7979

8080
# Section information
81-
section_header_offset(oh::ELFHandle) = header(oh).e_shoff
81+
82+
# The section entry at index 0 is SHN_UNDEF of section type SHT_NULL. It is not
83+
# a real section and may actually contain extension data. Do not return it to
84+
# avoid confusion clients
85+
section_header_offset(oh::ELFHandle) = header(oh).e_shoff + section_header_size(oh)
8286
section_header_size(oh::ELFHandle) = header(oh).e_shentsize
8387
function section_header_type(oh::H) where {H <: ELFHandle}
8488
if is64bit(oh)

src/ELF/ELFSection.jl

+12-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,18 @@ Sections(oh::ELFHandle) = ELFSections(oh)
1717

1818
# Implement Sections API
1919
handle(sections::ELFSections) = sections.handle
20-
lastindex(sections::ELFSections) = header(handle(sections)).e_shnum
21-
20+
function lastindex(sections::ELFSections)
21+
head = header(handle(sections))
22+
head.e_shoff == 0 && return 0
23+
if head.e_shnum == 0
24+
# Large section extension. Number of sections is actually stored in the
25+
# sh_size field of the undef section
26+
seek(handle(sections), head.e_shoff)
27+
return unpack(handle(sections), section_header_type(handle(sections))).sh_size - 1
28+
end
29+
# Exclude the SHT_NULL section
30+
return head.e_shnum - 1
31+
end
2232

2333
"""
2434
ELFSection

src/ELF/ELFStrTab.jl

+10-3
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ struct ELFStrTab{H <: ELFHandle} <: StrTab{H}
2121
""")
2222
@warn(replace(msg, "\n" => " "), key=(handle(section), section_idx))
2323
end
24-
24+
2525
return new(section)
2626
end
2727
end
@@ -59,10 +59,17 @@ construct an `StrTab` object from. The returned value is an index (e.g. it is
5959
1-based, not zero-based as the value within the ELF object itself).
6060
"""
6161
function section_header_strtab_index(oh::ELFHandle)
62-
return header(oh).e_shstrndx + 1
62+
head = header(oh)
63+
if head.e_shoff != 0 && head.e_shnum == 0
64+
# ELF Large Sections extension. Actual strtab index is the sh_link
65+
# field of the SHN_UNDEF section
66+
seek(oh, head.e_shoff)
67+
return unpack(oh, section_header_type(oh)).sh_link
68+
end
69+
return head.e_shstrndx
6370
end
6471

6572
function strtab_lookup(strtab::ELFStrTab, index)
6673
seek(strtab.section_ref, index)
6774
return strip(readuntil(handle(strtab), '\0'), '\0')
68-
end
75+
end

0 commit comments

Comments
 (0)