mirror of
https://git.mirrors.martin98.com/https://github.com/ceph/ceph-csi.git
synced 2025-08-15 16:45:58 +08:00

Several packages are only used while running the e2e suite. These packages are less important to update, as the they can not influence the final executable that is part of the Ceph-CSI container-image. By moving these dependencies out of the main Ceph-CSI go.mod, it is easier to identify if a reported CVE affects Ceph-CSI, or only the testing (like most of the Kubernetes CVEs). Signed-off-by: Niels de Vos <ndevos@ibm.com>
395 lines
11 KiB
Go
395 lines
11 KiB
Go
// Copyright (c) Faye Amacker. All rights reserved.
|
|
// Licensed under the MIT License. See LICENSE in the project root for license information.
|
|
|
|
package cbor
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"errors"
|
|
"io"
|
|
"math"
|
|
"strconv"
|
|
|
|
"github.com/x448/float16"
|
|
)
|
|
|
|
// SyntaxError is a description of a CBOR syntax error.
|
|
type SyntaxError struct {
|
|
msg string
|
|
}
|
|
|
|
func (e *SyntaxError) Error() string { return e.msg }
|
|
|
|
// SemanticError is a description of a CBOR semantic error.
|
|
type SemanticError struct {
|
|
msg string
|
|
}
|
|
|
|
func (e *SemanticError) Error() string { return e.msg }
|
|
|
|
// MaxNestedLevelError indicates exceeded max nested level of any combination of CBOR arrays/maps/tags.
|
|
type MaxNestedLevelError struct {
|
|
maxNestedLevels int
|
|
}
|
|
|
|
func (e *MaxNestedLevelError) Error() string {
|
|
return "cbor: exceeded max nested level " + strconv.Itoa(e.maxNestedLevels)
|
|
}
|
|
|
|
// MaxArrayElementsError indicates exceeded max number of elements for CBOR arrays.
|
|
type MaxArrayElementsError struct {
|
|
maxArrayElements int
|
|
}
|
|
|
|
func (e *MaxArrayElementsError) Error() string {
|
|
return "cbor: exceeded max number of elements " + strconv.Itoa(e.maxArrayElements) + " for CBOR array"
|
|
}
|
|
|
|
// MaxMapPairsError indicates exceeded max number of key-value pairs for CBOR maps.
|
|
type MaxMapPairsError struct {
|
|
maxMapPairs int
|
|
}
|
|
|
|
func (e *MaxMapPairsError) Error() string {
|
|
return "cbor: exceeded max number of key-value pairs " + strconv.Itoa(e.maxMapPairs) + " for CBOR map"
|
|
}
|
|
|
|
// IndefiniteLengthError indicates found disallowed indefinite length items.
|
|
type IndefiniteLengthError struct {
|
|
t cborType
|
|
}
|
|
|
|
func (e *IndefiniteLengthError) Error() string {
|
|
return "cbor: indefinite-length " + e.t.String() + " isn't allowed"
|
|
}
|
|
|
|
// TagsMdError indicates found disallowed CBOR tags.
|
|
type TagsMdError struct {
|
|
}
|
|
|
|
func (e *TagsMdError) Error() string {
|
|
return "cbor: CBOR tag isn't allowed"
|
|
}
|
|
|
|
// ExtraneousDataError indicates found extraneous data following well-formed CBOR data item.
|
|
type ExtraneousDataError struct {
|
|
numOfBytes int // number of bytes of extraneous data
|
|
index int // location of extraneous data
|
|
}
|
|
|
|
func (e *ExtraneousDataError) Error() string {
|
|
return "cbor: " + strconv.Itoa(e.numOfBytes) + " bytes of extraneous data starting at index " + strconv.Itoa(e.index)
|
|
}
|
|
|
|
// wellformed checks whether the CBOR data item is well-formed.
|
|
// allowExtraData indicates if extraneous data is allowed after the CBOR data item.
|
|
// - use allowExtraData = true when using Decoder.Decode()
|
|
// - use allowExtraData = false when using Unmarshal()
|
|
func (d *decoder) wellformed(allowExtraData bool, checkBuiltinTags bool) error {
|
|
if len(d.data) == d.off {
|
|
return io.EOF
|
|
}
|
|
_, err := d.wellformedInternal(0, checkBuiltinTags)
|
|
if err == nil {
|
|
if !allowExtraData && d.off != len(d.data) {
|
|
err = &ExtraneousDataError{len(d.data) - d.off, d.off}
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
|
|
// wellformedInternal checks data's well-formedness and returns max depth and error.
|
|
func (d *decoder) wellformedInternal(depth int, checkBuiltinTags bool) (int, error) { //nolint:gocyclo
|
|
t, _, val, indefiniteLength, err := d.wellformedHeadWithIndefiniteLengthFlag()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
switch t {
|
|
case cborTypeByteString, cborTypeTextString:
|
|
if indefiniteLength {
|
|
if d.dm.indefLength == IndefLengthForbidden {
|
|
return 0, &IndefiniteLengthError{t}
|
|
}
|
|
return d.wellformedIndefiniteString(t, depth, checkBuiltinTags)
|
|
}
|
|
valInt := int(val)
|
|
if valInt < 0 {
|
|
// Detect integer overflow
|
|
return 0, errors.New("cbor: " + t.String() + " length " + strconv.FormatUint(val, 10) + " is too large, causing integer overflow")
|
|
}
|
|
if len(d.data)-d.off < valInt { // valInt+off may overflow integer
|
|
return 0, io.ErrUnexpectedEOF
|
|
}
|
|
d.off += valInt
|
|
|
|
case cborTypeArray, cborTypeMap:
|
|
depth++
|
|
if depth > d.dm.maxNestedLevels {
|
|
return 0, &MaxNestedLevelError{d.dm.maxNestedLevels}
|
|
}
|
|
|
|
if indefiniteLength {
|
|
if d.dm.indefLength == IndefLengthForbidden {
|
|
return 0, &IndefiniteLengthError{t}
|
|
}
|
|
return d.wellformedIndefiniteArrayOrMap(t, depth, checkBuiltinTags)
|
|
}
|
|
|
|
valInt := int(val)
|
|
if valInt < 0 {
|
|
// Detect integer overflow
|
|
return 0, errors.New("cbor: " + t.String() + " length " + strconv.FormatUint(val, 10) + " is too large, it would cause integer overflow")
|
|
}
|
|
|
|
if t == cborTypeArray {
|
|
if valInt > d.dm.maxArrayElements {
|
|
return 0, &MaxArrayElementsError{d.dm.maxArrayElements}
|
|
}
|
|
} else {
|
|
if valInt > d.dm.maxMapPairs {
|
|
return 0, &MaxMapPairsError{d.dm.maxMapPairs}
|
|
}
|
|
}
|
|
|
|
count := 1
|
|
if t == cborTypeMap {
|
|
count = 2
|
|
}
|
|
maxDepth := depth
|
|
for j := 0; j < count; j++ {
|
|
for i := 0; i < valInt; i++ {
|
|
var dpt int
|
|
if dpt, err = d.wellformedInternal(depth, checkBuiltinTags); err != nil {
|
|
return 0, err
|
|
}
|
|
if dpt > maxDepth {
|
|
maxDepth = dpt // Save max depth
|
|
}
|
|
}
|
|
}
|
|
depth = maxDepth
|
|
|
|
case cborTypeTag:
|
|
if d.dm.tagsMd == TagsForbidden {
|
|
return 0, &TagsMdError{}
|
|
}
|
|
|
|
tagNum := val
|
|
|
|
// Scan nested tag numbers to avoid recursion.
|
|
for {
|
|
if len(d.data) == d.off { // Tag number must be followed by tag content.
|
|
return 0, io.ErrUnexpectedEOF
|
|
}
|
|
if checkBuiltinTags {
|
|
err = validBuiltinTag(tagNum, d.data[d.off])
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
}
|
|
if d.dm.bignumTag == BignumTagForbidden && (tagNum == 2 || tagNum == 3) {
|
|
return 0, &UnacceptableDataItemError{
|
|
CBORType: cborTypeTag.String(),
|
|
Message: "bignum",
|
|
}
|
|
}
|
|
if getType(d.data[d.off]) != cborTypeTag {
|
|
break
|
|
}
|
|
if _, _, tagNum, err = d.wellformedHead(); err != nil {
|
|
return 0, err
|
|
}
|
|
depth++
|
|
if depth > d.dm.maxNestedLevels {
|
|
return 0, &MaxNestedLevelError{d.dm.maxNestedLevels}
|
|
}
|
|
}
|
|
// Check tag content.
|
|
return d.wellformedInternal(depth, checkBuiltinTags)
|
|
}
|
|
|
|
return depth, nil
|
|
}
|
|
|
|
// wellformedIndefiniteString checks indefinite length byte/text string's well-formedness and returns max depth and error.
|
|
func (d *decoder) wellformedIndefiniteString(t cborType, depth int, checkBuiltinTags bool) (int, error) {
|
|
var err error
|
|
for {
|
|
if len(d.data) == d.off {
|
|
return 0, io.ErrUnexpectedEOF
|
|
}
|
|
if isBreakFlag(d.data[d.off]) {
|
|
d.off++
|
|
break
|
|
}
|
|
// Peek ahead to get next type and indefinite length status.
|
|
nt, ai := parseInitialByte(d.data[d.off])
|
|
if t != nt {
|
|
return 0, &SyntaxError{"cbor: wrong element type " + nt.String() + " for indefinite-length " + t.String()}
|
|
}
|
|
if additionalInformation(ai).isIndefiniteLength() {
|
|
return 0, &SyntaxError{"cbor: indefinite-length " + t.String() + " chunk is not definite-length"}
|
|
}
|
|
if depth, err = d.wellformedInternal(depth, checkBuiltinTags); err != nil {
|
|
return 0, err
|
|
}
|
|
}
|
|
return depth, nil
|
|
}
|
|
|
|
// wellformedIndefiniteArrayOrMap checks indefinite length array/map's well-formedness and returns max depth and error.
|
|
func (d *decoder) wellformedIndefiniteArrayOrMap(t cborType, depth int, checkBuiltinTags bool) (int, error) {
|
|
var err error
|
|
maxDepth := depth
|
|
i := 0
|
|
for {
|
|
if len(d.data) == d.off {
|
|
return 0, io.ErrUnexpectedEOF
|
|
}
|
|
if isBreakFlag(d.data[d.off]) {
|
|
d.off++
|
|
break
|
|
}
|
|
var dpt int
|
|
if dpt, err = d.wellformedInternal(depth, checkBuiltinTags); err != nil {
|
|
return 0, err
|
|
}
|
|
if dpt > maxDepth {
|
|
maxDepth = dpt
|
|
}
|
|
i++
|
|
if t == cborTypeArray {
|
|
if i > d.dm.maxArrayElements {
|
|
return 0, &MaxArrayElementsError{d.dm.maxArrayElements}
|
|
}
|
|
} else {
|
|
if i%2 == 0 && i/2 > d.dm.maxMapPairs {
|
|
return 0, &MaxMapPairsError{d.dm.maxMapPairs}
|
|
}
|
|
}
|
|
}
|
|
if t == cborTypeMap && i%2 == 1 {
|
|
return 0, &SyntaxError{"cbor: unexpected \"break\" code"}
|
|
}
|
|
return maxDepth, nil
|
|
}
|
|
|
|
func (d *decoder) wellformedHeadWithIndefiniteLengthFlag() (
|
|
t cborType,
|
|
ai byte,
|
|
val uint64,
|
|
indefiniteLength bool,
|
|
err error,
|
|
) {
|
|
t, ai, val, err = d.wellformedHead()
|
|
if err != nil {
|
|
return
|
|
}
|
|
indefiniteLength = additionalInformation(ai).isIndefiniteLength()
|
|
return
|
|
}
|
|
|
|
func (d *decoder) wellformedHead() (t cborType, ai byte, val uint64, err error) {
|
|
dataLen := len(d.data) - d.off
|
|
if dataLen == 0 {
|
|
return 0, 0, 0, io.ErrUnexpectedEOF
|
|
}
|
|
|
|
t, ai = parseInitialByte(d.data[d.off])
|
|
val = uint64(ai)
|
|
d.off++
|
|
dataLen--
|
|
|
|
if ai <= maxAdditionalInformationWithoutArgument {
|
|
return t, ai, val, nil
|
|
}
|
|
|
|
if ai == additionalInformationWith1ByteArgument {
|
|
const argumentSize = 1
|
|
if dataLen < argumentSize {
|
|
return 0, 0, 0, io.ErrUnexpectedEOF
|
|
}
|
|
val = uint64(d.data[d.off])
|
|
d.off++
|
|
if t == cborTypePrimitives && val < 32 {
|
|
return 0, 0, 0, &SyntaxError{"cbor: invalid simple value " + strconv.Itoa(int(val)) + " for type " + t.String()}
|
|
}
|
|
return t, ai, val, nil
|
|
}
|
|
|
|
if ai == additionalInformationWith2ByteArgument {
|
|
const argumentSize = 2
|
|
if dataLen < argumentSize {
|
|
return 0, 0, 0, io.ErrUnexpectedEOF
|
|
}
|
|
val = uint64(binary.BigEndian.Uint16(d.data[d.off : d.off+argumentSize]))
|
|
d.off += argumentSize
|
|
if t == cborTypePrimitives {
|
|
if err := d.acceptableFloat(float64(float16.Frombits(uint16(val)).Float32())); err != nil {
|
|
return 0, 0, 0, err
|
|
}
|
|
}
|
|
return t, ai, val, nil
|
|
}
|
|
|
|
if ai == additionalInformationWith4ByteArgument {
|
|
const argumentSize = 4
|
|
if dataLen < argumentSize {
|
|
return 0, 0, 0, io.ErrUnexpectedEOF
|
|
}
|
|
val = uint64(binary.BigEndian.Uint32(d.data[d.off : d.off+argumentSize]))
|
|
d.off += argumentSize
|
|
if t == cborTypePrimitives {
|
|
if err := d.acceptableFloat(float64(math.Float32frombits(uint32(val)))); err != nil {
|
|
return 0, 0, 0, err
|
|
}
|
|
}
|
|
return t, ai, val, nil
|
|
}
|
|
|
|
if ai == additionalInformationWith8ByteArgument {
|
|
const argumentSize = 8
|
|
if dataLen < argumentSize {
|
|
return 0, 0, 0, io.ErrUnexpectedEOF
|
|
}
|
|
val = binary.BigEndian.Uint64(d.data[d.off : d.off+argumentSize])
|
|
d.off += argumentSize
|
|
if t == cborTypePrimitives {
|
|
if err := d.acceptableFloat(math.Float64frombits(val)); err != nil {
|
|
return 0, 0, 0, err
|
|
}
|
|
}
|
|
return t, ai, val, nil
|
|
}
|
|
|
|
if additionalInformation(ai).isIndefiniteLength() {
|
|
switch t {
|
|
case cborTypePositiveInt, cborTypeNegativeInt, cborTypeTag:
|
|
return 0, 0, 0, &SyntaxError{"cbor: invalid additional information " + strconv.Itoa(int(ai)) + " for type " + t.String()}
|
|
case cborTypePrimitives: // 0xff (break code) should not be outside wellformedIndefinite().
|
|
return 0, 0, 0, &SyntaxError{"cbor: unexpected \"break\" code"}
|
|
}
|
|
return t, ai, val, nil
|
|
}
|
|
|
|
// ai == 28, 29, 30
|
|
return 0, 0, 0, &SyntaxError{"cbor: invalid additional information " + strconv.Itoa(int(ai)) + " for type " + t.String()}
|
|
}
|
|
|
|
func (d *decoder) acceptableFloat(f float64) error {
|
|
switch {
|
|
case d.dm.nanDec == NaNDecodeForbidden && math.IsNaN(f):
|
|
return &UnacceptableDataItemError{
|
|
CBORType: cborTypePrimitives.String(),
|
|
Message: "floating-point NaN",
|
|
}
|
|
case d.dm.infDec == InfDecodeForbidden && math.IsInf(f, 0):
|
|
return &UnacceptableDataItemError{
|
|
CBORType: cborTypePrimitives.String(),
|
|
Message: "floating-point infinity",
|
|
}
|
|
}
|
|
return nil
|
|
}
|