MEM03-C. 再利用可能なリソースに格納された機密情報は消去する
再利用可能なリソースに格納された機密情報は、適切に消去しないと権限の低いユーザや攻撃者に漏れる可能性がある。再利用可能なリソースの一例を以下に示す。
- 動的に割り当てられたメモリ
- 静的に割り当てられたメモリ
- 自動的に割り当てられた(スタック)メモリ
- メモリキャッシュ
- ディスク
- ディスクキャッシュ
機密情報を正しく消去する方法は、リソースの種類やプラットフォームにより異なる。
違反コード (free()
)
動的メモリ管理関数は、解放したメモリの内容を消去することを義務付けられておらず、実行時に余分な負荷がかかるため通常は消去しない。また、動的メモリ管理関数は解放済みの同じメモリを再度割り当てることができる。その結果、動的メモリを解放する関数を呼び出す前に機密情報を消去しなければ、誤って機密情報を漏えいしてしまう可能性がある。プログラマは、メモリが割り当てられるときにその内容が必ず初期化されると想定してはならない(「MEM09-C. メモリ割り当て関数がメモリを初期化すると想定しない」を参照)。
情報漏えいを防ぐには、動的に割り当てたメモリ領域を解放する前に、機密情報を消去する必要がある。動的に割り当てられたメモリ領域に対して free()
を呼び出すと、割り当てられていた領域は解放され、以後の割り当てで再利用される。しかし、再利用されるメモリ領域内に、それまで格納されていたデータが残っていることがある。このメモリ領域に機密情報が含まれていると、その情報が誤って漏えいしてしまう可能性がある。
以下のコード例では、secret
が参照する動的に割り当てられたメモリ内の機密情報が、動的に割り当てられたメモリ領域 new_secret
にコピーされる。この領域に対して処理が行われ、最終的に free()
の呼び出しによって解放される。メモリの内容が消去されていないため、プログラムの他のセクションで再度割り当てが行われ、そこで new_secret
に格納されていた情報が誤って漏えいする可能性がある。
char *secret; /* secret の初期化 */ char *new_secret; size_t size = strlen(secret); if (size == SIZE_MAX) { /* エラー処理 */ } new_secret = (char *)malloc(size+1); if (!new_secret) { /* エラー処理 */ } strcpy(new_secret, secret); /* new_secret に対する処理... */ free(new_secret); new_secret = NULL;
適合コード
情報漏えいを防ぐには、機密情報を含む動的メモリは解放前に初期化する必要がある。これは通常、割り当てられたメモリ領域のデータを消去する('\0'
文字をメモリ領域に書き込む)ことで行う。
char *secret; /* secret の初期化 */ char *new_secret; size_t size = strlen(secret); if (size == SIZE_MAX) { /* エラー処理 */ } /* calloc() を使用して、割り当てられた領域にゼロを書き込む */ new_secret = (char *)calloc(size+1, sizeof(char)); if (!new_secret) { /* エラー処理 */ } strcpy(new_secret, secret); /* new_secret に対する処理 ... */ /* メモリの初期化 */ memset_s(new_secret, '\0', size); free(new_secret); new_secret = NULL;
calloc()
関数は、新しく割り当てたメモリの内容を初期化する。sizeof(char)
は1になることが保証されているため、この適合コードでは calloc()
の使用時に整数オーバーフローが発生しないか検査する必要はない(「MEM07-C. calloc() の引数を乗算した結果がラップアラウンドしないことを確認する」を参照)。
memset_s()
関数の定義と使い方については、「MSC06-C. 機密データを扱う場合はコンパイラの最適化に注意する」を参照のこと。
違反コード (realloc()
)
realloc()
関数を使用してメモリの再割り当てを行う場合にも、メモリ解放の場合と同様の問題がある。realloc()
関数は、古いオブジェクトを解放し、新しいオブジェクトへのポインタを返す関数である。
realloc()
を使用して動的メモリのサイズを変更することで、機密情報を不注意に漏えいしてしまうことがある。また、「Fortify Taxonomy: Software Security Errors」 [Fortify 2006] および NIST の「Source Code Analysis Tool Functional Specification」 [Black 2007] に記載されているような、ヒープの覗き見(heap inspection)を許してしまうことがある。このコード例では、realloc()
が呼び出されると、より大きな新しいオブジェクトを割り当て、secret
の内容をこの新しいオブジェクトにコピーし、元のオブジェクトを free()
で解放し、新たに割り当てたオブジェクトへのポインタを secret
に代入する。元のオブジェクトの中身はメモリ内に残っている可能性がある。
char *secret; /* secret の初期化 */ size_t secret_size = strlen(secret); /* ... */ if (secret_size > SIZE_MAX/2) { /* エラー条件の処理 */ } else { secret = (char *)realloc(secret, secret_size * 2); }
なお、整数の乗算(secret_size * 2
)による整数オーバーフローを検知するために、secret_size
の値を確認している(「INT32-C. 符号付き整数演算がオーバーフローを引き起こさないことを保証する」を参照)。
適合コード
realloc()
はメモリの内容を消去することができないため、適合コードでは realloc()
を使用することはできない。代わりに、realloc()
と同等の関数で、ヒープバッファのサイズを変更する際に機密情報を消去するような関数を独自に用意せよ。ここでも、解放する領域を文字 '\0'
で上書きしている。
char *secret; /* secret の初期化 */ size_t secret_size = strlen(secret); char *temp_buff; /* ... */ if (secret_size > SIZE_MAX/2) { /* エラー条件の処理 */ } /* calloc() はメモリをゼロ初期化する */ temp_buff = (char *)calloc(secret_size * 2, sizeof(char)); if (temp_buff == NULL) { /* エラー処理 */ } memcpy(temp_buff, secret, secret_size); /* バッファの内容を消去 */ memset((volatile char *)secret, '\0', secret_size); free(secret); secret = temp_buff; /* サイズ変更したバッファを使う */ temp_buff = NULL;
calloc()
関数は、新しく割り当てたメモリの内容を初期化する。sizeof(char)
は1になることが保証されているため、この適合コードでは calloc()
の使用時に整数オーバーフローが発生しないか検査する必要はない(「MEM07-C. calloc() の引数を乗算した結果がラップアラウンドしないことを確認する」を参照)。
リスク評価
実際に、この種のセキュリティ上の欠陥によって、意図しない相手に機密情報を漏えいしてしまう可能性がある。「Secure Coding Principles & Practices: Designing and Implementing Secure Applications」 [Graf 2003] および Sun Security Bulletin #00122 [Sun] で議論されている Sun tarball の脆弱性は、このレコメンデーションの違反によって、機密情報漏えいが発生することを示している。ヒープ覗き見 などの技法を使うことで、攻撃者がこの欠陥を悪用して機密情報を取得することも可能である。
レコメンデーション |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
MEM03-C |
中 |
低 |
高 |
P2 |
L3 |
自動検出(最新の情報はこちら)
ツール |
バージョン |
チェッカー |
説明 |
---|---|---|---|
Compass/ROSE |
|
|
|
V. 9.1 |
SV.USAGERULES.UNINTENDED_COPY |
|
|
PRQA QA-C | 8.1 | warncall for realloc | Partially implemented |
関連するガイドライン
CERT C++ Secure Coding Standard | MEM03-CPP. Clear sensitive information stored in returned reusable resources |
ISO/IEC TR 24772:2013 | Sensitive Information Uncleared Before Use [XZK] |
MITRE CWE | CWE-226, Sensitive information uncleared before release CWE-244, Failure to clear heap memory before release ("heap inspection") |
参考資料
[Black 2007] |
[Fortify 2006] |
[Graff 2003] |
翻訳元
これは以下のページを翻訳したものです。
MEM03-C. Clear sensitive information stored in reusable resources (revision 140)