计算机系统:程序员的视角 说:
1 /* Illustration of code vulnerability similar to that found in 2 * Sun’s XDR library. 3 */ 4 void* copy_elements(void *ele_src[], int ele_cnt, size_t ele_size) { 5 /* 6 * Allocate buffer for ele_cnt objects, each of ele_size bytes 7 * and copy from locations designated by ele_src 8 */ 9 void *result = malloc(ele_cnt * ele_size); 10 if (result == NULL) 11 /* malloc failed */ 12 return NULL; 13 void *next = result; 14 int i; 15 for (i = 0; i < ele_cnt; i++) { 16 /* Copy object i to destination */ 17 memcpy(next, ele_src[i], ele_size); 18 /* Move pointer to next memory region */ 19 next += ele_size; 20 } 21 return result; 22 }
函数copy_elements旨在复制ele_cnt数据 结构体,每个结构体由 ele_ size 字节组成,分配到一个缓冲区中 通过第 9 行的函数。所需的字节数计算如下 ele_cnt * ele_size。
但是,想象一下,恶意程序员使用以下命令调用此函数 ele_cnt 为 1,048,577 (2^20 + 1),ele_size 为 4,096 (2^12) 程序编译为 32 位。 然后在线乘法 9 将溢出,导致仅分配 4,096 字节,而不是 保存这么多数据需要 4,294,971,392 字节。循环 从第 15 行开始将尝试复制所有这些字节, 超出了分配的缓冲区的末尾,因此损坏 其他数据结构。这可能会导致程序崩溃或 否则行为不当。
我想知道如何更改代码以不因算术溢出而出现漏洞?
谢谢。
从数学角度来看,你想要检查
(size_t)-1 < ele_cnt * ele_size
。但是,由于溢出,您无法在代码中执行此操作。您可以应用一些代数来避免溢出。您还需要首先检查两个值是否均为正值:
if ((ele_size == 0) || (ele_cnt <= 0) || ((size_t)-1 / ele_size < ele_cnt)) {
return NULL;
}
关于转换
(size_t)-1
,因为 size_t
是无符号类型,所以转换定义良好,并且计算结果为可以存储在 size_t
中的最大值。