Skip to content

Commit ff7a5be

Browse files
committed
Avoid memory corruption on invalid ELF input
Reject ELF data that would lead to invalid memory access or integer overflows.
1 parent 81c64dd commit ff7a5be

File tree

1 file changed

+52
-7
lines changed

1 file changed

+52
-7
lines changed

src/patchelf.cc

+52-7
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,25 @@ static void checkPointer(const FileContents & contents, const void * p, size_t s
243243
}
244244

245245

246+
static void checkOffset(const FileContents & contents, size_t offset, size_t size)
247+
{
248+
size_t end;
249+
250+
if (offset > contents->size()
251+
|| size > contents->size()
252+
|| __builtin_add_overflow(offset, size, &end)
253+
|| end > contents->size())
254+
error("data offset extends past file end");
255+
}
256+
257+
258+
static std::string extractString(const FileContents & contents, size_t offset, size_t size)
259+
{
260+
checkOffset(contents, offset, size);
261+
return { reinterpret_cast<const char *>(contents->data()) + offset, size };
262+
}
263+
264+
246265
template<ElfFileParams>
247266
ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents)
248267
: fileContents(fContents)
@@ -259,14 +278,34 @@ ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents)
259278
if (rdi(hdr()->e_type) != ET_EXEC && rdi(hdr()->e_type) != ET_DYN)
260279
error("wrong ELF type");
261280

262-
if (rdi(hdr()->e_phoff) + rdi(hdr()->e_phnum) * rdi(hdr()->e_phentsize) > fileContents->size())
263-
error("program header table out of bounds");
281+
{
282+
auto ph_offset = rdi(hdr()->e_phoff);
283+
auto ph_num = rdi(hdr()->e_phnum);
284+
auto ph_entsize = rdi(hdr()->e_phentsize);
285+
size_t ph_size, ph_end;
286+
287+
if (__builtin_mul_overflow(ph_num, ph_entsize, &ph_size)
288+
|| __builtin_add_overflow(ph_offset, ph_size, &ph_end)
289+
|| ph_end > fileContents->size()) {
290+
error("program header table out of bounds");
291+
}
292+
}
264293

265294
if (rdi(hdr()->e_shnum) == 0)
266295
error("no section headers. The input file is probably a statically linked, self-decompressing binary");
267296

268-
if (rdi(hdr()->e_shoff) + rdi(hdr()->e_shnum) * rdi(hdr()->e_shentsize) > fileContents->size())
269-
error("section header table out of bounds");
297+
{
298+
auto sh_offset = rdi(hdr()->e_shoff);
299+
auto sh_num = rdi(hdr()->e_shnum);
300+
auto sh_entsize = rdi(hdr()->e_shentsize);
301+
size_t sh_size, sh_end;
302+
303+
if (__builtin_mul_overflow(sh_num, sh_entsize, &sh_size)
304+
|| __builtin_add_overflow(sh_offset, sh_size, &sh_end)
305+
|| sh_end > fileContents->size()) {
306+
error("section header table out of bounds");
307+
}
308+
}
270309

271310
if (rdi(hdr()->e_phentsize) != sizeof(Elf_Phdr))
272311
error("program headers have wrong size");
@@ -295,7 +334,10 @@ ElfFile<ElfFileParamNames>::ElfFile(FileContents fContents)
295334
error("string table index out of bounds");
296335

297336
auto shstrtabSize = rdi(shdrs[shstrtabIndex].sh_size);
298-
char * shstrtab = (char * ) fileContents->data() + rdi(shdrs[shstrtabIndex].sh_offset);
337+
size_t shstrtabptr;
338+
if (__builtin_add_overflow(reinterpret_cast<size_t>(fileContents->data()), rdi(shdrs[shstrtabIndex].sh_offset), &shstrtabptr))
339+
error("string table overflow");
340+
const char *shstrtab = reinterpret_cast<const char *>(shstrtabptr);
299341
checkPointer(fileContents, shstrtab, shstrtabSize);
300342

301343
if (shstrtabSize == 0)
@@ -583,7 +625,7 @@ std::string & ElfFile<ElfFileParamNames>::replaceSection(const SectionName & sec
583625
s = std::string(i->second);
584626
} else {
585627
auto shdr = findSectionHeader(sectionName);
586-
s = std::string((char *) fileContents->data() + rdi(shdr.sh_offset), rdi(shdr.sh_size));
628+
s = extractString(fileContents, rdi(shdr.sh_offset), rdi(shdr.sh_size));
587629
}
588630

589631
s.resize(size);
@@ -1193,7 +1235,10 @@ template<ElfFileParams>
11931235
std::string ElfFile<ElfFileParamNames>::getInterpreter() const
11941236
{
11951237
auto shdr = findSectionHeader(".interp");
1196-
return std::string((const char *) fileContents->data() + rdi(shdr.sh_offset), rdi(shdr.sh_size) - 1);
1238+
auto size = rdi(shdr.sh_size);
1239+
if (size > 0)
1240+
size--;
1241+
return extractString(fileContents, rdi(shdr.sh_offset), size);
11971242
}
11981243

11991244
template<ElfFileParams>

0 commit comments

Comments
 (0)