潜在的缓冲区溢出写入¶
ID: cpp/very-likely-overrunning-write
Kind: problem
Security severity: 9.3
Severity: error
Precision: high
Tags:
- reliability
- security
- external/cwe/cwe-120
- external/cwe/cwe-787
- external/cwe/cwe-805
Query suites:
- cpp-code-scanning.qls
- cpp-security-extended.qls
- cpp-security-and-quality.qls
该程序执行缓冲区复制或写入操作,没有对复制大小的上限限制。通过分析所涉及的表达式的边界,似乎某些输入会导致这种情况下的缓冲区溢出。除了导致程序不稳定之外,还存在一些技术,攻击者可以使用这些技术利用此漏洞执行任意代码。
建议¶
始终控制缓冲区复制和缓冲区写入操作的长度。应使用 strncpy
代替 strcpy
,使用 snprintf
代替 sprintf
,在其他情况下应优先使用“n 变体”函数。
示例¶
int sayHello(uint32_t userId)
{
char buffer[17];
if (userId > 9999) return USER_ID_OUT_OF_BOUNDS;
// BAD: this message overflows the buffer if userId >= 1000,
// as no space for the null terminator was accounted for
sprintf(buffer, "Hello, user %d!", userId);
MessageBox(hWnd, buffer, "New Message", MB_OK);
return SUCCESS;
}
在此示例中,对 sprintf
的调用将写入 14 个字符(包括终止的空字符)加上 `userId` 字符串转换的长度,写入的缓冲区仅有 17 个字符的空间。虽然 `userId` 在转换时被检查为不超过 4 个字符,但如果 `userId >= 1000`,缓冲区中没有终止的空字符的空间。在这种情况下,空字符将溢出缓冲区,导致未定义的行为。
要解决此问题,应进行以下更改:
通过使用编译时常量声明缓冲区来控制缓冲区的大小。
最好使用
snprintf
代替对sprintf
的调用,使用定义的缓冲区常量大小或 `sizeof(buffer)` 作为要写入的最大长度。这将阻止缓冲区溢出。增加缓冲区大小以容纳 `userId` 的完整范围和终止的空字符。