* src/elflint.c (check_program_header): - PT_PHDR may not occur more than once - PT_INTERP must precede any loadable segment entry - PT_LOAD entries must be sorted on the p_vaddr member
Signed-off-by: Fabian Rast <[email protected]> --- src/elflint.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/elflint.c b/src/elflint.c index f47593df..3b4da4fd 100644 --- a/src/elflint.c +++ b/src/elflint.c @@ -4568,6 +4568,9 @@ only executables, shared objects, and core files can have program headers\n")); int num_pt_interp = 0; int num_pt_tls = 0; int num_pt_relro = 0; + int num_pt_phdr = 0; + size_t prev_pt_load_vaddr = 0; + bool pt_load_sorted = true; for (unsigned int cnt = 0; cnt < phnum; ++cnt) { @@ -4592,7 +4595,17 @@ program header entry %d: unknown program header entry type %#" PRIx64 "\n"), cnt, (uint64_t) phdr->p_type); if (phdr->p_type == PT_LOAD) - has_loadable_segment = true; + { + if (has_loadable_segment && pt_load_sorted + && prev_pt_load_vaddr >= phdr->p_vaddr) + { + ERROR (_("LOAD segments not sorted by vaddr\n")); + pt_load_sorted = false; + } + else + prev_pt_load_vaddr = phdr->p_vaddr; + has_loadable_segment = true; + } else if (phdr->p_type == PT_INTERP) { if (++num_pt_interp != 1) @@ -4601,6 +4614,9 @@ program header entry %d: unknown program header entry type %#" PRIx64 "\n"), ERROR (_("\ more than one INTERP entry in program header\n")); } + else if (has_loadable_segment) + ERROR (_("\ +INTERP entry is preceded by a loadable segment in program header\n")); has_interp_segment = true; } else if (phdr->p_type == PT_TLS) @@ -4694,7 +4710,13 @@ GNU_RELRO [%u] flags are not a subset of the loadable segment [%u] flags\n"), } else if (phdr->p_type == PT_PHDR) { - /* Check that the region is in a writable segment. */ + if (++num_pt_phdr != 1) + { + if (num_pt_phdr == 2) + ERROR (_("\ +more than one PHDR entry in program header\n")); + } + /* Check that the region is in a loaded segment. */ unsigned int inner; for (inner = 0; inner < phnum; ++inner) { -- 2.53.0 Relevant links to the specification: - PT_PHDR may not occur more than once: https://gabi.xinuos.com/elf/07-pheader.html#program-header-entry:~:text=This%20segment%20type%20may%20not%20occur%20more%20than%20once%20in%20a%20file%2E - PT_INTERP must precede any loadable segment entry: https://gabi.xinuos.com/elf/07-pheader.html#program-header-entry:~:text=If%20it%20is%20present%2C%20it%20must%20precede%20any%20loadable%20segment%20entry%2E - PT_LOAD entries must be sorted on the p_vaddr member: https://gabi.xinuos.com/elf/07-pheader.html#program-header-entry:~:text=Loadable%20segment%20entries%20in%20the%20program%20header%20table%20appear%20in%20ascending%20order%2C%20sorted%20on%20the%20p%5Fvaddr%20member The links refer to the 4.3 draft spec, but all of this is not new and also included in version 4.2 (https://gabi.xinuos.com/v42/elf/07-pheader.html#segment-types) and previous versions. Cheers, Fabian
signature.asc
Description: PGP signature
