From: Vedant Kumar Date: Tue, 3 Sep 2019 22:23:14 +0000 (+0000) Subject: [InstrProf] Tighten a check for malformed data records in raw profiles X-Git-Tag: llvmorg-11-init~10138 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=95fb23ab37e5e348788bb34623ebdc1e583e1ec8;p=platform%2Fupstream%2Fllvm.git [InstrProf] Tighten a check for malformed data records in raw profiles The check needs to validate a counter offset before performing pointer arithmetic with the (potentially corrupt) offset. Found by UBSan's pointer overflow check. rdar://54843625 Differential Revision: https://reviews.llvm.org/D66979 llvm-svn: 370826 --- diff --git a/llvm/include/llvm/ProfileData/InstrProfReader.h b/llvm/include/llvm/ProfileData/InstrProfReader.h index 73751fa..3eb84a8 100644 --- a/llvm/include/llvm/ProfileData/InstrProfReader.h +++ b/llvm/include/llvm/ProfileData/InstrProfReader.h @@ -268,8 +268,14 @@ private: return (const char *)ValueDataStart; } - const uint64_t *getCounter(IntPtrT CounterPtr) const { - ptrdiff_t Offset = (swap(CounterPtr) - CountersDelta) / sizeof(uint64_t); + /// Get the offset of \p CounterPtr from the start of the counters section of + /// the profile. The offset has units of "number of counters", i.e. increasing + /// the offset by 1 corresponds to an increase in the *byte offset* by 8. + ptrdiff_t getCounterOffset(IntPtrT CounterPtr) const { + return (swap(CounterPtr) - CountersDelta) / sizeof(uint64_t); + } + + const uint64_t *getCounter(ptrdiff_t Offset) const { return CountersStart + Offset; } diff --git a/llvm/lib/ProfileData/InstrProfReader.cpp b/llvm/lib/ProfileData/InstrProfReader.cpp index b97601c..5fb1d94 100644 --- a/llvm/lib/ProfileData/InstrProfReader.cpp +++ b/llvm/lib/ProfileData/InstrProfReader.cpp @@ -413,13 +413,19 @@ Error RawInstrProfReader::readRawCounts( if (NumCounters == 0) return error(instrprof_error::malformed); - auto RawCounts = makeArrayRef(getCounter(CounterPtr), NumCounters); auto *NamesStartAsCounter = reinterpret_cast(NamesStart); + ptrdiff_t MaxNumCounters = NamesStartAsCounter - CountersStart; - // Check bounds. - if (RawCounts.data() < CountersStart || - RawCounts.data() + RawCounts.size() > NamesStartAsCounter) + // Check bounds. Note that the counter pointer embedded in the data record + // may itself be corrupt. + if (NumCounters > MaxNumCounters) return error(instrprof_error::malformed); + ptrdiff_t CounterOffset = getCounterOffset(CounterPtr); + if (CounterOffset < 0 || CounterOffset > MaxNumCounters || + (CounterOffset + NumCounters) > MaxNumCounters) + return error(instrprof_error::malformed); + + auto RawCounts = makeArrayRef(getCounter(CounterOffset), NumCounters); if (ShouldSwapBytes) { Record.Counts.clear(); diff --git a/llvm/test/tools/llvm-profdata/Inputs/malformed-ptr-to-counter-array.profraw b/llvm/test/tools/llvm-profdata/Inputs/malformed-ptr-to-counter-array.profraw new file mode 100644 index 0000000..72fddd7 Binary files /dev/null and b/llvm/test/tools/llvm-profdata/Inputs/malformed-ptr-to-counter-array.profraw differ diff --git a/llvm/test/tools/llvm-profdata/malformed-ptr-to-counter-array.test b/llvm/test/tools/llvm-profdata/malformed-ptr-to-counter-array.test new file mode 100644 index 0000000..24a68e3 --- /dev/null +++ b/llvm/test/tools/llvm-profdata/malformed-ptr-to-counter-array.test @@ -0,0 +1,5 @@ +REQUIRES: zlib + +RUN: not llvm-profdata merge -o /dev/null %p/Inputs/malformed-ptr-to-counter-array.profraw 2>&1 | FileCheck %s + +CHECK: Malformed instrumentation profile data