2

我们使用 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.

覆盖 说:

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 处取消引用 *oh,这是出站访问索引。

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

4

3 回答 3

3

这个演员表:

osr = (const struct OFPSM *) oh;

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

sizeof(struct OFPSM) = 12 字节。

sizeof(struct OFPHDR) = 8 个字节。

于 2014-05-05T17:33:39.987 回答
3

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

Coverity 正试图将您从一条路径中拯救出来,在这种路径中,您可能只以sizeof OFPHDR字节为单位分配/读取,但您却试图访问超出该分配的范围。您可以看到两种合理的可能性:您的vendor == htonl(VENDOR_A)逻辑可能执行不正确,或者您从网络读取的值是恶意制作/错误的。

您的演员假设有关调用者实现的信息,coverity 认为您无法确定 in 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.

每个同意接受 a的人都会son_of_OFPHDR *从调用者那里得到一个隐含的保证,即整个结构的内存已经分配。并且随处son_of_OFPHDR出现自动存储时长,将在那里分配足够的内存。

于 2014-05-05T18:03:04.893 回答
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.

于 2014-05-06T05:29:50.027 回答