Androidが採用するLinuxカーネルには、メモリー上の実行コードやデータの配置位置をランダム化する「ASLR」(Address Space Layout Randomization)というセキュリティ機能がある。しかし32ビット環境では配置の変動量が少なく、十分な攻撃耐性を備えていなかった。2016年1月に、この問題を解消するための改良がLinuxカーネルに取り込まれた。同改良について紹介する。

 マルウエアやクラッカーなどの攻撃への耐性を高めるため、最近のOSは「ALSR」(Address Space Layout Randomization)というセキュリティ機能を備えるのが一般化している。ALSRとは、プログラムの実行コードやデータのメモリー空間における配置を、プログラム実行時などのタイミングでランダムに変化させる機能である。攻撃対象となる実行コードやデータの位置を推測困難にすることで、攻撃が成立しにくくなる効果を期待できる。

 例えばLinuxカーネルは、2005年にリリースされたバージョン2.6.12以降でASLR機能に対応している。Linuxカーネルを採用するAndroidでも、最初のバージョンであるAndroid 1.0からASLR機能は一部有効化されていた。しかし、Androidが当初備えていたプレリンクというアプリケーション起動高速化の仕組みとASLR機能の相性が悪く、完全に動作するようになったのは2012年6月にリリースされたAndroid 4.1からである。

変動幅が8ビットと小さかった

 Android 4.1以降では、LinuxカーネルのASLR機能の効果を最大限発揮できるようになった。本来ならこれで一安心となるはずだが、そうはならなかった。LinuxカーネルのASLR機能については、当初から特に32ビット環境で十分な安全性を確保できないという批判があったからだ。

 具体的には、プログラムの実行コードや共有ライブラリーの読み込みに使用するmmapというシステムコールでのASLR機能の動作に問題があった。x86やARMアーキテクチャーのような32ビット環境向けのカーネルでは、mmapで読み込んだデータの配置を8ビット幅でしか変化させていなかった(表1上)。これは、0から255までの範囲でしか値を変化させられないことを意味する。配置はメモリーページ単位で調整するため、ページサイズが通常の4Kバイトの場合は、mmap領域のアドレス変動幅は最大で1Mバイトとなる。

表1●カーネルやアーキテクチャー別のメモリー配置位置の変動幅
表1●カーネルやアーキテクチャー別のメモリー配置位置の変動幅
メモリーページのサイズが4Kバイトの場合を示した。改良後のカーネルでは、共有ライブラリーや実行コードの配置位置の変動幅をこれまでより大きく設定できることが分かる。
[画像のクリックで拡大表示]

 1Mバイトも変化するのであれば十分と思うかもしれないが、実際のランダム性は前述のように8ビット幅しかないため、高々256回の試行で攻撃が成立する恐れがある。これは非常に心許ない状況と言える。

 なお、データの一時保存に使用するヒープ領域やスタック領域については、mmap領域よりも大きな変動幅が与えられており、比較的安全である。またmmap領域についても、x86_64やARM64アーキテクチャーなどの64ビット環境向けのカーネルでは大きな変動幅が与えられている。