分配的大小计算可能会溢出¶
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
对可能很大的字符串或切片的大小进行计算可能会导致溢出(对于有符号整数类型)或回绕(对于无符号类型)。溢出会导致计算结果变为负数,而回绕则会导致出现很小(正)的数字。
这可能会导致进一步的问题。例如,如果结果随后用于分配,则如果结果为负数,则会导致运行时崩溃,否则会分配意外小的缓冲区。
建议¶
始终通过执行以下操作之一来防止涉及大数字的算术运算发生溢出
验证计算数字所依据的数据的大小。
在算术表达式上定义一个防护措施,以便仅当结果已知小于或等于该类型的最大值时才执行该操作。
使用更宽的类型(例如
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)
}
参考¶
Go 编程语言规范:整数溢出。
Go 编程语言规范:创建切片、映射和通道。
常见弱点枚举:CWE-190。