CodeQL 文档

分配的大小计算可能会溢出

ID: go/allocation-size-overflow
Kind: path-problem
Security severity: 8.1
Severity: warning
Precision: high
Tags:
   - security
   - external/cwe/cwe-190
Query suites:
   - go-code-scanning.qls
   - go-security-extended.qls
   - go-security-and-quality.qls

点击查看 CodeQL 存储库中的查询

对可能很大的字符串或切片的大小进行计算可能会导致溢出(对于有符号整数类型)或回绕(对于无符号类型)。溢出会导致计算结果变为负数,而回绕则会导致出现很小(正)的数字。

这可能会导致进一步的问题。例如,如果结果随后用于分配,则如果结果为负数,则会导致运行时崩溃,否则会分配意外小的缓冲区。

建议

始终通过执行以下操作之一来防止涉及大数字的算术运算发生溢出

  • 验证计算数字所依据的数据的大小。

  • 在算术表达式上定义一个防护措施,以便仅当结果已知小于或等于该类型的最大值时才执行该操作。

  • 使用更宽的类型(例如 uint64 而不是 int),以便较大的输入值不会导致溢出。

示例

在以下示例中,假设有一个函数 encryptBuffer,用于加密长度必须填充为 16 的倍数的字节切片。函数 encryptValue 提供了此函数的便捷包装器:当传递任意值时,它首先将该值编码为 JSON,填充生成的字节切片,然后将其传递给 encryptBuffer

package main

import "encoding/json"

func encryptValue(v interface{}) ([]byte, error) {
	jsonData, err := json.Marshal(v)
	if err != nil {
		return nil, err
	}
	size := len(jsonData) + (len(jsonData) % 16)
	buffer := make([]byte, size)
	copy(buffer, jsonData)
	return encryptBuffer(buffer)
}

当传递的 JSON 编码长度接近类型 int 的最大值的 value 时,size 的计算将溢出,从而产生负值。当该负值传递给 make 时,将发生运行时崩溃。

为了防止这种情况,应改进该函数以检查 JSON 编码值的长度。例如,以下是 encryptValue 的一个版本,它确保值不超过 64 MB,该值可以轻松地放入 int 中并避免溢出

package main

import (
	"encoding/json"
	"errors"
)

func encryptValueGood(v interface{}) ([]byte, error) {
	jsonData, err := json.Marshal(v)
	if err != nil {
		return nil, err
	}
	if len(jsonData) > 64*1024*1024 {
		return nil, errors.New("value too large")
	}
	size := len(jsonData) + (len(jsonData) % 16)
	buffer := make([]byte, size)
	copy(buffer, jsonData)
	return encryptBuffer(buffer)
}

参考

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