CodeQL 文档

潜在的缓冲区溢出写入

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

单击以查看 CodeQL 代码库中的查询

该程序执行缓冲区复制或写入操作,没有对复制大小的上限限制。通过分析所涉及的表达式的边界,似乎某些输入会导致这种情况下的缓冲区溢出。除了导致程序不稳定之外,还存在一些技术,攻击者可以使用这些技术利用此漏洞执行任意代码。

建议

始终控制缓冲区复制和缓冲区写入操作的长度。应使用 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` 的完整范围和终止的空字符。

参考资料

  • ©GitHub, Inc.
  • 条款
  • 隐私