GODRIVER-3240 Code hardening.#1684
Conversation
API Change ReportNo changes found! |
| i, err := strconv.ParseUint(val.v.(string), 16, 64) | ||
| if err != nil { | ||
| return nil, 0, fmt.Errorf("invalid $binary subType string: %s", val.v.(string)) | ||
| } | ||
|
|
||
| subType = byte(i) | ||
| b := []byte{0, 0, 0, 0, 0, 0, 0, 0} | ||
| binary.LittleEndian.PutUint64(b, i) | ||
| subType = b[0] |
There was a problem hiding this comment.
We can use ParseUint to limit the range of the parsed subtype value by using bitSize=8. I also recommend adding the parse error to returned error.
E.g.
i, err := strconv.ParseUint(val.v.(string), 16, 8)
if err != nil {
return nil, 0, fmt.Errorf("invalid $binary subType string %q: %w", val.v.(string), err)
}
subType = byte(i)4626635 to
27f5ac7
Compare
c34137f to
dfd8a33
Compare
dfd8a33 to
0fb85cf
Compare
| b := []byte{0, 0, 0, 0, 0, 0, 0, 0} | ||
| binary.LittleEndian.PutUint64(b, i) | ||
| subType = b[0] |
There was a problem hiding this comment.
Since we already apply the bounds check in the ParseUint call, it should be safe to assume that i is in the range [0, 255]. In that case, we can keep the existing uint64 -> byte conversion.
| b := []byte{0, 0, 0, 0, 0, 0, 0, 0} | |
| binary.LittleEndian.PutUint64(b, i) | |
| subType = b[0] | |
| subType = byte(i) |
| dataSize := len(keyData) | ||
| certSize := len(certData) | ||
| if math.MaxInt-dataSize < certSize { | ||
| return "", errors.New("size overflow") | ||
| } | ||
| dataSize += certSize | ||
| if math.MaxInt-dataSize < 1 { | ||
| return "", errors.New("size overflow") | ||
| } | ||
| dataSize++ |
There was a problem hiding this comment.
We can simplify the logic here by adding some additional data size validation. AFAIK there's no case where an X.509 key and cert should be anywhere near 64MiB, so we can avoid the integer overflow and check for reasonable data size at the same time.
| dataSize := len(keyData) | |
| certSize := len(certData) | |
| if math.MaxInt-dataSize < certSize { | |
| return "", errors.New("size overflow") | |
| } | |
| dataSize += certSize | |
| if math.MaxInt-dataSize < 1 { | |
| return "", errors.New("size overflow") | |
| } | |
| dataSize++ | |
| keySize := len(keyData) | |
| if keySize > 64*1024*1024 { | |
| return "", errors.New("X.509 key must be less than 64 MiB") | |
| } | |
| certSize := len(certData) | |
| if certSize > 64*1024*1024 { | |
| return "", errors.New("X.509 certificate must be less than 64 MiB") | |
| } | |
| data := make([]byte, 0, keySize+certSize+1) |
| case reflect.Uint: | ||
| if i64 < 0 || int64(uint(i64)) != i64 { // Can we fit this inside of an uint | ||
| if i64 < 0 { | ||
| return emptyValue, fmt.Errorf("%d overflows uint", i64) |
There was a problem hiding this comment.
Use a more accurate error message.
| return emptyValue, fmt.Errorf("%d overflows uint", i64) | |
| return emptyValue, fmt.Errorf("%d underflows uint", i64) |
There was a problem hiding this comment.
It seems better to keep the error message consistent with other unsigned types.
There was a problem hiding this comment.
Sounds reasonable. We can fix them all at the same time. Consider this comment resolved.
| return "", errors.New("X.509 certificate must be less than 64 MiB") | ||
| } | ||
| dataSize := keySize + certSize + 1 | ||
| if dataSize > math.MaxInt { |
There was a problem hiding this comment.
An additional fail-safe check.
|
The |
GODRIVER-3240
Summary
Background & Motivation