MemTagSanitizer¶
はじめに¶
注意: このページでは開発中のツールについて説明しています。この機能の一部は計画されていますが、まだ実装されていません。2019年10月現在、MemTagSanitizerを実行できるハードウェアは存在しません。
MemTagSanitizerは、Armv8.5-A メモリタギング拡張に基づく、高速なメモリエラー検出器であり、コード強化ツールです。AddressSanitizerやHardwareAssistedAddressSanitizerと同様のエラークラスを検出しますが、オーバーヘッドは非常に低くなります。
MemTagSanitizerのオーバーヘッドは、CPUとメモリの両方で一桁台前半になる見込みです。メモリオーバーヘッドがわずかに高く、診断機能が向上したデバッグモードも計画されています。MemTagSanitizerの主なユースケースは、スタックとヒープベースの両方のメモリバグに対する強力な軽減策となることが期待される、本番バイナリでのコード強化です。
使い方¶
-fsanitize=memtag
フラグを使用してプログラムをコンパイルおよびリンクします。これは、MemTag拡張機能を備えたAArch64をターゲットとする場合にのみ機能します。これを実現する1つの方法は、コンパイルフラグに -target aarch64-linux -march=armv8+memtag
を追加することです。
実装¶
メモリ安全性へのタグベースのアプローチの概要については、HardwareAssistedAddressSanitizerを参照してください。MemTagSanitizerは同様の実装戦略に従いますが、ハードウェアによって提供されるタグストレージ(シャドウ)を使用します。
MTEハードウェア機能の簡単な概要
メモリの16バイトアラインメントごとに、4ビットの割り当てタグを割り当てることができます。
すべてのポインタは、最上位バイトに4ビットのアドレスタグを持つことができます。
ほとんどのメモリアクセス命令は、アドレスタグ!=割り当てタグの場合に例外を生成します。
高速なタグ操作のための特別な命令が提供されています。
スタックのインストルメンテーション¶
スタックベースのメモリエラーは、各ローカル変数の割り当てタグをそのライフタイムの開始時にランダムな値に更新し、そのライフタイムの終了時にスタックポインタのアドレスタグにリセットすることで検出されます。割り当てられていないスタックスペースは、SPのアドレスタグと一致することが期待されます。これにより、メモリの安全性が静的に証明できる場合は、変数のタグ付けをスキップできます。
大きな関数内の各スタック変数に真にランダムなタグを割り当てると、コードサイズのオーバーヘッドが大きくなる可能性があります。これは、各変数のアドレスが独立した再マテリアル化できない値であることを意味するため、N個のローカル変数を持つ関数は、そのライフタイムのほとんどを通して維持する必要があるN個の追加のライブ値を持ちます。
このため、MemTagSanitizerは関数ごとに最大1つのランダムタグ(「ベースタグ」と呼ばれる)を生成します。他のスタック変数がある場合は、ベースからの固定オフセットでタグが割り当てられます。
スタックのインストルメンテーションの詳細については、このドキュメントを参照してください。
ヒープのタグ付け¶
注意: この部分は2019年10月現在実装されていません。
MemTagSanitizerは、Scudo Hardened Allocatorに、次の場合にメモリタグを更新する追加コードを組み込んで使用します。
新しいメモリがシステムから取得された場合。
割り当てが解放された場合。
一致するアドレスタグを持つポインタが返される限り、malloc()で割り当てられたメモリの大部分に対して割り当てタグを変更する必要はありません。