件のAndroidのPNG脆弱性

2019年2月に公開された，PNG画像を読み込むと任意のコードが実行されてしまう脆弱性が気になったので，個人的に雑に調べていた.

公式には以下のように書かれている.

https://source.android.com/security/bulletin/2019-02-01.html

> Framework
> The most severe vulnerability in this section could enable a remote attacker using a specially crafted PNG file to execute arbitrary code within the context of a privileged process.

## 影響範囲
パッチを眺めると Android に取り込まれている [Skia](https://skia.org/) のコードが修正されている（Skia 自体はいろんなブラウザ製品のソフトウェアレンダリングでも使われているらしい）. 自力で native の decoder を用意するとかしていない限り，PNG 画像を読み込む Android アプリは影響を受けるのではなかろうか.

## パッチの提供対象
Android 7.0, 7.1.1, 7.1.2, 8.0, 8.1, 9 となっている.

Android 6 (Marshmallow) の最終アップデートが October 3, 2017 となっているので 6 以前はすでにサポート範囲外の可能性が高そう.

### 蛇足
ただし以下のタグを見ていると android-6.0.1_r80 と android-7.1.2_r28 でそもそも存在するファイルが違ったりする（例えば SkPngCodec は 6以前のOSに含まれていない）. 今回と同様の脆弱性があったのか判断しがたい..

https://android.googlesource.com/platform/external/skia/+refs

以下を見ても 7 へのアップグレードで画像の decoder に何か手を加えたとは書いていない.

- https://developer.android.com/about/versions/nougat/android-7.0?hl=ja
- https://developer.android.com/about/versions/nougat/android-7.1?hl=ja

以下のような質問が残っているところを見ると，６あたりまで JPEG は skia の自前実装で PNG は libpng のラッパークラスを使っていて，７から libpng を使うのをやめて PNG も自前実装になったと見るべきか？（今回の脆弱性は７で注入された？）

https://stackoverflow.com/questions/16895036/why-png-compression-is-that-much-slower-than-jpeg-on-android

## パッチ
パッチが当たっているのは https://android.googlesource.com/platform/external/skia/+/master/src/codec 配下のファイル群. 主に以下のようなパッチが当たっている. サクッと眺めた限りだと入力チェックの追加と読み込み先の記憶領域の初期化が追加されている雰囲気（だけどコードを最後までちゃんと追いかけたわけではないので間違っているかも）.

https://android.googlesource.com/platform/external/skia/+/8157d73fb620bc463eb26e974fe92d3259e7545a%5E%21/

```
- Initialize rowsDecoded in SkSampledCodec. Otherwise,
fillIncompleteImage may be called with an uninitialized
value. This change was originally uploaded to AOSP as
https://android-review.googlesource.com/c/platform/external/skia/+/785816
- If SkPngCodec hits an error, still transform from the
interlace buffer (if needed) and set rowsDecoded properly.
- Do not copy uninitialized memory from the interlace buffer.
- Make BRD treat kErrorInInput like kIncompleteInput. The two errors
are different for the purposes of incremental decode. For a direct
decode, they're essentially the same - part was decoded, but then
the decode was interrupted. This allows testing images with
errors on the bots without reporting a failure.

Originally uploaded as https://skia-review.googlesource.com/c/skia/+/161822

- Also includes SkPngCodec SafetyNet logging from
https://skia-review.googlesource.com/c/skia/+/170354


Change-Id: Ie170abf65393feb4edba60aa941f2783fe18cd8b
(cherry picked from commit fc165d5cccf133574058cd0c5ba3a95ea6ad2bb8)
```

https://android.googlesource.com/platform/external/skia/+/654579dbab7cf3a566636bcc7d6617d5ac938f38%5E%21/

```
Because we're sampling, the offset ends up the same as the width. Back
up to the left enough to fit the bytes we will write.

Include SafetyNet logging from
https://skia-review.googlesource.com/c/skia/+/171227

Change-Id: Ie476a0191b66c2322446b9c0922f630d6e971645
Reviewed-on: https://skia-review.googlesource.com/c/164262
(cherry picked from commit 1a1cec98427fdc9e94614580ec42dbe936c47c55)
```

https://android.googlesource.com/platform/external/skia/+/0056606ac49688dcf3c08a51ca98fd94d9bf1897%5E%21/

```
Remove conflicting changes in infra. Resolved conflicts in:
- src/codec/SkHeifCodec.cpp
- src/codec/SkJpegCodec.cpp
- src/codec/SkSwizzler.cpp

Use old version of SkEncodedInfo::Make
Remove references to SkEncodedInfo::kXAlpha_Color and ::k565_Color
which are unused by Android.

Also include SafetyNet logging from
https://skia-review.googlesource.com/c/skia/+/171222.

Original message follows:

Bug: chromium:897031
Bug: chromium:896776

Prior to this fix, we would treat the output from such a JPEG
as if it were a 16 bit per component RGB PNG. We hit an assert
in debug, but in release mode we do the wrong thing.

Split up SkSwizzler::CreateSwizzler into two public factories
(and a private one) based on whether format conversion is desired.
Without format conversion, we may have already converted (as is
the case with this JPEG), so the SkEncodedInfo::Color is not relevant.
That flavor of the factory just needs to know the bytes per pixel,
so provide that info instead.

Add a test file to Google Storage: apron.jpg, from Chromium's
benchmark files.

Change-Id: Idd8a11a8da5c0a77a4348a6ee37a984137b39f19
(cherry picked from commit c880585df188439eb0d4dd4ad2cdeb1ac48719fc)
```

## CVE
CVE にはエントリーだけ登録されており，どういう内容かまでは記載されていない？

- http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1986
- http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1987
- http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1988

## 関連

- [なぜ iPhone の画像は Android の画像よりもずっと高品質なのか](https://qiita.com/KeithYokoma/items/c7f32a77402410545edb)