我们使用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字节的正确结构然后解除引用。那么,如何避免这种错误?
答案 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
的末尾。