UFM.FFM.MUST

解放されたメモリが再度解放される

メモリが、解放後に使用または参照されるか、2 回解放されると、予想外の結果が生じる可能性があります。メモリ参照問題により、予期しない値の使用が引き起こされ、それが原因でプログラムがクラッシュしたり任意のコードが実行されたりする可能性があります。

メモリ解放後使用エラーまたはメモリの二重解放エラーは通常、エラー状況または例外、未解決の競合状態、あるいはプログラムのさまざまな部分の間でメモリの担当責任が混乱しているときに発生します。UFM チェッカーは、コードのさまざまなメモリ解放後使用またはメモリの二重解放状況のインスタンスを探します。UFM.FFM.MUST チェッカーは、既に解放されたメモリが再度解放される状況にフラグを立てます。

脆弱性とリスク

メモリ参照問題は、重大な問題であることがわかることがあります。以前に解放されたメモリを使用すると、特定の状況に応じて、有効なデータが破損されるか、恣意的なコードが実行される可能性があります。メモリが解放されても、再度割り当てられるかリサイクルされないと、内容がそのまま残って、アクセスできる状態のままになる可能性があります。解放された場所にあるデータは、有効であるように思えるかもしれませんが、予想外に変化して意図しないコード動作を引き起こすことがあります。

メモリが解放されて元のポインターが再度使用された後に、メモリが別のポインターに割り当てられた場合、新しい割り当てでの場所をポイントする可能性があります。データが変化すると、有効な方法で使用されたメモリが破壊され、未定義のアクションが生じる可能性があります。関数ポインターが有効なコードのアドレスで上書きされた場合、悪意のあるユーザーが任意のコードを実行することができます。

プログラムが同じメモリを 2 回解放すると、メモリ管理データ構造が破壊され、プログラムがクラッシュしたり、2 つの後の関数呼び出しで同じポインターが返されたりすることがあります。この場合、攻撃者は二重に割り当てられたメモリに書き込まれるデータを制御できるようになることがあります。このメモリが今度は、バッファオーバーフロー攻撃に対して脆弱になります。

軽減と防止

メモリ参照問題を回避するには:

  • ポインターが解放されたら、null に設定します。
  • グローバル変数は一度しか解放されないことを確認します。
  • ループまたは条件ステートメントでメモリを解放するときおよび、realloc 関数を使用しているときは特に注意します。
  • クリーンアップルーチンがメモリ割り当てのステートを尊重していることを確認します。

脆弱コード例

コピー
  #include <stdlib.h>
  
  typedef struct x {
      char * field;
  } tx;
  
  void release(tx * a){
      free(a->field);
      free(a);
 }
 
 int main() {
     tx *a = (tx *)malloc(sizeof(tx));
     if (a==NULL) return;
     a->field = (char *)malloc(10);
     release(a);
     free(a->field);
     free(a);
     return 0;
 }

Klocwork は 'a->field' によってポイントされるメモリが、16 行目で 'release' 関数の呼び出しによって解放された後に 18 行目で解放されることを示すレポートを生成します。通常、メモリの割り当てと解放は、この例のコードでは削除されている離れたポイントで行われるので、そのような状況を認識するのは困難になります。いずれにしても、既に解放されたメモリを再度解放することの結果は、予測不可能で重大な結果になることがよくあります。