Files
cmake/Tests/Fuzzing/corpus/elf/generate.py
T
Leslie P. Polzer 8535a7963c Tests/Fuzzing: Add CMake_BUILD_FUZZING option and build infrastructure
Add infrastructure for building fuzz testing targets with libFuzzer or
other fuzzing engines (e.g., OSS-Fuzz's LIB_FUZZING_ENGINE).

Features:
- CMake_BUILD_FUZZING option in root CMakeLists.txt
- Fuzzing/CMakeLists.txt with add_fuzzer() macro
- Support for libFuzzer and external fuzzing engines
- Documentation in Tests/Fuzzing/README.rst

The infrastructure is opt-in and requires a compatible fuzzing engine.
If CMake_BUILD_FUZZING is enabled but no engine is found, configuration
fails with a clear error message.

See Tests/Fuzzing/README.rst for build instructions.
2026-01-20 14:06:25 -05:00

110 lines
3.8 KiB
Python
Executable File

#!/usr/bin/env python3
"""Generate minimal ELF corpus files for fuzzing.
These are hand-crafted minimal ELF headers that exercise the ELF parser
without requiring actual compiled binaries. They contain just enough
structure to be recognized as valid ELF files.
Usage: python3 generate.py
Output files can be verified with: file *.elf
"""
import os
import struct
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
def generate_minimal_elf64():
"""Generate a minimal 64-bit ELF executable header (72 bytes).
Structure: ELF64 header (64 bytes) with e_type=ET_EXEC, e_machine=EM_X86_64,
plus 8 bytes padding for fuzzer mutation headroom.
"""
elf = bytearray()
# e_ident[16]: ELF identification
elf.extend(b'\x7fELF') # EI_MAG: magic number
elf.append(2) # EI_CLASS: ELFCLASS64
elf.append(1) # EI_DATA: ELFDATA2LSB (little-endian)
elf.append(1) # EI_VERSION: EV_CURRENT
elf.append(0) # EI_OSABI: ELFOSABI_NONE
elf.extend(b'\x00' * 8) # EI_PAD: padding
# ELF header fields
elf.extend(struct.pack('<H', 2)) # e_type: ET_EXEC
elf.extend(struct.pack('<H', 0x3e)) # e_machine: EM_X86_64
elf.extend(struct.pack('<I', 1)) # e_version: EV_CURRENT
elf.extend(struct.pack('<Q', 0)) # e_entry: entry point
elf.extend(struct.pack('<Q', 0)) # e_phoff: program header offset
elf.extend(struct.pack('<Q', 0)) # e_shoff: section header offset
elf.extend(struct.pack('<I', 0)) # e_flags
elf.extend(struct.pack('<H', 0)) # e_ehsize
elf.extend(struct.pack('<H', 0)) # e_phentsize
elf.extend(struct.pack('<H', 0)) # e_phnum
elf.extend(struct.pack('<H', 0)) # e_shentsize
elf.extend(struct.pack('<H', 0)) # e_shnum
elf.extend(struct.pack('<H', 0)) # e_shstrndx
# Padding for fuzzer mutation headroom
elf.extend(b'\x00' * 8)
return bytes(elf)
def generate_minimal_elf32():
"""Generate a minimal 32-bit ELF PIE header (60 bytes).
Structure: ELF32 header (52 bytes) with e_type=ET_DYN, e_machine=EM_386,
plus 8 bytes padding for fuzzer mutation headroom.
"""
elf = bytearray()
# e_ident[16]: ELF identification
elf.extend(b'\x7fELF') # EI_MAG: magic number
elf.append(1) # EI_CLASS: ELFCLASS32
elf.append(1) # EI_DATA: ELFDATA2LSB (little-endian)
elf.append(1) # EI_VERSION: EV_CURRENT
elf.append(0) # EI_OSABI: ELFOSABI_NONE
elf.extend(b'\x00' * 8) # EI_PAD: padding
# ELF header fields
elf.extend(struct.pack('<H', 3)) # e_type: ET_DYN (PIE)
elf.extend(struct.pack('<H', 3)) # e_machine: EM_386
elf.extend(struct.pack('<I', 1)) # e_version: EV_CURRENT
elf.extend(struct.pack('<I', 0)) # e_entry: entry point
elf.extend(struct.pack('<I', 0)) # e_phoff: program header offset
elf.extend(struct.pack('<I', 0)) # e_shoff: section header offset
elf.extend(struct.pack('<I', 0)) # e_flags
elf.extend(struct.pack('<H', 0)) # e_ehsize
elf.extend(struct.pack('<H', 0)) # e_phentsize
elf.extend(struct.pack('<H', 0)) # e_phnum
elf.extend(struct.pack('<H', 0)) # e_shentsize
elf.extend(struct.pack('<H', 0)) # e_shnum
elf.extend(struct.pack('<H', 0)) # e_shstrndx
# Padding for fuzzer mutation headroom
elf.extend(b'\x00' * 8)
return bytes(elf)
def main():
os.chdir(SCRIPT_DIR)
elf64 = generate_minimal_elf64()
elf32 = generate_minimal_elf32()
with open('minimal64.elf', 'wb') as f:
f.write(elf64)
print(f"Generated minimal64.elf ({len(elf64)} bytes)")
with open('minimal32.elf', 'wb') as f:
f.write(elf32)
print(f"Generated minimal32.elf ({len(elf32)} bytes)")
if __name__ == '__main__':
main()