Go

Go

Made by DeepSource

Size computation for allocation may overflow GO-S1008

Security
Major
cwe-170

Performing marshaling for potentially large objects can result in sizes that may overflow (for signed integer types) or wraparound (for unsigned types). An overflow causes the result of the calculation to become negative, and wraparound results for unsigned types in a smaller (positive) number. Allocation with the computed sizes might cause a runtime panic because of size being negative or allocation of unexpectedly small buffer because of the wraparound. This, it is recommended guarding against such computations.

Recommended ways to guard against overflow in arithmetic operations involving potentially large numbers: - Validate the size of the data from which the numbers are computed. - Define a guard on the expression so that the operation is performed only if the result meets the guard's condition, i.e., computed size should be less than or equal to the maximum value for the result's type. See example. - Use a wider type (such as uint64 instead of int) so larger input values do not cause overflow.

Currently, size computation guard validation support is only there for json.Marshal (encoding/json) and xml.Marshal (encoding/xml).

Bad practice

func encoder(v interface{}) ([]byte, error) {
    data, err := json.Marshal(v)
    if err != nil {
        return nil, err
    }

    // size computation of encoded data
    size := len(data) + (len(data) % 16)

    // NOTE: If `len(size) > ((2^63) or (2^31))`, then `size < 0` and there could be
    // runtime panic because in `int` max positive integer that could be stored is `2^(32-1)` or `2^(64-1)`
    // depending on the platform (32/64 bit). Also, note that `^` here denotes the exponentiation operator.
    buffer := make([]byte, 0, size)
    copy(buffer, data)

    return data, nil
}

When passed a value whose JSON encoding is close to the maximum value of type int in length, size computation will overflow, producing a negative value. A runtime panic will occur when that negative value is passed to make for byte slice allocation.

Recommended

func encoder(v interface{}) ([]byte, error) {
    data, err := json.Marshal(v)
    if err != nil {
        return nil, err
    }

    // NOTE: The choice of 64MB (`64*1024*1024`) is arbitrary; you can choose whatever
    // limit you want, but it should fit inside an `int` type and not overflow.
    if len(data) > 64*1024*1024 {
        return nil, errors.New("too large")
    }

    // size computation of encoded data
    size := len(data) + (len(data) % 16)

    buffer := make([]byte, 0, size)
    copy(buffer, data)

    return data, nil
}

References