MEM06-C. 機密情報はディスクに書き出さない
開発者は、パスワードや秘密鍵といった機密情報をうっかり漏えいしないための対策をとるべきである。機密情報のディスクへの書き出しも、この対象となる。
データをうっかりディスクに書き出してしまうおもな原因としては、スワッピング と コアダンプの2つのメカニズムがある。
汎用OSの多くは、ページングと呼ばれる(スワッピングとも呼ばれる)仮想メモリ管理技法を実装し、メインメモリとディスクドライブなど補助記憶装置との間で、メモリページを転送する。この機能は通常、OSのカーネルが実行するタスクとして実装されており、実行中のプログラムからは不可視である。
コアダンプとは、プロセスメモリの状態を記録したデータであり、後でデバッガで調査できるようディスクに書き出される。通常、コアダンプが生成されるのは、エラーによるクラッシュや、終了を引き起こすシグナルを受信した結果として、プログラムが異常終了した場合である。
プロセスのリソース消費を制御する POSIX 標準のシステムコール setrlimit()
を使用することで、コアダンプを生成しないように設定することができる。これにより、プログラムを停止させる能力のある攻撃者がコアダンプに含まれる機密情報にアクセスすることを阻止できる。
違反コード
以下のコード例では、機密情報が、動的に割り当てられたバッファ secret
に格納される。このメモリ領域は、しかるべく処理された後、free()
の呼び出しにより解放される。secret
を含むメモリページはディスクにスワップアウトされる可能性がある。また、free()
を呼び出す前にプログラムがクラッシュすると、secret
に格納された情報がコアダンプに含まれているかもしれない。
char *secret; secret = (char *)malloc(size+1); if (!secret) { /* エラー処理 */ } /* secret を使った処理... */ free(secret); secret = NULL;
適合コード (POSIX)
情報がコアダンプに書き出されないようにしたければ、setrlimit()
を使用してプログラムが生成するコアダンプのサイズを 0 にすべきである。
#include <sys/resource.h> /* ... */ struct rlimit limit; limit.rlim_cur = 0; limit.rlim_max = 0; if (setrlimit(RLIMIT_CORE, &limit) != 0) { /* エラー処理 */ } char *secret; secret = (char *)malloc(size+1); if (!secret) { /* エラー処理 */ } /* secret を使った処理... */ free(secret); secret = NULL;
適合コード (特権を持つプロセス、POSIX)
mlock()
を使うことで強化できるセキュリティは、限られたものに過ぎない(Nick Stoughton による補足説明を参照)。
特権を持つプロセスは、POSIX mlock()
関数を使用してメモリをロックすることにより、ページングを無効にできる [Open Group 2004]。こうすることで、メモリが不揮発性記憶装置であるハードディスクにコピーされ無期限に保存されることを防止できる。
以下のコードでは、コアファイルの作成を無効にするだけでなく、バッファがハードディスクにスワップされないようにしている。
#include <sys/resource.h> /* ... */ struct rlimit limit; limit.rlim_cur = 0; limit.rlim_max = 0; if (setrlimit(RLIMIT_CORE, &limit) != 0) { /* エラー処理 */ } long pagesize = sysconf(_SC_PAGESIZE); if (pagesize == -1) { /* エラー処理 */ } char *secret_buf; char *secret; secret_buf = (char *)malloc(size+1+pagesize); if (!secret_buf) { /* エラー処理 */ } /* 環境によっては、アドレスは PAGESIZE の倍数である必要がある */ secret = (char *)((((intptr_t)secret_buf + pagesize - 1) / pagesize) * pagesize); if (mlock(secret, size+1) != 0) { /* エラー処理 */ } /* secret を使った処理... */ if (munlock(secret, size+1) != 0) { /* エラー処理 */ } secret = NULL; free(secret_buf); secret_buf = NULL;
適合コード (特権を持つプロセス、Windows)
特権を持つ Windows プロセスは、VirtualLock()
(Windows)を使用してメモリをロックすることで、ページングを無効にできる [MSDN]。
char *secret; secret = (char *)malloc(size+1); if (!secret) { /* エラー処理 */ } if (VirtualLock(secret, size+1) != 0) { /* エラー処理 */ } /* secret を使った処理... */ free(secret); secret = NULL;
リスク評価
ディスクに書き出された機密情報は、後で攻撃者により取得される可能性がある。OSによるディスクに対するアクセス制限は、ディスク管理プログラムを使用して迂回できるだろう。
レコメンデーション |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
MEM06-C |
中 |
低 |
高 |
P2 |
L3 |
関連するガイドライン
CERT C++ Secure Coding Standard | MEM06-CPP. Ensure that sensitive data is not written out to disk |
ISO/IEC TR 24772:2013 | Memory Locking [XZX] |
MITRE CWE | CWE-591, Sensitive data storage in improperly locked memory CWE-528, Information leak through core dump files |
参考資料
[Open Group 04] | mlock() , setrlimit() |
[Wheeler 2003] | Section 7.14 Section 11.4 |
翻訳元
これは以下のページを翻訳したものです。
MEM06-C. Ensure that sensitive data is not written out to disk (revision 54)