Use-After-Free【UAF】
概要
次

プログラムは実行中、データを格納するためにメインメモリ中の領域を必要な容量だけ動的に確保し、不要になった時点でシステムに返却する。返却されたメモリ領域は以降、別の用途に再割り当てされる可能性がある。
ところが、C言語やC++言語のように開発者がメモリを手動で管理する言語では、解放後も元のアドレスを指したままのポインタ変数が残ることがある。これを「ダングリングポインタ」(dangling pointer)という。プログラムが誤ってこのポインタを通じてメモリを読み書きすることで、Use-After-Freeが発生する。
発生の原因としては、メモリを解放するタイミングの誤りや、複数の処理が同じオブジェクトを共有する際の同期不備、参照カウントの管理ミスなどがある。特に並列処理では、一方がオブジェクトを解放した直後に別の処理が同じ領域へアクセスして発生する例が少なくない。
脆弱性としてのUAF
問題が単なる異常終了に留まらないのは、攻撃者がこの挙動を悪用できるためである。解放されたメモリ領域は、別のmalloc呼び出しにより再利用されることがある。攻撃者はこの不具合が存在するソフトウェアを狙い、解放済み領域に任意のデータをあらかじめ書き込んでおき、プログラムがUse-After-Free経由でそのデータを関数ポインタとして呼び出すよう誘導する。
これにより、攻撃者のコードを実行させることが可能になる。Webブラウザのレンダリングエンジンで悪用された場合は細工されたWebページを閲覧させるだけで攻撃が成立し、OSカーネルで悪用された場合は一般利用者の権限から管理者権限への特権昇格につながる。危険性が高い不具合で、CVSSスコアが9点を超える致命的な脆弱性として報告された事例も多い。
主な対策
対策としては、解放後のポインタを無効化することや、C++の「スマートポインタ」など寿命管理を自動化する仕組みを利用すること、「AddressSanitizer」のようなメモリ検査ツールや静的解析ツールを開発段階で活用することが挙げられる。より根本的な手段として、Rustのようにコンパイラがメモリの所有権と生存期間を静的に検査することができる言語や、JavaやC#のようにガベージコレクションによって参照されなくなったオブジェクトを自動回収する言語の採用も有効である。