先日、SpectreとMeltdownと、あるプロセスが別のプロセスのメモリにアクセスする機能について考えていました。
私のLinuxシステムでは、JavaScriptをすべて無効にして、一部のJSプログラムがメモリに不適切な方法でアクセスする可能性を排除しています。一部のWebサイトでJSの動作が必要な場合は、最初に他のすべてのアプリケーションを閉じ、その単一サイトを開いた状態でブラウザーウィンドウのみを残してから、そのサイトでのみJSを有効にし、設定を元に戻します。アイデアは、メモリに機密データが含まれる可能性を減らすことです(疑似シングルタスク)。
しかし、それで私は考えました:
プログラム/カーネルが実際にメモリを解放すると、RAM=の内容が消去されますか?
または、別のプログラムが前のコンテンツをRAMに保持しながら、別のプロセスが上書きするまで)別のプログラムがそのメモリを割り当てる可能性を単に提供しますか?(キャッシュなどについて考えます)
1が有効である場合-私がやっていることは(ある程度)意味があるかもしれません。しかし、2が実際のケースである場合、それは完全に無駄かもしれません。
これはどのように機能するのでしょうか?それについての実際の事実を共有してください。
直接的な答えを与えるのではなく、ほとんどが「依存する」ことになるため、Windowsでのメモリ割り当ての動作を説明している最近の鉱山の発見を紹介する方が興味深いと思うので、そのすべての背後にあるコンテキストを得ました。 Linuxのメモリ管理モデルについては十分に理解していないので、その点についてはコメントしませんが、かなり似ていると言われています。
最近、Windowsカーネルが提供するW-Xメモリ保護機能について考えていました。これは "動的コードポリシー" として知られています。アイデアは、アプリケーションにマップされたページが書き込み可能としてマークされると、実行可能としてマークされることは決してないということです。これは、シェルコードの配信を含むほとんどすべてのクラスのエクスプロイトを防ぐため、強力なエクスプロイト緩和策です。バッファオーバーフローを実行して、命令ポインタの制御を取得し、VirtualProtectへのROPを実行して、ペイロードをRWXとしてマークし、実行することはできません。メモリを書き込みおよび実行できないため、VirtualProtect呼び出しは失敗します。
ここでの一般的なバイパスについての私の考えは、VirtualAllocにいくつかの読み取り+書き込みメモリ、VirtualFreeを実行し、次にVirtualAllocを読み取り+実行として再度実行して、同じページを再割り当てできるようにすることでした。結局のところ、これは機能しません。質問に関連する理由。
Windowsのメモリ管理がページをスクラブしてゼロにするケースは3つあります。
MEM_RESET
としてマークされたとき最初のものは私の計画を妨げます。プロセスには、コミットすることなく仮想アドレス空間を割り当てることができます。 MEM_RESERVE
でVirtualAllocを呼び出す。予約されたアドレス空間は、物理メモリやスワップに直接マッピングされていませんが、必要に応じてプロセスが使用できるように保持されています。実際にメモリを使用するには、ページをコミットする必要があります。 MEM_RESERVE | MEM_COMMIT
を使用してVirtualAllocを呼び出す。コミットされると、まだ他の方法でページがゼロにされていない場合、ページはゼロになります。このように、書き込み可能なデータを割り当て、それを解放し、実行可能ファイルとして割り当てるという私のトリックは、メモリマネージャーがページをゼロにするため壊れています。
2番目のものも興味深いです。ここまででメモリブロックの使用を終了し、後で再び使用する場合は、MEM_RESET
を使用してページをリセットできます。これは、プロセスからページをデコミットしないことをメモリマネージャーに示しますが、内部に含まれるデータは重要ではないため、ページをディスクにスワップアウトする必要はありません。空き時間がある場合、システムはこれらのページをバックグラウンドでゼロにします。ただし、システムがMEM_RESET_UNDO
フラグを使用してページをまだゼロに設定していない場合、アプリケーションはリセットフラグを元に戻すことを要求できます。
3番目のオプションは、ページをデコミットして解放することです。これは、メモリマネージャーが他のプロセスで完全に再利用できることです。ページにデータが含まれている場合は、ダーティとしてマークされます。システムは、バックグラウンドでスクラブするか、再度コミットしたときにアクティブにゼロにします。
これらは、システムレベルメモリ管理の場合です。プロセスレベルの管理は大きく異なります。 HeapAlloc、ライブラリアロケーター(malloc)、または完全にカスタムアロケーターを使用します。これらの設計では、メモリページを割り当ててコミットし、そのコミットされたブロックに加えて、独自のメモリ使用管理を実行できます。そのため、libc free()呼び出しは、実際には基礎となるメモリーページをデコミットしない可能性があります。 malloc()呼び出しがリセットされていないページを返すことも完全に可能です。これがcalloc()が存在する理由です。
問題の次の部分は、ブラウザーがこれに対して積極的な防御策を持っているかどうかです。そうかどうかはわかりません。初期化されていないメモリ読み取りの可能性を制限し、より適切に識別するために、メモリアロケータがすべての新しい割り当てられたページを明示的にゼロにする(またはそれらを何らかのマジック値、たとえば0xDEADBEEFに設定する)ことは確かに可能です。また、たとえば、Microsoft Edgeのメモリアロケーターは、メモリ破損に対するセキュリティを強化するように特別に設計されているため、割り当てのリセットもその一部です。
要約すると、状況によって異なります。
OSの観点からは、解放後にメモリを消去する必要はありません。また、コストのかかる操作であるため、可能性は高いです。したがって、非常に特別なカーネルがない限り、アプリケーションを閉じた後、物理メモリに機密情報が含まれていないという保証はありません。