Coverity静态分析代码缺陷

时间:2014-05-05 17:21:15

标签: c coverity

我们使用Coverity来检测代码中的漏洞。基本上这是代码片段:

static int vendor_request(
      const struct OFPHDR *oh, 
      size_t length, 
      const struct OFPUTIL_MT **typep
      )
   {
      const struct OFPSM *osr;
      ovs_be32 vendor;

      osr = (const struct OFPSM *) oh;

      memcpy(&vendor,  ((char*)osr + sizeof(struct OFPSM)), sizeof( vendor ));
      if (vendor == htonl(VENDOR_A))
         return (functionA(oh, typep));
      if (vendor == htonl(VENDOR_B))
         return (functionB(oh, length, typep));
      else
         return 0;
   }

下面,

sizeof(struct OFPSM) = 12 bytes.

sizeof(struct OFPHDR) = 8 bytes.

Coverity说:

CID xxxxx (#1 of 2): Out-of-bounds access (OVERRUN)   
1. overrun-buffer-val: Overrunning struct type OFPHDR of 8 bytes by passing it to a function which accesses it at byte offset 12. Pointer osr indexed by constant 12U through dereference in call to memcpy.

基本上,struct OFPHDR是TCP层之上的PDU,它的大小是8个字节,但它可以根据OFP消息的类型而变化。 Coverity说我在字节偏移量索引12处取消引用*哦,这是一个出境访问索引。

但我不明白这个问题,因为我将OFPHDR类型转换为12字节的正确结构然后解除引用。那么,如何避免这种错误?

3 个答案:

答案 0 :(得分:3)

这个演员:

osr = (const struct OFPSM *) oh;

正在打破严格的别名规则,因为它正在转换为不兼容的类型。 很明显它们是不相容的,因为你说:

  

sizeof(struct OFPSM)= 12个字节。

     

sizeof(struct OFPHDR)= 8个字节。

答案 1 :(得分:3)

  

但我不明白这个问题,因为我将OFPHDR类型转换为12字节的正确结构然后解除引用。

Coverity正试图将你从一个可能只分配/读入sizeof OFPHDR字节的路径中拯救出来,但是你尝试在该分配之外进行访问。你可以看到两种合理的可能性:你的vendor == htonl(VENDOR_A)逻辑可能被错误地实现,或者你从网络中读取的值被恶意制作/错误。

您的演员会提供有关调用者执行情况的信息,该调用者认为您无法在vendor_request中确定。

  

那么,怎么可以避免这个错误呢?

您可以通过更改vendor_request来避免它:

typedef union {
       struct OFPHDR oh;
       struct OFPSM  osm;
} son_of_OFPHDR;

static int vendor_request(
      const son_of_OFPHDR *oh, 
      size_t length, 
      const struct OFPUTIL_MT **typep
      )

这明确告诉编译器,静态检查器和人类oh输入可能是OFPHDR,也可能是OFPSM

每个同意接受son_of_OFPHDR *的人都有来自呼叫者的隐含承诺,即已经分配了整个结构的内存。并且son_of_OFPHDR显示自动存储持续时间,将在那里分配足够的内存。

答案 2 :(得分:1)

每个人,谢谢你的答案。

@PeterSW:结构是不兼容的,但正如我所提到的,OFPHDR是TCP层之上的PDU,它的大小是可变的。我们需要从该指针中提取(供应商)的信息位于其第12个字节偏移量上。

这可以通过将其类型转换为正确的结构来解决,该结构的大小足以包含超过12个字节并包含该元素(供应商):

struct OFPVSM {
    struct OFPSM osm;
    ovs_be32 vendor;            /* Vendor ID:
    /* Followed by vendor-defined arbitrary additional data. */
};

下面,

sizeof(struct OFPVSM) = 16 bytes.

git diff格式的解决方案:

-   const struct OFPSM *osr;
+   const struct OFPVSM *osr;

-   osr = (const struct OFPSM *) oh;
+   osr = (const struct OFPVSM*) oh;

很抱歉没有提及至关重要的信息:

struct OFPSM实际上由struct OFPHDR

组成
struct OFPSM{
    struct OFPHDR header;
    ovs_be16 type;
    ovs_be16 flags;
};

“供应商”位于struct OFPSM的末尾。