潜在的越界写入¶
ID: cpp/overrunning-write
Kind: problem
Security severity: 9.3
Severity: error
Precision: medium
Tags:
- reliability
- security
- external/cwe/cwe-120
- external/cwe/cwe-787
- external/cwe/cwe-805
Query suites:
- cpp-security-extended.qls
- cpp-security-and-quality.qls
程序执行缓冲区复制或写入操作,但对复制的大小没有上限,并且似乎某些输入会导致在这种情况下发生缓冲区溢出。除了导致程序不稳定之外,还存在一些技术可能允许攻击者利用此漏洞执行任意代码。
建议¶
始终控制缓冲区复制和缓冲区写入操作的长度。应使用 strncpy
而不是 strcpy
,使用 snprintf
而不是 sprintf
,并且在其他情况下应优先使用“n 变体”函数。
示例¶
void sayHello(uint32_t userId)
{
char buffer[18];
// BAD: this message overflows the buffer if userId >= 10000
sprintf(buffer, "Hello, user %d!", userId);
MessageBox(hWnd, buffer, "New Message", MB_OK);
}
在此示例中,对 sprintf
的调用将写入一个 14 个字符(包括终止空字符)的消息以及将 `userId` 转换为字符串的长度,写入到一个只有 18 个字符空间的缓冲区中。因此,如果 `userId` 大于或等于 `10000`,则最后的字符会溢出缓冲区,导致未定义的行为。
要解决此问题,应进行以下更改
通过使用编译时常量声明缓冲区来控制缓冲区的大小。
最好将对
sprintf
的调用替换为snprintf
,并使用定义的缓冲区常量大小或 `sizeof(buffer)` 作为要写入的最大长度。这将防止缓冲区溢出。或者,如果预期 `userId` 小于 `10000`,则在 `userId` 超出范围时返回或抛出错误。
否则,请考虑将缓冲区大小至少增加到 25 个字符,以便无论 `userId` 的值是多少,消息都能正确显示。
参考¶
CERT C 编码标准:STR31-C。确保字符串的存储空间足以容纳字符数据和空终止符。
CERT C++ 编码标准:STR50-CPP。确保字符串的存储空间足以容纳字符数据和空终止符。
常见弱点枚举:CWE-120。
常见弱点枚举:CWE-787。
常见弱点枚举:CWE-805。