diff --git a/attribute.go b/attribute.go index 1c81c323..2da437e7 100644 --- a/attribute.go +++ b/attribute.go @@ -12,6 +12,12 @@ import ( // errInvalidAttribute specifies if an Attribute's length is incorrect. var errInvalidAttribute = errors.New("invalid attribute; length too short or too large") +// errInvalidAttribute specifies if an Attribute's data length overflows the length field. +var errAttributeOverflow = errors.New("attribute size overflow; data length can be at most 65531 bytes") + +// errInvalidAttribute specifies if the provided buffer is too short. +var errBufferTooShort = errors.New("buffer too short") + // An Attribute is a netlink attribute. Attributes are packed and unpacked // to and from the Data field of Message for some netlink families. type Attribute struct { @@ -30,15 +36,22 @@ type Attribute struct { // marshal marshals the contents of a into b and returns the number of bytes // written to b, including attribute alignment padding. func (a *Attribute) marshal(b []byte) (int, error) { - if int(a.Length) < nlaHeaderLen { + if len(a.Data) > math.MaxUint16-nlaHeaderLen { + return 0, errAttributeOverflow + } + if int(a.Length) != nlaHeaderLen+len(a.Data) { return 0, errInvalidAttribute } + written := nlaHeaderLen + nlaAlign(len(a.Data)) + if len(b) < written { + return 0, errBufferTooShort + } nlenc.PutUint16(b[0:2], a.Length) nlenc.PutUint16(b[2:4], a.Type) - n := copy(b[nlaHeaderLen:], a.Data) + copy(b[nlaHeaderLen:], a.Data) - return nlaHeaderLen + nlaAlign(n), nil + return written, nil } // unmarshal unmarshals the contents of a byte slice into an Attribute. diff --git a/attribute_test.go b/attribute_test.go index 4a05a5d8..0a42211c 100644 --- a/attribute_test.go +++ b/attribute_test.go @@ -30,6 +30,33 @@ func TestMarshalAttributes(t *testing.T) { }}, err: errInvalidAttribute, }, + { + name: "one attribute, overflow", + attrs: []Attribute{{ + Type: 1, + Data: make([]byte, 0x10000), + }}, + err: errAttributeOverflow, + }, + { + name: "one attribute, smallest overflow", + attrs: []Attribute{{ + Type: 1, + Data: make([]byte, 0x10000-4), + }}, + err: errAttributeOverflow, + }, + { + name: "one attribute, largest possible size", + attrs: []Attribute{{ + Type: 1, + Data: make([]byte, 0x10000-5), + }}, + b: append([]byte{ + 0xff, 0xff, + 0x01, 0x00, + }, make([]byte, 0x10000-4)...), + }, { name: "one attribute, no data", attrs: []Attribute{{