Fix incorrect range checks in elf image note reader

Overflows before and after padding could cause the max note size check
to be evaded.

Bug: chromium:967228, chromium: 967257, chromium:967223
Change-Id: I499a273e76e78529fc59ddcb74055be6d01fa2cb
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1631635
Reviewed-by: Joshua Peraza <jperaza@chromium.org>
Commit-Queue: Scott Graham <scottmg@chromium.org>
This commit is contained in:
Scott Graham 2019-05-27 10:26:15 -07:00 committed by Commit Bot
parent daf9f5669e
commit ee1d5124a2

View File

@ -22,6 +22,7 @@
#include <vector>
#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(&note_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;