diff --git a/include/debug_logger.h b/include/debug_logger.h index 1360a93a183eeec0359bcdb54004f81305b31484..8dc7ff1b3d057a90f608cbc88f35e09afa009b32 100644 --- a/include/debug_logger.h +++ b/include/debug_logger.h @@ -287,6 +287,14 @@ private: #define HLOG_ASSERT(condition) HLOG_ASSERT_MESSAGE(condition, "") #endif +#ifndef HIPERF_ASSERT +#define HIPERF_ASSERT(condition, format, ...) \ + if (!(condition)) [[unlikely]] { \ + printf(format, ##__VA_ARGS__); \ + exit(-1); \ + } +#endif + #undef assert #else #define HLOGDUMMY(...) \ diff --git a/src/perf_event_record.cpp b/src/perf_event_record.cpp index c83aeea66e60736230a457fca9587b5a9dc16aa6..5d0ed8cd9a072237242333c7005336ba9e308f77 100644 --- a/src/perf_event_record.cpp +++ b/src/perf_event_record.cpp @@ -89,25 +89,36 @@ inline void PushToBinary2(bool condition, uint8_t *&p, const T1 &v1, const T2 &v } template -inline void PopFromBinary(bool condition, uint8_t *&p, T &v) +inline void PopFromBinary(bool condition, uint8_t*& p, T& v, u64& size) { + HIPERF_ASSERT(sizeof(T) <= size, "PopFromBinary error\n"); if (condition) { v = *(reinterpret_cast(p)); p += sizeof(T); + size -= sizeof(T); } } template -inline void PopFromBinary2(bool condition, uint8_t *&p, T1 &v1, T2 &v2) +inline void PopFromBinary2(bool condition, uint8_t*& p, T1& v1, T2& v2, u64& size) { + HIPERF_ASSERT(sizeof(T1) + sizeof(T2) <= size, "PopFromBinary2 error\n"); if (condition) { v1 = *(reinterpret_cast(p)); p += sizeof(T1); v2 = *(reinterpret_cast(p)); p += sizeof(T2); + size -= (sizeof(T1) + sizeof(T2)); } } +inline void SetPointerOffset(uint8_t*& p, u64 offset, u64& size) +{ + HIPERF_ASSERT(offset <= size, "SetPointerOffset error\n"); + size -= offset; + p += offset; +} + // PerfEventRecord void PerfEventRecord::Init(perf_event_type type, bool inKernel) { @@ -347,56 +358,57 @@ void PerfRecordSample::Init(uint8_t *p, const perf_event_attr &attr) removeStack_ = false; data_ = {}; uint8_t *start = p; - p += sizeof(header_); + u64 dataSize = static_cast(RECORD_SIZE_LIMIT); + SetPointerOffset(p, sizeof(header_), dataSize); // parse record according SAMPLE_TYPE - PopFromBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id); - PopFromBinary(sampleType_ & PERF_SAMPLE_IP, p, data_.ip); - PopFromBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.pid, data_.tid); - PopFromBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.time); - PopFromBinary(sampleType_ & PERF_SAMPLE_ADDR, p, data_.addr); - PopFromBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.id); - PopFromBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.stream_id); - PopFromBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.cpu, data_.res); - PopFromBinary(sampleType_ & PERF_SAMPLE_PERIOD, p, data_.period); - PopFromBinary(sampleType_ & PERF_SAMPLE_CALLCHAIN, p, data_.nr); + PopFromBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id, dataSize); + PopFromBinary(sampleType_ & PERF_SAMPLE_IP, p, data_.ip, dataSize); + PopFromBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.pid, data_.tid, dataSize); + PopFromBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.time, dataSize); + PopFromBinary(sampleType_ & PERF_SAMPLE_ADDR, p, data_.addr, dataSize); + PopFromBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.id, dataSize); + PopFromBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.stream_id, dataSize); + PopFromBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.cpu, data_.res, dataSize); + PopFromBinary(sampleType_ & PERF_SAMPLE_PERIOD, p, data_.period, dataSize); + PopFromBinary(sampleType_ & PERF_SAMPLE_CALLCHAIN, p, data_.nr, dataSize); if (data_.nr > 0) { // the pointer is from input(p), require caller keep input(p) with *this together // think it in next time data_.ips = reinterpret_cast(p); - p += data_.nr * sizeof(u64); + SetPointerOffset(p, data_.nr * sizeof(u64), dataSize); } - PopFromBinary(sampleType_ & PERF_SAMPLE_RAW, p, data_.raw_size); + PopFromBinary(sampleType_ & PERF_SAMPLE_RAW, p, data_.raw_size, dataSize); if (data_.raw_size > 0) { data_.raw_data = p; - p += data_.raw_size * sizeof(u8); + SetPointerOffset(p, data_.raw_size * sizeof(u8), dataSize); } - PopFromBinary(sampleType_ & PERF_SAMPLE_BRANCH_STACK, p, data_.bnr); + PopFromBinary(sampleType_ & PERF_SAMPLE_BRANCH_STACK, p, data_.bnr, dataSize); if (data_.bnr > 0) { data_.lbr = reinterpret_cast(p); - p += data_.bnr * sizeof(PerfBranchEntry); + SetPointerOffset(p, data_.bnr * sizeof(PerfBranchEntry), dataSize); } - PopFromBinary(sampleType_ & PERF_SAMPLE_REGS_USER, p, data_.user_abi); + PopFromBinary(sampleType_ & PERF_SAMPLE_REGS_USER, p, data_.user_abi, dataSize); if (data_.user_abi > 0) { data_.reg_mask = attr.sample_regs_user; data_.reg_nr = __builtin_popcountll(data_.reg_mask); data_.user_regs = reinterpret_cast(p); - p += data_.reg_nr * sizeof(u64); + SetPointerOffset(p, data_.reg_nr * sizeof(u64), dataSize); } - PopFromBinary(sampleType_ & PERF_SAMPLE_SERVER_PID, p, data_.server_nr); + PopFromBinary(sampleType_ & PERF_SAMPLE_SERVER_PID, p, data_.server_nr, dataSize); if (data_.server_nr > 0) { data_.server_pids = reinterpret_cast(p); - p += data_.server_nr * sizeof(u64); + SetPointerOffset(p, data_.server_nr * sizeof(u64), dataSize); } - PopFromBinary(sampleType_ & PERF_SAMPLE_STACK_USER, p, data_.stack_size); + PopFromBinary(sampleType_ & PERF_SAMPLE_STACK_USER, p, data_.stack_size, dataSize); if (data_.stack_size > 0) { data_.stack_data = p; - p += data_.stack_size; - PopFromBinary(true, p, data_.dyn_size); + SetPointerOffset(p, data_.stack_size, dataSize); + PopFromBinary(true, p, data_.dyn_size, dataSize); } uint32_t remain = header_.size - (p - start); if (data_.nr == 0 && dumpRemoveStack_ && remain == sizeof(stackId_)) { - PopFromBinary(true, p, stackId_.value); + PopFromBinary(true, p, stackId_.value, dataSize); } } diff --git a/src/perf_file_format.cpp b/src/perf_file_format.cpp index d94dca495d64a8a32236090ccabc3880da804977..4dcbb9e5b9befd46f5df787c3f9c86e02a79807d 100644 --- a/src/perf_file_format.cpp +++ b/src/perf_file_format.cpp @@ -35,6 +35,7 @@ static const std::vector FEATURE_NAMES = { "branch_stack", "pmu_mappings", "group_desc", "auxtrace", "stat", "cache", "sample_time", "mem_topology", "last_feature", }; +static constexpr size_t MAX_VECTOR_RESIZE_COUNT = 100000; #ifdef FUZZER_TEST // issue from fuzz test and also will lead to PerfFileSectionSymbolsFiles uncompletely construct static constexpr size_t MAX_SYMBOLS_FILE_NUMBER = 300; @@ -500,6 +501,7 @@ PerfFileSectionEventDesc::PerfFileSectionEventDesc(FEATURE id, const char *buf, HLOGW("nrIds is too large ! %u", nrIds); } CHECK_TRUE(!Read(eventDesc.name), NO_RETVAL, 0, ""); + HIPERF_ASSERT(nrIds <= MAX_VECTOR_RESIZE_COUNT, "nrIds exceeds 100000\n"); eventDesc.ids.resize(nrIds, 0); CHECK_TRUE(!Read(reinterpret_cast(eventDesc.ids.data()), sizeof(uint64_t) * nrIds), NO_RETVAL, 0, ""); eventDesces_.emplace_back(std::move(eventDesc)); diff --git a/test/unittest/common/native/perf_event_record_test.cpp b/test/unittest/common/native/perf_event_record_test.cpp index 6062da6ba12e46497f2306dfb9cbaaee5842323b..d6e0369c5de7421a74ec7cba92228a396566f153 100644 --- a/test/unittest/common/native/perf_event_record_test.cpp +++ b/test/unittest/common/native/perf_event_record_test.cpp @@ -857,7 +857,31 @@ HWTEST_F(PerfEventRecordTest, CreatePerfRecordAuxtrace, TestSize.Level1) record.Init(p); ASSERT_NE(record.rawData_, nullptr); - free(p); + free(p); +} + +HWTEST_F(PerfEventRecordTest, CreatePerfRecordSample, TestSize.Level1) +{ + pid_t pid = fork(); + ASSERT_NE(pid, -1); + + if (pid == 0) { + PerfRecordSample record; + perf_event_attr attr = {}; + attr.sample_type = PERF_SAMPLE_CALLCHAIN + PERF_SAMPLE_RAW + PERF_SAMPLE_BRANCH_STACK + PERF_SAMPLE_REGS_USER; + std::vector data = {}; + data.resize(200); + for (auto i = 0; i < 200; i++) { + data[i] = UINT8_MAX; + } + record.Init(data.data(), attr); + _exit(-2); + } else { + int status = 0; + waitpid(pid, &status, 0); + ASSERT_TRUE(WIFEXITED(status)); + EXPECT_EQ(WEXITSTATUS(status), static_cast(-1)); + } } } // namespace HiPerf } // namespace Developtools diff --git a/test/unittest/common/native/perf_file_format_test.cpp b/test/unittest/common/native/perf_file_format_test.cpp index 1b97e06c53608eaf054b1da1db4ad049fbecd3d1..7bd649e296978d20046a64d422c2237d9fd2d602 100644 --- a/test/unittest/common/native/perf_file_format_test.cpp +++ b/test/unittest/common/native/perf_file_format_test.cpp @@ -249,6 +249,40 @@ HWTEST_F(PerfFileFormatTest, PerfFileSectionEventDesc, TestSize.Level1) CompareEventDesc(eventDesc, eventDescOut); ASSERT_EQ(withBuff.featureId_, FEATURE::EVENT_DESC); } + +HWTEST_F(PerfFileFormatTest, PerfFileSectionEventDesc2, TestSize.Level1) +{ + pid_t pid = fork(); + ASSERT_NE(pid, -1); + + if (pid == 0) { + char buff[BIGK] = {0}; + buff[0] = 1; + buff[4] = sizeof(perf_event_attr); + for (uint32_t i = 8; i < BIGK; i += 4) { + buff[i] = 0; + } + // data for nrId + buff[sizeof(perf_event_attr) + 8] = 0x7f; + buff[sizeof(perf_event_attr) + 9] = 0x7f; + buff[sizeof(perf_event_attr) + 10] = 0x7f; + buff[sizeof(perf_event_attr) + 11] = 0x7f; + + // data for size of eventDesc.name + buff[sizeof(perf_event_attr) + 12] = 0x02; + buff[sizeof(perf_event_attr) + 13] = 0x00; + buff[sizeof(perf_event_attr) + 14] = 0x00; + buff[sizeof(perf_event_attr) + 15] = 0x00; + + PerfFileSectionEventDesc(FEATURE::EVENT_DESC, buff, sizeof(buff)); + _exit(-2); + } else { + int status = 0; + waitpid(pid, &status, 0); + ASSERT_TRUE(WIFEXITED(status)); + EXPECT_EQ(WEXITSTATUS(status), static_cast(-1)); + } +} } // namespace HiPerf } // namespace Developtools } // namespace OHOS