mirror of
https://github.com/vee1e/flare-floss.git
synced 2026-09-01 17:57:06 +00:00
Rename test_qs_* to names that match layout/tags/ranges scope after QuantumStrand removal (test_layout_*, test_oss_db, test_ranges, etc.).
106 lines
3.8 KiB
Python
106 lines
3.8 KiB
Python
# Copyright 2026 Google LLC
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
from pathlib import Path
|
|
|
|
from floss.layout import compute_layout
|
|
from floss.ranges import Slice
|
|
from floss.layout.base import ELFLayout, SegmentLayout
|
|
|
|
CD = Path(__file__).resolve().parent
|
|
ELF_DIR = CD / "data" / "elf"
|
|
|
|
# x86-64 Position Independent Executable (PIE), dynamically linked, not stripped
|
|
X86_64_PIE = "055da8e6ccfe5a9380231ea04b850e18.elf"
|
|
# ARM64 shared object, dynamically linked, stripped, Android linker
|
|
ARM64_SO = "687e79cde5b0ced75ac229465835054931f9ec438816f2827a8be5f3bd474929.elf"
|
|
# ARM64 PIE, dynamically linked, stripped
|
|
ARM64_LS = "ls"
|
|
|
|
|
|
def _load_layout(name: str):
|
|
path = ELF_DIR / name
|
|
data = path.read_bytes()
|
|
return compute_layout(Slice.from_bytes(data))
|
|
|
|
|
|
def test_elf_layout():
|
|
layout = _load_layout(X86_64_PIE)
|
|
assert isinstance(layout, ELFLayout)
|
|
assert layout.name == "elf"
|
|
assert layout.children
|
|
text_sections = [c for c in layout.children if c.name == ".text"]
|
|
assert len(text_sections) == 1
|
|
assert text_sections[0].offset == 0x10A0
|
|
assert text_sections[0].slice.range.length == 0x1C5
|
|
|
|
|
|
def test_elf_section_names():
|
|
# x86-64, not stripped: executable code section, dynamic string table, and symbol table all present
|
|
layout = _load_layout(X86_64_PIE)
|
|
names = {child.name for child in layout.children}
|
|
assert ".text" in names
|
|
assert ".dynstr" in names
|
|
assert ".symtab" in names
|
|
|
|
|
|
def test_elf_structures_present():
|
|
layout = _load_layout(X86_64_PIE)
|
|
assert layout.structures_by_address[0x0].name == "elf header"
|
|
assert layout.structures_by_address[0x40].name == "program header"
|
|
assert layout.structures_by_address[0x39D0].name == "section header"
|
|
assert layout.structures_by_address[0x3C8].name == "symbol table" # .dynsym
|
|
assert layout.structures_by_address[0x4A0].name == "string table" # .dynstr
|
|
|
|
|
|
def test_elf_code_and_reloc_offsets():
|
|
layout = _load_layout(X86_64_PIE)
|
|
# .text (offset 0x10a0, size 0x1c5) is fully covered by code ranges;
|
|
# it merges with adjacent exec sections (.plt etc.) so we check coverage, not exact range
|
|
assert layout.code_offsets.overlaps(0x10A0, 0x10A0 + 0x1C5 - 1)
|
|
assert (0x568, 0x66F) in layout.relocation_offsets.ranges # .rela.dyn + .rela.plt merged
|
|
|
|
|
|
def test_arm64_so_android_note_section():
|
|
# Android shared object has an Android-specific note section absent from standard Linux ELFs
|
|
layout = _load_layout(ARM64_SO)
|
|
names = {child.name for child in layout.children}
|
|
assert ".note.android.ident" in names
|
|
|
|
|
|
def test_arm64_ls_stripped():
|
|
# stripped binary has no symbol table
|
|
layout = _load_layout(ARM64_LS)
|
|
names = {child.name for child in layout.children}
|
|
assert ".symtab" not in names
|
|
|
|
|
|
def test_elf_segment_fallback():
|
|
# Test fallback to segments when section headers are missing/corrupted
|
|
path = ELF_DIR / X86_64_PIE
|
|
data = bytearray(path.read_bytes())
|
|
|
|
# Verify ELFCLASS64
|
|
assert data[4] == 2
|
|
# Corrupt e_shoff (set 8 bytes at offset 40 to 0)
|
|
data[40:48] = b"\x00" * 8
|
|
# Corrupt e_shnum (set 2 bytes at offset 60 to 0)
|
|
data[60:62] = b"\x00\x00"
|
|
|
|
layout = compute_layout(Slice.from_bytes(bytes(data)))
|
|
assert isinstance(layout, ELFLayout)
|
|
assert layout.children
|
|
for child in layout.children:
|
|
assert isinstance(child, SegmentLayout)
|
|
assert child.name.startswith("segment_")
|