2

コードスニペット:

int secret_foo(void)
{
  int key = get_secret();
  /* use the key to do highly privileged  stuff */
  ....

  /* Need to clear the value of key on the stack before exit */
  key = 0;      
  /* Any half decent compiler would probably optimize out the statement above */
  /* How can I convince it not to do that? */

  return result;
}

(コードに示されているように) ingkeyの前にスタックから変数の値をクリアする必要があります。return

ご参考までに、これは実際の顧客要件 (埋め込みドメイン) でした。

4

4 に答える 4

8

使用できますvolatile(強調鉱山):

volatile 修飾された型の左辺値式を介して行われるすべてのアクセス (読み取りと書き込みの両方) は、最適化のために観察可能な副作用と見なされ、抽象マシンの規則に従って厳密に評価されます (つまり、すべての書き込みは次の時点で完了します)。次のシーケンスポイントの少し前)。これは、単一の実行スレッド内で、揮発性アクセスを最適化して除外したり、揮発性アクセスからのシーケンス ポイントによって分離された別の目に見える副作用と比較して並べ替えたりすることができないことを意味します。

 volatile int key = get_secret();
于 2016-05-26T21:41:58.587 に答える
3

volatile変数の他のすべての使用にも影響を与えるため、時にはやり過ぎかもしれません。

使用memset_s(C11 以降): http://en.cppreference.com/w/c/string/byte/memset

memset は、この関数によって変更されたオブジェクトがその存続期間中に再びアクセスされない場合、(as-if ルールの下で) 最適化されて取り除かれます。そのため、この関数を使用してメモリをスクラブすることはできません (たとえば、パスワードを格納した配列をゼロで埋めるなど)。この最適化は memset_s では禁止されています。メモリ書き込みの実行が保証されています。

int secret_foo(void)
{
  int key = get_secret();
  /* use the key to do highly privileged  stuff */
  ....

  memset_s(&key, sizeof(int), 0, sizeof(int));
  return result;
}

ここで、さまざまなプラットフォーム/C 標準の他のソリューションを見つけることができます: https://www.securecoding.cert.org/confluence/display/c/MSC06-C.+Beware+of+compiler+optimizations

補遺:他の問題を指摘するこの記事を参照してください(実際のバッファーをゼロにする以外に):

少し注意を払い、協調的なコンパイラーを使用すればバッファーをゼロにすることができますが、それは私たちが必要としているものではありません。私たちがしなければならないことは、機密データが保存されている可能性のあるすべての場所をゼロにすることです。そもそも機密情報をメモリに保持していたのは、それを使用できるようにするためだったことを思い出してください。そして、その使用により、ほぼ確実に、機密データがスタックとレジスターにコピーされました。

コンパイラkeyによって値が別の場所 (レジスタまたは一時的なスタック/メモリの場所など) にコピーされた可能性があり、その場所をクリアするための制御がありません。

于 2016-05-26T22:03:03.630 に答える
1

動的割り当てを使用すると、そのメモリのワイプを制御でき、システムがスタックで行うことに拘束されなくなります。

int secret_foo(void)
{
  int *key = malloc(sizeof(int));
  *key = get_secret();
  memset(key, 0, sizeof(int));
  // other magical things...
  return result;
}
于 2016-05-26T21:50:49.963 に答える
1

1 つの解決策は、最適化を望まないコードのセクションのコンパイラの最適化を無効にすることです。

int secret_foo(void) {
     int key = get_secret();
     #pragma GCC push_options
     #pragma GCC optimize ("O0")

         key = 0;

     #pragma GCC pop_options
     return result;
}
于 2016-05-26T21:56:40.453 に答える