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 后,在第 16 行中释放处理程序 h。