From ff7a5beb000a06842fc046c81388e0e103255f3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Tue, 21 Feb 2023 19:41:11 +0100 Subject: Avoid memory corruption on invalid ELF input Reject ELF data that would lead to invalid memory access or integer overflows. --- src/patchelf.cc | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/src/patchelf.cc b/src/patchelf.cc index 7bfabb4..126cada 100644 --- a/src/patchelf.cc +++ b/src/patchelf.cc @@ -243,6 +243,25 @@ static void checkPointer(const FileContents & contents, const void * p, size_t s } +static void checkOffset(const FileContents & contents, size_t offset, size_t size) +{ + size_t end; + + if (offset > contents->size() + || size > contents->size() + || __builtin_add_overflow(offset, size, &end) + || end > contents->size()) + error("data offset extends past file end"); +} + + +static std::string extractString(const FileContents & contents, size_t offset, size_t size) +{ + checkOffset(contents, offset, size); + return { reinterpret_cast(contents->data()) + offset, size }; +} + + template ElfFile::ElfFile(FileContents fContents) : fileContents(fContents) @@ -259,14 +278,34 @@ ElfFile::ElfFile(FileContents fContents) if (rdi(hdr()->e_type) != ET_EXEC && rdi(hdr()->e_type) != ET_DYN) error("wrong ELF type"); - if (rdi(hdr()->e_phoff) + rdi(hdr()->e_phnum) * rdi(hdr()->e_phentsize) > fileContents->size()) - error("program header table out of bounds"); + { + auto ph_offset = rdi(hdr()->e_phoff); + auto ph_num = rdi(hdr()->e_phnum); + auto ph_entsize = rdi(hdr()->e_phentsize); + size_t ph_size, ph_end; + + if (__builtin_mul_overflow(ph_num, ph_entsize, &ph_size) + || __builtin_add_overflow(ph_offset, ph_size, &ph_end) + || ph_end > fileContents->size()) { + error("program header table out of bounds"); + } + } if (rdi(hdr()->e_shnum) == 0) error("no section headers. The input file is probably a statically linked, self-decompressing binary"); - if (rdi(hdr()->e_shoff) + rdi(hdr()->e_shnum) * rdi(hdr()->e_shentsize) > fileContents->size()) - error("section header table out of bounds"); + { + auto sh_offset = rdi(hdr()->e_shoff); + auto sh_num = rdi(hdr()->e_shnum); + auto sh_entsize = rdi(hdr()->e_shentsize); + size_t sh_size, sh_end; + + if (__builtin_mul_overflow(sh_num, sh_entsize, &sh_size) + || __builtin_add_overflow(sh_offset, sh_size, &sh_end) + || sh_end > fileContents->size()) { + error("section header table out of bounds"); + } + } if (rdi(hdr()->e_phentsize) != sizeof(Elf_Phdr)) error("program headers have wrong size"); @@ -295,7 +334,10 @@ ElfFile::ElfFile(FileContents fContents) error("string table index out of bounds"); auto shstrtabSize = rdi(shdrs[shstrtabIndex].sh_size); - char * shstrtab = (char * ) fileContents->data() + rdi(shdrs[shstrtabIndex].sh_offset); + size_t shstrtabptr; + if (__builtin_add_overflow(reinterpret_cast(fileContents->data()), rdi(shdrs[shstrtabIndex].sh_offset), &shstrtabptr)) + error("string table overflow"); + const char *shstrtab = reinterpret_cast(shstrtabptr); checkPointer(fileContents, shstrtab, shstrtabSize); if (shstrtabSize == 0) @@ -583,7 +625,7 @@ std::string & ElfFile::replaceSection(const SectionName & sec s = std::string(i->second); } else { auto shdr = findSectionHeader(sectionName); - s = std::string((char *) fileContents->data() + rdi(shdr.sh_offset), rdi(shdr.sh_size)); + s = extractString(fileContents, rdi(shdr.sh_offset), rdi(shdr.sh_size)); } s.resize(size); @@ -1193,7 +1235,10 @@ template std::string ElfFile::getInterpreter() const { auto shdr = findSectionHeader(".interp"); - return std::string((const char *) fileContents->data() + rdi(shdr.sh_offset), rdi(shdr.sh_size) - 1); + auto size = rdi(shdr.sh_size); + if (size > 0) + size--; + return extractString(fileContents, rdi(shdr.sh_offset), size); } template -- cgit v1.2.1