diff --git a/snapshot/elf/elf_image_reader.cc b/snapshot/elf/elf_image_reader.cc index 7c03a363..7f6d7c7e 100644 --- a/snapshot/elf/elf_image_reader.cc +++ b/snapshot/elf/elf_image_reader.cc @@ -22,6 +22,7 @@ #include #include "base/logging.h" +#include "base/numerics/safe_math.h" #include "build/build_config.h" #include "util/numeric/checked_vm_address_range.h" @@ -277,10 +278,24 @@ ElfImageReader::NoteReader::Result ElfImageReader::NoteReader::ReadNote( current_address_ += sizeof(note_info); constexpr size_t align = sizeof(note_info.n_namesz); -#define PAD(x) (((x) + align - 1) & ~(align - 1)) - size_t padded_namesz = PAD(note_info.n_namesz); - size_t padded_descsz = PAD(note_info.n_descsz); - size_t note_size = padded_namesz + padded_descsz; + +#define CHECKED_PAD(x, into) \ + base::CheckAnd(base::CheckAdd(x, align - 1), ~(align - 1)) \ + .AssignIfValid(&into) + + size_t padded_namesz; + if (!CHECKED_PAD(note_info.n_namesz, padded_namesz)) { + return Result::kError; + } + size_t padded_descsz; + if (!CHECKED_PAD(note_info.n_descsz, padded_descsz)) { + return Result::kError; + } + + size_t note_size; + if (!base::CheckAdd(padded_namesz, padded_descsz).AssignIfValid(¬e_size)) { + return Result::kError; + } // Notes typically have 4-byte alignment. However, .note.android.ident may // inadvertently use 2-byte alignment. @@ -289,9 +304,19 @@ ElfImageReader::NoteReader::Result ElfImageReader::NoteReader::ReadNote( // but there may be 4-byte aligned notes following it. If this note was // aligned at less than 4-bytes, expect that the next note will be aligned at // 4-bytes and add extra padding, if necessary. - VMAddress end_of_note = - std::min(PAD(current_address_ + note_size), segment_end_address_); -#undef PAD + + VMAddress end_of_note_candidate; + if (!base::CheckAdd(current_address_, note_size) + .AssignIfValid(&end_of_note_candidate)) { + return Result::kError; + } + VMAddress end_of_note; + if (!CHECKED_PAD(end_of_note_candidate, end_of_note)) { + return Result::kError; + } + end_of_note = std::min(end_of_note, segment_end_address_); + +#undef CHECKED_PAD if (note_size > max_note_size_) { current_address_ = end_of_note;