CVE-2016-1669

| categories notes 
tags CVE分析 

https://bugs.chromium.org/p/chromium/issues/detail?id=606115

test.js(不一定能复现)

r2 = new RegExp("(?=)*", "g");
s0 = Array(220000700).join('a'); // the size could be different between v8 and chrome
result = s0.match(r2);

原因

这个漏洞非常有意思,其实跟正则没什么管理,而是内存管理的细节没有考虑到位,导致溢出。

// runtime/runtime-strings.cc

 334 RUNTIME_FUNCTION(Runtime_StringMatch) {
 ..
 349   ZoneScope zone_scope(isolate->runtime_zone());
 350   ZoneList<int> offsets(8, zone_scope.zone());
 351
 352   while (true) {
 353     int32_t* match = global_cache.FetchNext();
 354     if (match == NULL) break;
 355     offsets.Add(match[0], zone_scope.zone());  // start <----------
 356     offsets.Add(match[1], zone_scope.zone());  // end
 357   }

这里进行了非常多次的Add操作,导致 offsets 这个 ZoneList 变得非常大

#0  v8::internal::Zone::New (this=0x42d61b8, size=18432) at ../src/zone.cc:112
#1  0x0000000000d1c225 in v8::internal::ZoneAllocationPolicy::New (
    this=0x7ffc861b73f8, size=18428) at .././src/zone.h:160
#2  0x0000000000f5947a in v8::internal::List<int, v8::internal::ZoneAllocationPolicy>::NewData (this=0x7ffc861b7648, n=4607, allocator=...)
    at .././src/list.h:182
#3  0x0000000000f593fc in v8::internal::List<int, v8::internal::ZoneAllocationPolicy>::Resize (this=0x7ffc861b7648, new_capacity=4607, alloc=...)
    at .././src/list-inl.h:71
#4  0x0000000000f5933f in v8::internal::List<int, v8::internal::ZoneAllocationPolicy>::ResizeAddInternal (this=0x7ffc861b7648, element=@0x42d9f5c: 1151,
    alloc=...) at .././src/list-inl.h:63
#5  0x0000000000f5928d in v8::internal::List<int, v8::internal::ZoneAllocationPolicy>::ResizeAdd (this=0x7ffc861b7648, element=@0x42d9f5c: 1151, alloc=...)
    at .././src/list-inl.h:50
#6  0x0000000000f59255 in v8::internal::List<int, v8::internal::ZoneAllocationPolicy>::Add (this=0x7ffc861b7648, element=@0x42d9f5c: 1151, alloc=...)
    at .././src/list-inl.h:22
#7  0x0000000000f591e0 in v8::internal::ZoneList<int>::Add (
    this=0x7ffc861b7648, element=@0x42d9f5c: 1151, zone=0x42d61b8)
    at .././src/zone.h:193

在这个过程中,下面的 position_ 和 limit_ 都会逐渐变大,但是有可能 position_ + size_with_redzone 先溢出

// ../src/zone.cc

void* Zone::New(size_t size) {
  // Round up the requested size to fit the alignment.
  size = RoundUp(size, kAlignment);

  // If the allocation size is divisible by 8 then we return an 8-byte aligned
  // address.
  if (kPointerSize == 4 && kAlignment == 4) {
    position_ += ((~size) & 4) & (reinterpret_cast<intptr_t>(position_) & 4);
  } else {
    DCHECK(kAlignment >= kPointerSize);
  }

  // Check if the requested size is available without expanding.
  Address result = position_;

  const size_t size_with_redzone = size + kASanRedzoneBytes;
  if (limit_ < position_ + size_with_redzone) { // 会溢出,导致IF语句为FALSE
    result = NewExpand(size_with_redzone);
  } else {
    position_ += size_with_redzone; // position_ 实际变小了
  }


If you liked this post, you can share it with your followers !