SV.TAINTED.CALL.DEREF

通过函数调用取消引用未验证的指针

从用户或外部环境接受输入数据时,应在使用之前验证类型、长度、格式和范围。在未经正确验证之前,将其视为已污染数据。SV.TAINTED 系列检查器查找代码中使用已污染数据的情况。

SV.TAINTED.CALL.DEREF 检查器标记出那些在取消引用操作中通过函数调用使用已污染数据的代码。

漏洞与风险

当代码的指针输入未正确验证并用于取消引用操作时,可能导致尝试读取或写入禁止内存区域,从而造成程序崩溃,或对可能非预期地读取或写入包含用户密码等敏感数据的有效内存位置。这会引发潜在的安全漏洞,可能允许攻击者执行以下操作:

  • 提供无法预料的值并导致程序崩溃
  • 读取机密数据
  • 使用恶意输入来修改数据或改变控制流
  • 导致过度的资源消耗
  • 执行任意命令

缓解与预防

要避免受污染输入错误:

  • 了解不受信任的输入进入您软件的所有可能区域:参数或自变量、cookie、读取自网络的输入、环境变量、反向 DNS 查找、查询结果、文件名、数据库以及任何外部系统;
  • 使用白名单或“已知正确”策略进行输入,而不是仅依赖于黑名单或“已知错误”策略;
  • 确保对输入的所有相关属性进行验证,包括长度、输入类型、范围、缺失或额外输入、语法以及一致性;
  • 如果应用程序的客户端有安全性检查,请确保在服务器端也进行一次安全性检查;
  • 如果应用程序组合来自多个来源的输入,请在组合来源之后再执行验证

漏洞代码示例 1

复制
  #include <sys/ipc.h>
  #include <sys/shm.h>
  #include <string.h>

  #define SHMEM_SIZE 1024

  typedef struct  S_ {
        int  transaction_id;
        int* id;
       char* str;
  } S;
 
  void  use_shared_mem_example(key_t shmem_key,  int  id) {
        int  shmem_id = shmget(shmem_key, SHMEM_SIZE, IPC_CREAT);
        S* s = (S*) shmat(shmem_id, NULL, 0);
        if  (s != (S*) (-1)) {
             *(s->id) = id;                               // dereference of untrusted pointer, flagged as SV.TAINTED.DEREF
             strcpy (s->str,  "Sample signal string" );      // dereference of untrusted pointer via call, flagged as SV.TAINTED.CALL.DEREF
        }
        shmdt(( void *) s);
  }

在上例中,指向进程之间共享内存的指针通过函数调用直接取消引用。Klocwork 通过突出 SV.TAINTED.DEREF 和 SV.TAINTED.CALL.DEREF 缺陷来标记这些操作。

在第 17 行:[SV.TAINTED.DEREF] 在第 17 行取消引用了从第 15 行的“shmat”接收到的未验证的指针“s->id”。
在第 18 行:[SV.TAINTED.CALL.DEREF] 在第 18 行通过调用“strcpy”而取消引用了从第 15 行的“shmat”接收到的未验证的指针“s->str”。

建议此代码的开发人员在执行取消引用操作之前使用可靠的指针审查(其详细信息不在此检查器的简要说明范围之内),或彻底抑制取消引用此类指针。

漏洞代码示例 2

复制
  #include <string.h>

  typedef struct  {
          void  *data;
  } request_t;

  #define MAGIC_ADDRESS ((void*)0xdeadbeef)
  #define MAGIC_SIZE 1024

 char* get_sensitive_data();
 void* read_from_port() {
      // a library function known to return pointer to untrusted data
      // for example, read from a fixed memory location
      return  MAGIC_ADDRESS;
 }

 void  unsafe_dereference() {
      request_t* req = read_from_port();
      char* data = get_sensitive_data();
      memcpy(req->data, data, MAGIC_SIZE);     // unsafe dereference inside the function, flagged by SV.TAINTED.CALL.DEREF
 }
在此示例中,在第 20 行执行了类似的取消引用被污染指针 req->data 的操作。Klocwork 发出 SV.TAINTED.CALL.DEREF 警告来标记潜在的安全问题:
[SV.TAINTED.CALL.DEREF] 在第 20 行通过调用“memcpy”而取消引用了从第 18 行的“read_from_port”接收到的未验证的指针“req->data”。

扩展

此检查器可通过 Klocwork 知识库进行扩展。有关详情,请参阅调整 C/C++ 分析。