Skip to content

[asan][win] The memory used for PoisonShadow should be created #146679

Open
@GkvJwa

Description

@GkvJwa

Here is a issue on Win

Because the memory is not created when running to FastPoisonShadow->memset, an access violation will be triggered under the debugger

As mentioned in the issue, msvc's asan does not have this problem, So I analyzed the asan version of msvc, there is indeed a big difference

The memory for PoisonShadow will be created

void __fastcall __asan::AsanMapUnmapCallback::OnMap(
        __asan::AsanMapUnmapCallback *this,
        unsigned __int64 p,
        unsigned __int64 size)
{
  __asan::AsanStats *CurrentThreadStats; // rax

  _sanitizer_virtual_alloc(
    (char *)_asan_shadow_memory_dynamic_address + (p >> 3),
    (unsigned __int64)_asan_shadow_memory_dynamic_address
  + ((size + p - 8) >> 3)
  - ((_QWORD)_asan_shadow_memory_dynamic_address
   + (p >> 3))
  + 1,
    0x1000u,
    4u);
  __asan::PoisonShadow(p, size, 0xFAu);
  CurrentThreadStats = __asan::GetCurrentThreadStats();
  ++CurrentThreadStats->mmaps;
  CurrentThreadStats->mmaped += size;
}

-->

void AsanMapUnmapCallback::OnMap(uptr p, uptr size) const {
  uptr shadow_beg = MEM_TO_SHADOW(p);
  uptr shadow_end = MEM_TO_SHADOW(p + size - ASAN_SHADOW_GRANULARITY) + 1;

  VirtualAlloc((LPVOID)shadow_beg, shadow_end - shadow_beg, MEM_COMMIT,
               PAGE_READWRITE);
  PoisonShadow(p, size, kAsanHeapLeftRedzoneMagic);
  // Statistics.
  AsanStats &thread_stats = GetCurrentThreadStats();
  thread_stats.mmaps++;
  thread_stats.mmaped += size;
}

To avoid exceptions in debugger

Of course, MSVC's ASAN also has many other logics
like
When calling PoisonShadow, _sanitizer_virtual_alloc is basically executed first

void __fastcall __asan::AsanThread::ClearShadowForThreadStackAndTLS(__asan::AsanThread *this)
{
  unsigned __int64 stack_bottom; // rax
  unsigned __int64 stack_top; // r8
  unsigned __int64 tls_end; // rax
  unsigned __int64 tls_begin; // rdi
  unsigned __int64 v6; // rdi
  unsigned __int64 v7; // rbx

  stack_bottom = this->stack_bottom_;
  stack_top = this->stack_top_;
  if ( stack_top != stack_bottom )
  {
    _sanitizer_virtual_alloc(
      (char *)_asan_shadow_memory_dynamic_address + (stack_bottom >> 3),
      (unsigned __int64)_asan_shadow_memory_dynamic_address
    + ((stack_top - 8) >> 3)
    - ((_QWORD)_asan_shadow_memory_dynamic_address
     + (stack_bottom >> 3))
    + 1,
      0x1000u,
      4u);
    __asan::PoisonShadow(this->stack_bottom_, this->stack_top_ - this->stack_bottom_, 0);
  }
  tls_end = this->tls_end_;

rewritten VirtualAlloc

void *__fastcall _sanitizer_virtual_alloc(
        void *lpAddress,
        unsigned __int64 dwSize,
        unsigned int flAllocationType,
        unsigned int flProtect)
{
  void *v5; // [rsp+40h] [rbp+8h] BYREF
  unsigned __int64 v6; // [rsp+48h] [rbp+10h] BYREF
  unsigned int v7; // [rsp+50h] [rbp+18h] BYREF
  unsigned int v8; // [rsp+58h] [rbp+20h] BYREF

  v8 = flProtect;
  v7 = flAllocationType;
  v6 = dwSize;
  v5 = lpAddress;
  return __sanitizer::IATOverwriteGuard<void * (void *,unsigned __int64,unsigned long,unsigned long),void * &,unsigned __int64 &,unsigned long &,unsigned long &>(
           "VirtualAlloc IAT entry overwritten.",
           (void *(__fastcall *)(void *, unsigned __int64, unsigned int, unsigned int))VirtualAlloc,
           &v5,
           &v6,
           &v7,
           &v8);
}

Therefore, it may be better for asan to create the memory for PoisonShadow in advance on the windows, like MSVC does.

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions