SV.INCORRECT_RESOURCE_HANDLING.WRONG_STATUS

安全でないリソース処理 - ステータスの確認

リソース管理の指摘は、消費過剰やリソースの枯渇につながります。リソースが割り当てられると、リソースの適切な解放とすべての潜在的な終了パスの占有が重要となります。同様に、リソースが解放されてから、または、既に解放された場合は閉じてから要求されることがないよう、コードは要求と解放を追跡することが必要です。このタイプの欠陥は、例外やエラー処理のため、関数が終了する際にしばしば生じます。

SV.INCORRECT_RESOURCE_HANDLING.WRONG_STATUS チェッカーは、現在のステータスがそのアクションと互換性がない場合にリソースが要求または解放される状況にフラグを立てます。たとえば、リソースコードは、オープンになったことがない場合、リソースを解放しようとします。

チェッカーは、不正確なリソース処理について、次の POSIX リソースを解析します。

  • 標準入力/出力リソース:ファイル記述子、ファイル、パイプストリーム
  • X/オープンシステムインターフェイス (XSI) リソース:メッセージ、セマフォ、共有メモリ
  • リアルタイムリソース:メッセージキュー、セマフォ、共有メモリ、型指定メモリオブジェクト、プロセス生成、クロック、タイマー
  • スレッドのリソース:スレッド、ミューテックス、条件変数、バリア、読み取り/作成ロックオブジェクト、スピンロックオブジェクト
  • ソケット
  • トレース

詳細については、オープングループ基本指定の最新の指摘を参照してください。

脆弱性とリスク

この状況は大したセキュリティリスクではありませんが、不正確なエラー処理が原因で、ソフトウェアの信頼性が問題となる可能性があり、機密データを開示する結果となる可能性もあります。攻撃者がリソースリークを意図的にトリガできる場合、リソースのプールはサービス拒否 (DoS) の段階まで削減されます。

軽減と防止

割り当てられたすべてのリソースが解放されることと、関数とアプリケーションのリソースの割り当てと解放が一致していることを確認することは、よい対処法です。リソースが適切に割り当てられて解放されることを確認するために、エラー条件をチェックする必要があります。

脆弱コード例

コピー
   #include <stdio.h>
   #include <mqueue.h>
  
   void message_unchecked(const char* name, const char* data1, const char* data2)
   {
         char c;
         mqd_t h;
         if ((h = mq_open(name, O_RDWR)) != (mqd_t)-1)
         {
                      mq_receive(h, &c, 1, NULL);
                      if (c == '1')
                               mq_send(h, data1, strlen(data1)+1, 2);
                      else
                      if (c == '2')
                               mq_send(h, data2, strlen(data2)+1, 2);
        }
        else
        {
                      fprintf(stderr, "'mq_open' failed for %s\n", name);
        }
        mq_close(h); // Handler status might be wrong here.
  }

Klocwork は 21 行目で、この場合はクローズにできないが、先行するコードによってはハンドラーのリソースがこの時点でオープンにならない可能性があることを示す欠陥レポートを生成します。このような不正確なリソース処理は、ソフトウェアの信頼性の問題の原因となる可能性があります。

修正コード例

コピー
   #include <stdio.h>
   #include <mqueue.h>
  
   void message_unchecked(const char* name, const char* data1, const char* data2)
   {
         char c;
         mqd_t h;
         if ((h = mq_open(name, O_RDWR)) != (mqd_t)-1)
         {
                      mq_receive(h, &c, 1, NULL);
                      if (c == '1')
                               mq_send(h, data1, strlen(data1)+1, 2);
                      else
                      if (c == '2')
                               mq_send(h, data2, strlen(data2)+1, 2);
        mq_close(h);
        }
        else
        {
                      fprintf(stderr, "'mq_open' failed for %s\n", name);
        } 
  }

修正されたコード例では、'mq_send' への呼び出しの後で、ハンドラー 'h' は 16 行目で解放されます。