hwasan_report.cpp revision 360784
1195534Sscottl//===-- hwasan_report.cpp -------------------------------------------------===// 2195534Sscottl// 3195534Sscottl// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4195534Sscottl// See https://llvm.org/LICENSE.txt for license information. 5195534Sscottl// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6195534Sscottl// 7195534Sscottl//===----------------------------------------------------------------------===// 8195534Sscottl// 9195534Sscottl// This file is a part of HWAddressSanitizer. 10195534Sscottl// 11195534Sscottl// Error reporting. 12195534Sscottl//===----------------------------------------------------------------------===// 13195534Sscottl 14195534Sscottl#include "hwasan.h" 15195534Sscottl#include "hwasan_allocator.h" 16195534Sscottl#include "hwasan_mapping.h" 17195534Sscottl#include "hwasan_report.h" 18195534Sscottl#include "hwasan_thread.h" 19195534Sscottl#include "hwasan_thread_list.h" 20195534Sscottl#include "sanitizer_common/sanitizer_allocator_internal.h" 21195534Sscottl#include "sanitizer_common/sanitizer_common.h" 22195534Sscottl#include "sanitizer_common/sanitizer_flags.h" 23195534Sscottl#include "sanitizer_common/sanitizer_mutex.h" 24195534Sscottl#include "sanitizer_common/sanitizer_report_decorator.h" 25195534Sscottl#include "sanitizer_common/sanitizer_stackdepot.h" 26195534Sscottl#include "sanitizer_common/sanitizer_stacktrace_printer.h" 27195534Sscottl#include "sanitizer_common/sanitizer_symbolizer.h" 28195534Sscottl 29195534Sscottlusing namespace __sanitizer; 30220454Smav 31220454Smavnamespace __hwasan { 32195534Sscottl 33195534Sscottlclass ScopedReport { 34195534Sscottl public: 35195534Sscottl ScopedReport(bool fatal = false) : error_message_(1), fatal(fatal) { 36195534Sscottl BlockingMutexLock lock(&error_message_lock_); 37195534Sscottl error_message_ptr_ = fatal ? &error_message_ : nullptr; 38195534Sscottl ++hwasan_report_count; 39195534Sscottl } 40195534Sscottl 41195534Sscottl ~ScopedReport() { 42195534Sscottl { 43195534Sscottl BlockingMutexLock lock(&error_message_lock_); 44195534Sscottl if (fatal) 45195534Sscottl SetAbortMessage(error_message_.data()); 46195534Sscottl error_message_ptr_ = nullptr; 47251792Smav } 48214279Sbrucec if (common_flags()->print_module_map >= 2 || 49195534Sscottl (fatal && common_flags()->print_module_map)) 50195534Sscottl DumpProcessMap(); 51195534Sscottl if (fatal) 52195534Sscottl Die(); 53195534Sscottl } 54195534Sscottl 55195534Sscottl static void MaybeAppendToErrorMessage(const char *msg) { 56195534Sscottl BlockingMutexLock lock(&error_message_lock_); 57195534Sscottl if (!error_message_ptr_) 58195534Sscottl return; 59195534Sscottl uptr len = internal_strlen(msg); 60195534Sscottl uptr old_size = error_message_ptr_->size(); 61195534Sscottl error_message_ptr_->resize(old_size + len); 62298002Simp // overwrite old trailing '\0', keep new trailing '\0' untouched. 63195534Sscottl internal_memcpy(&(*error_message_ptr_)[old_size - 1], msg, len); 64195534Sscottl } 65195534Sscottl private: 66208349Smarius ScopedErrorReportLock error_report_lock_; 67208349Smarius InternalMmapVector<char> error_message_; 68195534Sscottl bool fatal; 69195534Sscottl 70195534Sscottl static InternalMmapVector<char> *error_message_ptr_; 71195534Sscottl static BlockingMutex error_message_lock_; 72298002Simp}; 73298002Simp 74195534SscottlInternalMmapVector<char> *ScopedReport::error_message_ptr_; 75224497SmavBlockingMutex ScopedReport::error_message_lock_; 76220412Smav 77198708Smav// If there is an active ScopedReport, append to its error message. 78195534Sscottlvoid AppendToErrorMessageBuffer(const char *buffer) { 79195534Sscottl ScopedReport::MaybeAppendToErrorMessage(buffer); 80195534Sscottl} 81249199Smarius 82249199Smariusstatic StackTrace GetStackTraceFromId(u32 id) { 83249199Smarius CHECK(id); 84249199Smarius StackTrace res = StackDepotGet(id); 85249199Smarius CHECK(res.trace); 86257054Smav return res; 87249199Smarius} 88249199Smarius 89249199Smarius// A RAII object that holds a copy of the current thread stack ring buffer. 90249199Smarius// The actual stack buffer may change while we are iterating over it (for 91249199Smarius// example, Printf may call syslog() which can itself be built with hwasan). 92253724Smavclass SavedStackAllocations { 93298002Simp public: 94298002Simp SavedStackAllocations(StackAllocationsRingBuffer *rb) { 95298002Simp uptr size = rb->size() * sizeof(uptr); 96195534Sscottl void *storage = 97195534Sscottl MmapAlignedOrDieOnFatalError(size, size * 2, "saved stack allocations"); 98195534Sscottl new (&rb_) StackAllocationsRingBuffer(*rb, storage); 99222520Smav } 100222520Smav 101298002Simp ~SavedStackAllocations() { 102195534Sscottl StackAllocationsRingBuffer *rb = get(); 103195534Sscottl UnmapOrDie(rb->StartOfStorage(), rb->size() * sizeof(uptr)); 104250792Ssmh } 105250792Ssmh 106298002Simp StackAllocationsRingBuffer *get() { 107298002Simp return (StackAllocationsRingBuffer *)&rb_; 108250792Ssmh } 109195534Sscottl 110224497Smav private: 111224497Smav uptr rb_; 112195534Sscottl}; 113195534Sscottl 114201139Smavclass Decorator: public __sanitizer::SanitizerCommonDecorator { 115195534Sscottl public: 116195534Sscottl Decorator() : SanitizerCommonDecorator() { } 117195534Sscottl const char *Access() { return Blue(); } 118195534Sscottl const char *Allocation() const { return Magenta(); } 119195534Sscottl const char *Origin() const { return Magenta(); } 120195534Sscottl const char *Name() const { return Green(); } 121195534Sscottl const char *Location() { return Green(); } 122298002Simp const char *Thread() { return Green(); } 123298002Simp}; 124298002Simp 125298002Simp// Returns the index of the rb element that matches tagged_addr (plus one), 126298002Simp// or zero if found nothing. 127298002Simpuptr FindHeapAllocation(HeapAllocationsRingBuffer *rb, 128298002Simp uptr tagged_addr, 129298002Simp HeapAllocationRecord *har) { 130298002Simp if (!rb) return 0; 131298002Simp for (uptr i = 0, size = rb->size(); i < size; i++) { 132298002Simp auto h = (*rb)[i]; 133298002Simp if (h.tagged_addr <= tagged_addr && 134298002Simp h.tagged_addr + h.requested_size > tagged_addr) { 135298002Simp *har = h; 136298002Simp return i + 1; 137298002Simp } 138298002Simp } 139195534Sscottl return 0; 140195534Sscottl} 141198897Smav 142195534Sscottlstatic void PrintStackAllocations(StackAllocationsRingBuffer *sa, 143198897Smav tag_t addr_tag, uptr untagged_addr) { 144198897Smav uptr frames = Min((uptr)flags()->stack_history_size, sa->size()); 145195534Sscottl bool found_local = false; 146195534Sscottl for (uptr i = 0; i < frames; i++) { 147222643Smav const uptr *record_addr = &(*sa)[i]; 148249934Ssmh uptr record = *record_addr; 149201139Smav if (!record) 150249934Ssmh break; 151256836Smav tag_t base_tag = 152201139Smav reinterpret_cast<uptr>(record_addr) >> kRecordAddrBaseTagShift; 153201139Smav uptr fp = (record >> kRecordFPShift) << kRecordFPLShift; 154195534Sscottl uptr pc_mask = (1ULL << kRecordFPShift) - 1; 155298002Simp uptr pc = record & pc_mask; 156257054Smav FrameInfo frame; 157257054Smav if (Symbolizer::GetOrInit()->SymbolizeFrame(pc, &frame)) { 158195534Sscottl for (LocalInfo &local : frame.locals) { 159257054Smav if (!local.has_frame_offset || !local.has_size || !local.has_tag_offset) 160195534Sscottl continue; 161298002Simp tag_t obj_tag = base_tag ^ local.tag_offset; 162201139Smav if (obj_tag != addr_tag) 163224497Smav continue; 164220454Smav // Calculate the offset from the object address to the faulting 165298002Simp // address. Because we only store bits 4-19 of FP (bits 0-3 are 166298002Simp // guaranteed to be zero), the calculation is performed mod 2^20 and may 167220454Smav // harmlessly underflow if the address mod 2^20 is below the object 168220454Smav // address. 169220454Smav uptr obj_offset = 170220454Smav (untagged_addr - fp - local.frame_offset) & (kRecordFPModulus - 1); 171220454Smav if (obj_offset >= local.size) 172220454Smav continue; 173195534Sscottl if (!found_local) { 174195534Sscottl Printf("Potentially referenced stack objects:\n"); 175195534Sscottl found_local = true; 176195534Sscottl } 177195534Sscottl Printf(" %s in %s %s:%d\n", local.name, local.function_name, 178195534Sscottl local.decl_file, local.decl_line); 179201139Smav } 180298002Simp frame.Clear(); 181298002Simp } 182298002Simp } 183298002Simp 184298002Simp if (found_local) 185298002Simp return; 186298002Simp 187195534Sscottl // We didn't find any locals. Most likely we don't have symbols, so dump 188195534Sscottl // the information that we have for offline analysis. 189195534Sscottl InternalScopedString frame_desc(GetPageSizeCached() * 2); 190195534Sscottl Printf("Previously allocated frames:\n"); 191195534Sscottl for (uptr i = 0; i < frames; i++) { 192195534Sscottl const uptr *record_addr = &(*sa)[i]; 193195534Sscottl uptr record = *record_addr; 194199178Smav if (!record) 195199178Smav break; 196199178Smav uptr pc_mask = (1ULL << 48) - 1; 197222520Smav uptr pc = record & pc_mask; 198222520Smav frame_desc.append(" record_addr:0x%zx record:0x%zx", 199222520Smav reinterpret_cast<uptr>(record_addr), record); 200222520Smav if (SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc)) { 201222520Smav RenderFrame(&frame_desc, " %F %L\n", 0, frame->info, 202222520Smav common_flags()->symbolize_vs_style, 203228819Smav common_flags()->strip_path_prefix); 204228819Smav frame->ClearAll(); 205228819Smav } 206228819Smav Printf("%s", frame_desc.data()); 207228819Smav frame_desc.clear(); 208222520Smav } 209222520Smav} 210222520Smav 211222520Smav// Returns true if tag == *tag_ptr, reading tags from short granules if 212222520Smav// necessary. This may return a false positive if tags 1-15 are used as a 213222520Smav// regular tag rather than a short granule marker. 214222520Smavstatic bool TagsEqual(tag_t tag, tag_t *tag_ptr) { 215222520Smav if (tag == *tag_ptr) 216222520Smav return true; 217228819Smav if (*tag_ptr == 0 || *tag_ptr > kShadowAlignment - 1) 218228819Smav return false; 219228819Smav uptr mem = ShadowToMem(reinterpret_cast<uptr>(tag_ptr)); 220228819Smav tag_t inline_tag = *reinterpret_cast<tag_t *>(mem + kShadowAlignment - 1); 221228819Smav return tag == inline_tag; 222228819Smav} 223228819Smav 224228819Smavvoid PrintAddressDescription( 225228819Smav uptr tagged_addr, uptr access_size, 226228819Smav StackAllocationsRingBuffer *current_stack_allocations) { 227222520Smav Decorator d; 228222520Smav int num_descriptions_printed = 0; 229222520Smav uptr untagged_addr = UntagAddr(tagged_addr); 230222520Smav 231222520Smav // Print some very basic information about the address, if it's a heap. 232222520Smav HwasanChunkView chunk = FindHeapChunkByAddress(untagged_addr); 233222520Smav if (uptr beg = chunk.Beg()) { 234222520Smav uptr size = chunk.ActualSize(); 235222520Smav Printf("%s[%p,%p) is a %s %s heap chunk; " 236222520Smav "size: %zd offset: %zd\n%s", 237222520Smav d.Location(), 238228819Smav beg, beg + size, 239228819Smav chunk.FromSmallHeap() ? "small" : "large", 240228819Smav chunk.IsAllocated() ? "allocated" : "unallocated", 241228819Smav size, untagged_addr - beg, 242228819Smav d.Default()); 243228819Smav } 244228819Smav 245228819Smav // Check if this looks like a heap buffer overflow by scanning 246228819Smav // the shadow left and right and looking for the first adjacent 247228819Smav // object with a different memory tag. If that tag matches addr_tag, 248222520Smav // check the allocator if it has a live chunk there. 249222520Smav tag_t addr_tag = GetTagFromPointer(tagged_addr); 250222520Smav tag_t *tag_ptr = reinterpret_cast<tag_t*>(MemToShadow(untagged_addr)); 251222520Smav tag_t *candidate = nullptr, *left = tag_ptr, *right = tag_ptr; 252222520Smav for (int i = 0; i < 1000; i++) { 253222520Smav if (TagsEqual(addr_tag, left)) { 254222520Smav candidate = left; 255222520Smav break; 256222520Smav } 257228819Smav --left; 258228819Smav if (TagsEqual(addr_tag, right)) { 259228819Smav candidate = right; 260228819Smav break; 261228819Smav } 262222520Smav ++right; 263222520Smav } 264222520Smav 265222520Smav if (candidate) { 266222520Smav uptr mem = ShadowToMem(reinterpret_cast<uptr>(candidate)); 267280845Seadler HwasanChunkView chunk = FindHeapChunkByAddress(mem); 268280845Seadler if (chunk.IsAllocated()) { 269280845Seadler Printf("%s", d.Location()); 270280845Seadler Printf("%p is located %zd bytes to the %s of %zd-byte region [%p,%p)\n", 271280845Seadler untagged_addr, 272222520Smav candidate == left ? untagged_addr - chunk.End() 273222520Smav : chunk.Beg() - untagged_addr, 274222520Smav candidate == left ? "right" : "left", chunk.UsedSize(), 275222520Smav chunk.Beg(), chunk.End()); 276222520Smav Printf("%s", d.Allocation()); 277280845Seadler Printf("allocated here:\n"); 278222520Smav Printf("%s", d.Default()); 279222520Smav GetStackTraceFromId(chunk.GetAllocStackId()).Print(); 280222520Smav num_descriptions_printed++; 281222520Smav } else { 282280845Seadler // Check whether the address points into a loaded library. If so, this is 283280845Seadler // most likely a global variable. 284280845Seadler const char *module_name; 285280845Seadler uptr module_address; 286280845Seadler Symbolizer *sym = Symbolizer::GetOrInit(); 287280845Seadler if (sym->GetModuleNameAndOffsetForPC(mem, &module_name, 288280845Seadler &module_address)) { 289280845Seadler DataInfo info; 290280845Seadler if (sym->SymbolizeData(mem, &info) && info.start) { 291280845Seadler Printf( 292222520Smav "%p is located %zd bytes to the %s of %zd-byte global variable " 293222520Smav "%s [%p,%p) in %s\n", 294222520Smav untagged_addr, 295222520Smav candidate == left ? untagged_addr - (info.start + info.size) 296222520Smav : info.start - untagged_addr, 297222520Smav candidate == left ? "right" : "left", info.size, info.name, 298222520Smav info.start, info.start + info.size, module_name); 299222520Smav } else { 300222520Smav Printf("%p is located to the %s of a global variable in (%s+0x%x)\n", 301222520Smav untagged_addr, candidate == left ? "right" : "left", 302222520Smav module_name, module_address); 303222520Smav } 304222520Smav num_descriptions_printed++; 305222520Smav } 306222520Smav } 307222520Smav } 308222520Smav 309222520Smav hwasanThreadList().VisitAllLiveThreads([&](Thread *t) { 310222520Smav // Scan all threads' ring buffers to find if it's a heap-use-after-free. 311222520Smav HeapAllocationRecord har; 312222520Smav if (uptr D = FindHeapAllocation(t->heap_allocations(), tagged_addr, &har)) { 313222520Smav Printf("%s", d.Location()); 314222520Smav Printf("%p is located %zd bytes inside of %zd-byte region [%p,%p)\n", 315222520Smav untagged_addr, untagged_addr - UntagAddr(har.tagged_addr), 316222520Smav har.requested_size, UntagAddr(har.tagged_addr), 317222520Smav UntagAddr(har.tagged_addr) + har.requested_size); 318222520Smav Printf("%s", d.Allocation()); 319222520Smav Printf("freed by thread T%zd here:\n", t->unique_id()); 320222520Smav Printf("%s", d.Default()); 321251061Ssmh GetStackTraceFromId(har.free_context_id).Print(); 322222520Smav 323241784Seadler Printf("%s", d.Allocation()); 324241784Seadler Printf("previously allocated here:\n", t); 325241784Seadler Printf("%s", d.Default()); 326241784Seadler GetStackTraceFromId(har.alloc_context_id).Print(); 327241784Seadler 328241784Seadler // Print a developer note: the index of this heap object 329241784Seadler // in the thread's deallocation ring buffer. 330241784Seadler Printf("hwasan_dev_note_heap_rb_distance: %zd %zd\n", D, 331241784Seadler flags()->heap_history_size); 332241784Seadler 333241784Seadler t->Announce(); 334241784Seadler num_descriptions_printed++; 335241784Seadler } 336241784Seadler 337241784Seadler // Very basic check for stack memory. 338241784Seadler if (t->AddrIsInStack(untagged_addr)) { 339241784Seadler Printf("%s", d.Location()); 340256547Ssmh Printf("Address %p is located in stack of thread T%zd\n", untagged_addr, 341256547Ssmh t->unique_id()); 342256547Ssmh Printf("%s", d.Default()); 343256547Ssmh t->Announce(); 344256547Ssmh 345256547Ssmh auto *sa = (t == GetCurrentThread() && current_stack_allocations) 346256547Ssmh ? current_stack_allocations 347256547Ssmh : t->stack_allocations(); 348269974Ssmh PrintStackAllocations(sa, addr_tag, untagged_addr); 349241784Seadler num_descriptions_printed++; 350241784Seadler } 351269974Ssmh }); 352241784Seadler 353241784Seadler // Print the remaining threads, as an extra information, 1 line per thread. 354241784Seadler hwasanThreadList().VisitAllLiveThreads([&](Thread *t) { t->Announce(); }); 355241784Seadler 356251061Ssmh if (!num_descriptions_printed) 357241784Seadler // We exhausted our possibilities. Bail out. 358241784Seadler Printf("HWAddressSanitizer can not describe address in more detail.\n"); 359251061Ssmh} 360241784Seadler 361241784Seadlervoid ReportStats() {} 362241784Seadler 363241784Seadlerstatic void PrintTagInfoAroundAddr(tag_t *tag_ptr, uptr num_rows, 364298027Simp void (*print_tag)(InternalScopedString &s, 365298027Simp tag_t *tag)) { 366298002Simp const uptr row_len = 16; // better be power of two. 367298027Simp tag_t *center_row_beg = reinterpret_cast<tag_t *>( 368298002Simp RoundDownTo(reinterpret_cast<uptr>(tag_ptr), row_len)); 369298002Simp tag_t *beg_row = center_row_beg - row_len * (num_rows / 2); 370298002Simp tag_t *end_row = center_row_beg + row_len * ((num_rows + 1) / 2); 371298002Simp InternalScopedString s(GetPageSizeCached() * 8); 372298002Simp for (tag_t *row = beg_row; row < end_row; row += row_len) { 373298002Simp s.append("%s", row == center_row_beg ? "=>" : " "); 374298002Simp s.append("%p:", row); 375298002Simp for (uptr i = 0; i < row_len; i++) { 376298002Simp s.append("%s", row + i == tag_ptr ? "[" : " "); 377298002Simp print_tag(s, &row[i]); 378298002Simp s.append("%s", row + i == tag_ptr ? "]" : " "); 379298002Simp } 380298002Simp s.append("\n"); 381298002Simp } 382298002Simp Printf("%s", s.data()); 383298002Simp} 384298002Simp 385298002Simpstatic void PrintTagsAroundAddr(tag_t *tag_ptr) { 386298002Simp Printf( 387298002Simp "Memory tags around the buggy address (one tag corresponds to %zd " 388298002Simp "bytes):\n", kShadowAlignment); 389298002Simp PrintTagInfoAroundAddr(tag_ptr, 17, [](InternalScopedString &s, tag_t *tag) { 390298002Simp s.append("%02x", *tag); 391298002Simp }); 392298002Simp 393298002Simp Printf( 394298002Simp "Tags for short granules around the buggy address (one tag corresponds " 395298002Simp "to %zd bytes):\n", 396251061Ssmh kShadowAlignment); 397251061Ssmh PrintTagInfoAroundAddr(tag_ptr, 3, [](InternalScopedString &s, tag_t *tag) { 398251061Ssmh if (*tag >= 1 && *tag <= kShadowAlignment) { 399251061Ssmh uptr granule_addr = ShadowToMem(reinterpret_cast<uptr>(tag)); 400251061Ssmh s.append("%02x", 401251061Ssmh *reinterpret_cast<u8 *>(granule_addr + kShadowAlignment - 1)); 402251061Ssmh } else { 403251061Ssmh s.append(".."); 404298027Simp } 405298027Simp }); 406298027Simp Printf( 407298027Simp "See " 408298027Simp "https://clang.llvm.org/docs/" 409298027Simp "HardwareAssistedAddressSanitizerDesign.html#short-granules for a " 410298027Simp "description of short granule tags\n"); 411298027Simp} 412251061Ssmh 413241784Seadlervoid ReportInvalidFree(StackTrace *stack, uptr tagged_addr) { 414241784Seadler ScopedReport R(flags()->halt_on_error); 415251061Ssmh 416241784Seadler uptr untagged_addr = UntagAddr(tagged_addr); 417241784Seadler tag_t ptr_tag = GetTagFromPointer(tagged_addr); 418241784Seadler tag_t *tag_ptr = reinterpret_cast<tag_t*>(MemToShadow(untagged_addr)); 419241784Seadler tag_t mem_tag = *tag_ptr; 420251061Ssmh Decorator d; 421241784Seadler Printf("%s", d.Error()); 422241784Seadler uptr pc = stack->size ? stack->trace[0] : 0; 423251061Ssmh const char *bug_type = "invalid-free"; 424241784Seadler Report("ERROR: %s: %s on address %p at pc %p\n", SanitizerToolName, bug_type, 425241784Seadler untagged_addr, pc); 426241784Seadler Printf("%s", d.Access()); 427241784Seadler Printf("tags: %02x/%02x (ptr/mem)\n", ptr_tag, mem_tag); 428251061Ssmh Printf("%s", d.Default()); 429251061Ssmh 430241784Seadler stack->Print(); 431251061Ssmh 432251061Ssmh PrintAddressDescription(tagged_addr, 0, nullptr); 433241784Seadler 434241784Seadler PrintTagsAroundAddr(tag_ptr); 435241784Seadler 436251061Ssmh ReportErrorSummary(bug_type, stack); 437251061Ssmh} 438241784Seadler 439251061Ssmhvoid ReportTailOverwritten(StackTrace *stack, uptr tagged_addr, uptr orig_size, 440241784Seadler const u8 *expected) { 441241784Seadler uptr tail_size = kShadowAlignment - (orig_size % kShadowAlignment); 442241784Seadler ScopedReport R(flags()->halt_on_error); 443241784Seadler Decorator d; 444254329Ssmh uptr untagged_addr = UntagAddr(tagged_addr); 445254329Ssmh Printf("%s", d.Error()); 446254329Ssmh const char *bug_type = "allocation-tail-overwritten"; 447254329Ssmh Report("ERROR: %s: %s; heap object [%p,%p) of size %zd\n", SanitizerToolName, 448254329Ssmh bug_type, untagged_addr, untagged_addr + orig_size, orig_size); 449254329Ssmh Printf("\n%s", d.Default()); 450254329Ssmh stack->Print(); 451254329Ssmh HwasanChunkView chunk = FindHeapChunkByAddress(untagged_addr); 452251061Ssmh if (chunk.Beg()) { 453250532Seadler Printf("%s", d.Allocation()); 454250532Seadler Printf("allocated here:\n"); 455251061Ssmh Printf("%s", d.Default()); 456250532Seadler GetStackTraceFromId(chunk.GetAllocStackId()).Print(); 457250532Seadler } 458250532Seadler 459250532Seadler InternalScopedString s(GetPageSizeCached() * 8); 460251061Ssmh CHECK_GT(tail_size, 0U); 461241784Seadler CHECK_LT(tail_size, kShadowAlignment); 462241784Seadler u8 *tail = reinterpret_cast<u8*>(untagged_addr + orig_size); 463251061Ssmh s.append("Tail contains: "); 464241784Seadler for (uptr i = 0; i < kShadowAlignment - tail_size; i++) 465241784Seadler s.append(".. "); 466241784Seadler for (uptr i = 0; i < tail_size; i++) 467241784Seadler s.append("%02x ", tail[i]); 468254329Ssmh s.append("\n"); 469254329Ssmh s.append("Expected: "); 470254329Ssmh for (uptr i = 0; i < kShadowAlignment - tail_size; i++) 471254329Ssmh s.append(".. "); 472254329Ssmh for (uptr i = 0; i < tail_size; i++) 473254329Ssmh s.append("%02x ", expected[i]); 474254329Ssmh s.append("\n"); 475254329Ssmh s.append(" "); 476298027Simp for (uptr i = 0; i < kShadowAlignment - tail_size; i++) 477298002Simp s.append(" "); 478298002Simp for (uptr i = 0; i < tail_size; i++) 479298027Simp s.append("%s ", expected[i] != tail[i] ? "^^" : " "); 480298002Simp 481298002Simp s.append("\nThis error occurs when a buffer overflow overwrites memory\n" 482298002Simp "to the right of a heap object, but within the %zd-byte granule, e.g.\n" 483298002Simp " char *x = new char[20];\n" 484298002Simp " x[25] = 42;\n" 485298002Simp "%s does not detect such bugs in uninstrumented code at the time of write," 486298002Simp "\nbut can detect them at the time of free/delete.\n" 487298002Simp "To disable this feature set HWASAN_OPTIONS=free_checks_tail_magic=0\n", 488298002Simp kShadowAlignment, SanitizerToolName); 489298002Simp Printf("%s", s.data()); 490298002Simp GetCurrentThread()->Announce(); 491298002Simp 492298002Simp tag_t *tag_ptr = reinterpret_cast<tag_t*>(MemToShadow(untagged_addr)); 493298002Simp PrintTagsAroundAddr(tag_ptr); 494298002Simp 495298002Simp ReportErrorSummary(bug_type, stack); 496298002Simp} 497298002Simp 498298002Simpvoid ReportTagMismatch(StackTrace *stack, uptr tagged_addr, uptr access_size, 499298002Simp bool is_store, bool fatal, uptr *registers_frame) { 500254329Ssmh ScopedReport R(fatal); 501254329Ssmh SavedStackAllocations current_stack_allocations( 502254329Ssmh GetCurrentThread()->stack_allocations()); 503254329Ssmh 504254329Ssmh Decorator d; 505254329Ssmh Printf("%s", d.Error()); 506254329Ssmh uptr untagged_addr = UntagAddr(tagged_addr); 507254329Ssmh // TODO: when possible, try to print heap-use-after-free, etc. 508251061Ssmh const char *bug_type = "tag-mismatch"; 509250532Seadler uptr pc = stack->size ? stack->trace[0] : 0; 510250532Seadler Report("ERROR: %s: %s on address %p at pc %p\n", SanitizerToolName, bug_type, 511251061Ssmh untagged_addr, pc); 512250532Seadler 513250532Seadler Thread *t = GetCurrentThread(); 514250532Seadler 515250532Seadler sptr offset = 516241784Seadler __hwasan_test_shadow(reinterpret_cast<void *>(tagged_addr), access_size); 517241784Seadler CHECK(offset >= 0 && offset < static_cast<sptr>(access_size)); 518241784Seadler tag_t ptr_tag = GetTagFromPointer(tagged_addr); 519241784Seadler tag_t *tag_ptr = 520241784Seadler reinterpret_cast<tag_t *>(MemToShadow(untagged_addr + offset)); 521241784Seadler tag_t mem_tag = *tag_ptr; 522241784Seadler 523241784Seadler Printf("%s", d.Access()); 524251061Ssmh Printf("%s of size %zu at %p tags: %02x/%02x (ptr/mem) in thread T%zd\n", 525241784Seadler is_store ? "WRITE" : "READ", access_size, untagged_addr, ptr_tag, 526241784Seadler mem_tag, t->unique_id()); 527251061Ssmh if (offset != 0) 528241784Seadler Printf("Invalid access starting at offset [%zu, %zu)\n", offset, 529241784Seadler Min(access_size, static_cast<uptr>(offset) + (1 << kShadowScale))); 530241784Seadler Printf("%s", d.Default()); 531251061Ssmh 532251061Ssmh stack->Print(); 533251061Ssmh 534251061Ssmh PrintAddressDescription(tagged_addr, access_size, 535251061Ssmh current_stack_allocations.get()); 536251061Ssmh t->Announce(); 537251061Ssmh 538251061Ssmh PrintTagsAroundAddr(tag_ptr); 539251061Ssmh 540253091Ssmh if (registers_frame) 541253091Ssmh ReportRegisters(registers_frame, pc); 542253091Ssmh 543253091Ssmh ReportErrorSummary(bug_type, stack); 544253091Ssmh} 545253091Ssmh 546253091Ssmh// See the frame breakdown defined in __hwasan_tag_mismatch (from 547253091Ssmh// hwasan_tag_mismatch_aarch64.S). 548251061Ssmhvoid ReportRegisters(uptr *frame, uptr pc) { 549298002Simp Printf("Registers where the failure occurred (pc %p):\n", pc); 550251061Ssmh 551251061Ssmh // We explicitly print a single line (4 registers/line) each iteration to 552298002Simp // reduce the amount of logcat error messages printed. Each Printf() will 553251061Ssmh // result in a new logcat line, irrespective of whether a newline is present, 554251061Ssmh // and so we wish to reduce the number of Printf() calls we have to make. 555251061Ssmh Printf(" x0 %016llx x1 %016llx x2 %016llx x3 %016llx\n", 556269974Ssmh frame[0], frame[1], frame[2], frame[3]); 557298002Simp Printf(" x4 %016llx x5 %016llx x6 %016llx x7 %016llx\n", 558269974Ssmh frame[4], frame[5], frame[6], frame[7]); 559269974Ssmh Printf(" x8 %016llx x9 %016llx x10 %016llx x11 %016llx\n", 560298002Simp frame[8], frame[9], frame[10], frame[11]); 561269974Ssmh Printf(" x12 %016llx x13 %016llx x14 %016llx x15 %016llx\n", 562269974Ssmh frame[12], frame[13], frame[14], frame[15]); 563269974Ssmh Printf(" x16 %016llx x17 %016llx x18 %016llx x19 %016llx\n", 564273279Sgnn frame[16], frame[17], frame[18], frame[19]); 565298002Simp Printf(" x20 %016llx x21 %016llx x22 %016llx x23 %016llx\n", 566273279Sgnn frame[20], frame[21], frame[22], frame[23]); 567273279Sgnn Printf(" x24 %016llx x25 %016llx x26 %016llx x27 %016llx\n", 568298002Simp frame[24], frame[25], frame[26], frame[27]); 569273279Sgnn Printf(" x28 %016llx x29 %016llx x30 %016llx\n", 570270305Ssbruno frame[28], frame[29], frame[30]); 571270305Ssbruno} 572298035Simp 573298035Simp} // namespace __hwasan 574298035Simp