# CVE-2020-16010: Chrome for Android ConvertToJavaBitmap Heap Buffer Overflow
*Mark Brand and Sergei Glazunov, Project Zero (Originally posted on [Project Zero blog](https://googleprojectzero.blogspot.com/p/rca.html) 2021-02-04)*

## The Basics

**Disclosure or Patch Date:** 2 November 2020

**Product:** Google Chrome for Android

**Advisory:** https://chromereleases.googleblog.com/2020/11/chrome-for-android-update.html 

**Affected Versions:** 86.0.4240.114 and previous

**First Patched Version:** 86.0.4240.185

**Issue/Bug Report:**

* Project Zero: https://bugs.chromium.org/p/project-zero/issues/detail?id=2112 
* Chromium: https://bugs.chromium.org/p/chromium/issues/detail?id=1144368 

**Patch CL:** https://chromium.googlesource.com/chromium/src.git/+/e598fc599bd920392256d05c61826466c73c8e89 

**Bug-Introducing CL:** Unknown - at least from the [migration of the use of SkColorType from SkBitmap::Config](https://source.chromium.org/chromium/chromium/src/+/3fa5258463086cc5606c3e8363d0ded6ff88c1d4) but may have existed prior to that.

**Reporter(s):** Maddie Stone, Mark Brand, and Sergei Glazunov of Google Project Zero 

## The Code

**Proof-of-concept:** https://bugs.chromium.org/p/project-zero/issues/detail?id=2112 

**Exploit sample:** N/A

**Did you have access to the exploit sample when doing the analysis?** Yes

## The Vulnerability

**Bug class:** Buffer overflow

**Vulnerability details:**

`ConvertToJavaBitmap` doesn't handle all Skia supported color formats, and when converting a Skia bitmap with an unsupported `SkColorType`, it falls back to a default format (32-bits-per-pixel, ARGB_8888).

https://source.chromium.org/chromium/chromium/src/+/master:ui/gfx/android/java_bitmap.cc;drc=8811640591d59f0b489a7703224530b03efe127b;l=44

```c++
static int SkColorTypeToBitmapFormat(SkColorType color_type) {
  switch (color_type) {
    case kAlpha_8_SkColorType:
      return BITMAP_FORMAT_ALPHA_8;
    case kARGB_4444_SkColorType:
      return BITMAP_FORMAT_ARGB_4444;
    case kN32_SkColorType:
      return BITMAP_FORMAT_ARGB_8888;
    case kRGB_565_SkColorType:
      return BITMAP_FORMAT_RGB_565;
    case kUnknown_SkColorType:
    default:
      NOTREACHED(); // NOTREACHED has no effect in release builds.
      return BITMAP_FORMAT_NO_CONFIG;
  }
}
```

https://source.chromium.org/chromium/chromium/src/+/master:ui/android/java/src/org/chromium/ui/gfx/BitmapHelper.java;drc=8811640591d59f0b489a7703224530b03efe127b;l=61
```c++
/**
 * Provides a matching Bitmap.Config for the enum config value passed.
 *
 * @param bitmapFormatValue The Bitmap Configuration enum value.
 * @return Matching Bitmap.Config  for the enum value passed.
 */
private static Bitmap.Config getBitmapConfigForFormat(int bitmapFormatValue) {
    switch (bitmapFormatValue) {
        case BitmapFormat.ALPHA_8:
            return Bitmap.Config.ALPHA_8;
         case BitmapFormat.ARGB_4444:
            return Bitmap.Config.ARGB_4444;
         case BitmapFormat.RGB_565:
            return Bitmap.Config.RGB_565;
         case BitmapFormat.ARGB_8888:
         default:
            return Bitmap.Config.ARGB_8888; // <-- fallback to 32-bpp
    }
}
```

Since Skia supports formats with more than 32-bits-per-pixel (eg. 64-bits-per-pixel, `RGBA_F16`), this can cause a mismatch between the size of the input and output bitmap buffers.

This allows an attacker to supply a malicious bitmap that will cause `CreateJavaBitmap` to create an output `JavaBitmap` with a smaller backing store than the input `SkBitmap`. This leads to a heap buffer overflow when copying the raw pixel data into the destination bitmap.

The vulnerability can be fixed by ensuring that all of the input `SkBitmap`'s parameters are supported before performing the conversion, and adding an additional size check to make sure that the destination bitmap buffer is large enough prior to doing the `memcpy`.

https://source.chromium.org/chromium/chromium/src/+/master:ui/gfx/android/java_bitmap.cc;drc=8811640591d59f0b489a7703224530b03efe127b;l=73
```c++
ScopedJavaLocalRef<jobject> ConvertToJavaBitmap(const SkBitmap* skbitmap,
                                                OomBehavior reaction) {
  DCHECK(skbitmap);
  DCHECK(!skbitmap->isNull());
  SkColorType color_type = skbitmap->colorType();
  DCHECK((color_type == kRGB_565_SkColorType) ||
         (color_type == kN32_SkColorType));
  ScopedJavaLocalRef<jobject> jbitmap = CreateJavaBitmap(
      skbitmap->width(), skbitmap->height(), color_type, reaction);
  if (!jbitmap) {
    DCHECK_EQ(OomBehavior::kReturnNullOnOom, reaction);
    return jbitmap;
  }
  JavaBitmap dst_lock(jbitmap);
  void* src_pixels = skbitmap->getPixels();
  void* dst_pixels = dst_lock.pixels();
  memcpy(dst_pixels, src_pixels, skbitmap->computeByteSize()); // <-- we use skbitmap size here, which may be larger than allocated size.

  return jbitmap;
}
```

**Patch analysis:** N/A

**Thoughts on how this vuln might have been found _(fuzzing, code auditing, variant analysis, etc.)_:**

Most likely through source-code auditing.
This issue (at least in the context that it was exploited) would have required an IPC fuzzer that was sufficiently aware to produce valid serialized `SkBitmap` objects, and that would be more work than simply auditing all of the relevant code.

**(Historical/present/future) context of bug:** 

## The Exploit

(The terms *exploit primitive*, *exploit strategy*, *exploit technique*, and *exploit flow* are [defined here](https://googleprojectzero.blogspot.com/2020/06/a-survey-of-recent-ios-kernel-exploits.html).)

**Exploit strategy (or strategies):** *Still under analysis*

**Exploit flow:** *Still under analysis*

**Known cases of the same exploit flow:** *Still under analysis*

**Part of an exploit chain?** This vulnerability was chained as the sandbox escape on Android with [CVE-2020-15999](CVE-2020-15999.md). It was delivered to Android devices running Chrome 81+, while a Chrome 1-day was delivered to Android devices running Chrome <= 80.

## The Next Steps

### Variant analysis

**Areas/approach for variant analysis (and why):** Manual source-code auditing of similar image format conversion paths, especially where incoming image data comes from an untrusted source (IPC).

**Found variants:**

* [CVE-2020-16011](https://bugs.chromium.org/p/project-zero/issues/detail?id=2112#c3): An identical bug existing in Chrome for Windows 

### Structural improvements

This specific vulnerability would not have been exploitable if it wasn't for the surprising (lack of) behaviour of Chrome's `NOTREACHED` macro in release builds; but this would not address the general class of issue.

### 0-day detection methods

## Other References 
