1*0b57cec5SDimitry Andric 2*0b57cec5SDimitry Andric #include "hwasan.h" 3*0b57cec5SDimitry Andric #include "hwasan_mapping.h" 4*0b57cec5SDimitry Andric #include "hwasan_thread.h" 5*0b57cec5SDimitry Andric #include "hwasan_poisoning.h" 6*0b57cec5SDimitry Andric #include "hwasan_interface_internal.h" 7*0b57cec5SDimitry Andric 8*0b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_file.h" 9*0b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_placement_new.h" 10*0b57cec5SDimitry Andric #include "sanitizer_common/sanitizer_tls_get_addr.h" 11*0b57cec5SDimitry Andric 12*0b57cec5SDimitry Andric 13*0b57cec5SDimitry Andric namespace __hwasan { 14*0b57cec5SDimitry Andric 15*0b57cec5SDimitry Andric static u32 RandomSeed() { 16*0b57cec5SDimitry Andric u32 seed; 17*0b57cec5SDimitry Andric do { 18*0b57cec5SDimitry Andric if (UNLIKELY(!GetRandom(reinterpret_cast<void *>(&seed), sizeof(seed), 19*0b57cec5SDimitry Andric /*blocking=*/false))) { 20*0b57cec5SDimitry Andric seed = static_cast<u32>( 21*0b57cec5SDimitry Andric (NanoTime() >> 12) ^ 22*0b57cec5SDimitry Andric (reinterpret_cast<uptr>(__builtin_frame_address(0)) >> 4)); 23*0b57cec5SDimitry Andric } 24*0b57cec5SDimitry Andric } while (!seed); 25*0b57cec5SDimitry Andric return seed; 26*0b57cec5SDimitry Andric } 27*0b57cec5SDimitry Andric 28*0b57cec5SDimitry Andric void Thread::InitRandomState() { 29*0b57cec5SDimitry Andric random_state_ = flags()->random_tags ? RandomSeed() : unique_id_; 30*0b57cec5SDimitry Andric 31*0b57cec5SDimitry Andric // Push a random number of zeros onto the ring buffer so that the first stack 32*0b57cec5SDimitry Andric // tag base will be random. 33*0b57cec5SDimitry Andric for (tag_t i = 0, e = GenerateRandomTag(); i != e; ++i) 34*0b57cec5SDimitry Andric stack_allocations_->push(0); 35*0b57cec5SDimitry Andric } 36*0b57cec5SDimitry Andric 37*0b57cec5SDimitry Andric void Thread::Init(uptr stack_buffer_start, uptr stack_buffer_size) { 38*0b57cec5SDimitry Andric static u64 unique_id; 39*0b57cec5SDimitry Andric unique_id_ = unique_id++; 40*0b57cec5SDimitry Andric if (auto sz = flags()->heap_history_size) 41*0b57cec5SDimitry Andric heap_allocations_ = HeapAllocationsRingBuffer::New(sz); 42*0b57cec5SDimitry Andric 43*0b57cec5SDimitry Andric HwasanTSDThreadInit(); // Only needed with interceptors. 44*0b57cec5SDimitry Andric uptr *ThreadLong = GetCurrentThreadLongPtr(); 45*0b57cec5SDimitry Andric // The following implicitly sets (this) as the current thread. 46*0b57cec5SDimitry Andric stack_allocations_ = new (ThreadLong) 47*0b57cec5SDimitry Andric StackAllocationsRingBuffer((void *)stack_buffer_start, stack_buffer_size); 48*0b57cec5SDimitry Andric // Check that it worked. 49*0b57cec5SDimitry Andric CHECK_EQ(GetCurrentThread(), this); 50*0b57cec5SDimitry Andric 51*0b57cec5SDimitry Andric // ScopedTaggingDisable needs GetCurrentThread to be set up. 52*0b57cec5SDimitry Andric ScopedTaggingDisabler disabler; 53*0b57cec5SDimitry Andric 54*0b57cec5SDimitry Andric uptr tls_size; 55*0b57cec5SDimitry Andric uptr stack_size; 56*0b57cec5SDimitry Andric GetThreadStackAndTls(IsMainThread(), &stack_bottom_, &stack_size, &tls_begin_, 57*0b57cec5SDimitry Andric &tls_size); 58*0b57cec5SDimitry Andric stack_top_ = stack_bottom_ + stack_size; 59*0b57cec5SDimitry Andric tls_end_ = tls_begin_ + tls_size; 60*0b57cec5SDimitry Andric 61*0b57cec5SDimitry Andric if (stack_bottom_) { 62*0b57cec5SDimitry Andric int local; 63*0b57cec5SDimitry Andric CHECK(AddrIsInStack((uptr)&local)); 64*0b57cec5SDimitry Andric CHECK(MemIsApp(stack_bottom_)); 65*0b57cec5SDimitry Andric CHECK(MemIsApp(stack_top_ - 1)); 66*0b57cec5SDimitry Andric } 67*0b57cec5SDimitry Andric 68*0b57cec5SDimitry Andric if (flags()->verbose_threads) { 69*0b57cec5SDimitry Andric if (IsMainThread()) { 70*0b57cec5SDimitry Andric Printf("sizeof(Thread): %zd sizeof(HeapRB): %zd sizeof(StackRB): %zd\n", 71*0b57cec5SDimitry Andric sizeof(Thread), heap_allocations_->SizeInBytes(), 72*0b57cec5SDimitry Andric stack_allocations_->size() * sizeof(uptr)); 73*0b57cec5SDimitry Andric } 74*0b57cec5SDimitry Andric Print("Creating : "); 75*0b57cec5SDimitry Andric } 76*0b57cec5SDimitry Andric } 77*0b57cec5SDimitry Andric 78*0b57cec5SDimitry Andric void Thread::ClearShadowForThreadStackAndTLS() { 79*0b57cec5SDimitry Andric if (stack_top_ != stack_bottom_) 80*0b57cec5SDimitry Andric TagMemory(stack_bottom_, stack_top_ - stack_bottom_, 0); 81*0b57cec5SDimitry Andric if (tls_begin_ != tls_end_) 82*0b57cec5SDimitry Andric TagMemory(tls_begin_, tls_end_ - tls_begin_, 0); 83*0b57cec5SDimitry Andric } 84*0b57cec5SDimitry Andric 85*0b57cec5SDimitry Andric void Thread::Destroy() { 86*0b57cec5SDimitry Andric if (flags()->verbose_threads) 87*0b57cec5SDimitry Andric Print("Destroying: "); 88*0b57cec5SDimitry Andric AllocatorSwallowThreadLocalCache(allocator_cache()); 89*0b57cec5SDimitry Andric ClearShadowForThreadStackAndTLS(); 90*0b57cec5SDimitry Andric if (heap_allocations_) 91*0b57cec5SDimitry Andric heap_allocations_->Delete(); 92*0b57cec5SDimitry Andric DTLS_Destroy(); 93*0b57cec5SDimitry Andric } 94*0b57cec5SDimitry Andric 95*0b57cec5SDimitry Andric void Thread::Print(const char *Prefix) { 96*0b57cec5SDimitry Andric Printf("%sT%zd %p stack: [%p,%p) sz: %zd tls: [%p,%p)\n", Prefix, 97*0b57cec5SDimitry Andric unique_id_, this, stack_bottom(), stack_top(), 98*0b57cec5SDimitry Andric stack_top() - stack_bottom(), 99*0b57cec5SDimitry Andric tls_begin(), tls_end()); 100*0b57cec5SDimitry Andric } 101*0b57cec5SDimitry Andric 102*0b57cec5SDimitry Andric static u32 xorshift(u32 state) { 103*0b57cec5SDimitry Andric state ^= state << 13; 104*0b57cec5SDimitry Andric state ^= state >> 17; 105*0b57cec5SDimitry Andric state ^= state << 5; 106*0b57cec5SDimitry Andric return state; 107*0b57cec5SDimitry Andric } 108*0b57cec5SDimitry Andric 109*0b57cec5SDimitry Andric // Generate a (pseudo-)random non-zero tag. 110*0b57cec5SDimitry Andric tag_t Thread::GenerateRandomTag() { 111*0b57cec5SDimitry Andric if (tagging_disabled_) return 0; 112*0b57cec5SDimitry Andric tag_t tag; 113*0b57cec5SDimitry Andric do { 114*0b57cec5SDimitry Andric if (flags()->random_tags) { 115*0b57cec5SDimitry Andric if (!random_buffer_) 116*0b57cec5SDimitry Andric random_buffer_ = random_state_ = xorshift(random_state_); 117*0b57cec5SDimitry Andric CHECK(random_buffer_); 118*0b57cec5SDimitry Andric tag = random_buffer_ & 0xFF; 119*0b57cec5SDimitry Andric random_buffer_ >>= 8; 120*0b57cec5SDimitry Andric } else { 121*0b57cec5SDimitry Andric tag = random_state_ = (random_state_ + 1) & 0xFF; 122*0b57cec5SDimitry Andric } 123*0b57cec5SDimitry Andric } while (!tag); 124*0b57cec5SDimitry Andric return tag; 125*0b57cec5SDimitry Andric } 126*0b57cec5SDimitry Andric 127*0b57cec5SDimitry Andric } // namespace __hwasan 128