Skip to content

Commit

Permalink
Geneve SerializeTo improvements (#9)
Browse files Browse the repository at this point in the history
* geneve: Fix crash in SerializeTo when lengths are wrong

We run the risk of panicing on buffer overflow if option lengths in the
packet are blindly trusted in serialization.

In line with the precedent set elsewhere (e.g. IPv4, TCP), compute the
necessary buffer size based on the actual options size.

Fill lengths fields from user-provided values, even if those are wrong.

Signed-off-by: Nick Zavaritsky <mejedi@gmail.com>

* geneve: support FixLengths option in SerializeTo

Signed-off-by: Nick Zavaritsky <mejedi@gmail.com>

Signed-off-by: Nick Zavaritsky <mejedi@gmail.com>
  • Loading branch information
mejedi committed Oct 6, 2022
1 parent 43ab360 commit 9e6d99b
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 5 deletions.
22 changes: 18 additions & 4 deletions layers/geneve.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,16 @@ func decodeGeneve(data []byte, p gopacket.PacketBuilder) error {
// SerializationBuffer, implementing gopacket.SerializableLayer.
// See the docs for gopacket.SerializableLayer for more info.
func (gn *Geneve) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.SerializeOptions) error {
plen := int(gn.OptionsLength + 8)
var optionsLength int
for _, o := range gn.Options {
dataLen := len(o.Data) & ^3
optionsLength += 4 + dataLen
}
if opts.FixLengths {
gn.OptionsLength = uint8(optionsLength)
}

plen := int(8 + optionsLength)
bytes, err := b.PrependBytes(plen)
if err != nil {
return err
Expand Down Expand Up @@ -159,8 +168,13 @@ func (gn *Geneve) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.Serializ

// Construct Options

offset, _ := uint8(8), int32(gn.OptionsLength)
offset := 8
for _, o := range gn.Options {
dataLen := len(o.Data) & ^3
if opts.FixLengths {
o.Length = uint8(4 + dataLen)
}

binary.BigEndian.PutUint16(bytes[offset:(offset+2)], uint16(o.Class))

offset += 2
Expand All @@ -171,9 +185,9 @@ func (gn *Geneve) SerializeTo(b gopacket.SerializeBuffer, opts gopacket.Serializ
bytes[offset] |= ((o.Length - 4) >> 2) & 0x1f

offset += 1
copy(bytes[offset:(offset+o.Length-4)], o.Data)
copy(bytes[offset:(offset+dataLen)], o.Data)

offset += o.Length - 4
offset += dataLen
}

return nil
Expand Down
89 changes: 88 additions & 1 deletion layers/geneve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,34 @@ func BenchmarkDecodeGeneve1(b *testing.B) {
}
}

func TestGeneveSerializeToNoCrashWithWrongLengths(t *testing.T) {
gn := &Geneve{
Version: 0x0,
OptionsLength: 0x0,
OAMPacket: false,
CriticalOption: true,
Protocol: EthernetTypeTransparentEthernetBridging,
VNI: 0xa,
Options: []*GeneveOption{
{
Class: 0x0,
Type: 0x80,
Length: 0x0,
Data: []byte{0, 0, 0, 0, 0, 0, 0, 0xc},
},
{
Class: 0x0,
Type: 0x80,
Length: 0x0,
Data: []byte{0, 0, 0, 0xc},
},
},
}

b := gopacket.NewSerializeBuffer()
gn.SerializeTo(b, gopacket.SerializeOptions{})
}

func TestIsomorphicPacketGeneve(t *testing.T) {
gn := &Geneve{
Version: 0x0,
Expand Down Expand Up @@ -188,6 +216,65 @@ func TestIsomorphicPacketGeneve(t *testing.T) {
gnTranslated.BaseLayer = BaseLayer{}

if !reflect.DeepEqual(gn, gnTranslated) {
t.Errorf("VXLAN isomorph mismatch, \nwant %#v\ngot %#v\n", gn, gnTranslated)
t.Errorf("Geneve isomorph mismatch, \nwant %#v\ngot %#v\n", gn, gnTranslated)
}
}

func TestIsomorphicPacketGeneveFixLengths(t *testing.T) {
gn := &Geneve{
Version: 0x0,
OptionsLength: 0x14,
OAMPacket: false,
CriticalOption: true,
Protocol: EthernetTypeTransparentEthernetBridging,
VNI: 0xa,
Options: []*GeneveOption{
{
Class: 0x0,
Type: 0x80,
Length: 12,
Data: []byte{0, 0, 0, 0, 0, 0, 0, 0xc},
},
{
Class: 0x0,
Type: 0x80,
Length: 8,
Data: []byte{0, 0, 0, 0xc},
},
},
}

gnWrongLengths := &Geneve{
Version: 0x0,
OptionsLength: 0x0,
OAMPacket: false,
CriticalOption: true,
Protocol: EthernetTypeTransparentEthernetBridging,
VNI: 0xa,
Options: []*GeneveOption{
{
Class: 0x0,
Type: 0x80,
Length: 0x0,
Data: []byte{0, 0, 0, 0, 0, 0, 0, 0xc},
},
{
Class: 0x0,
Type: 0x80,
Length: 0x0,
Data: []byte{0, 0, 0, 0xc},
},
},
}

b := gopacket.NewSerializeBuffer()
gnWrongLengths.SerializeTo(b, gopacket.SerializeOptions{FixLengths: true})

p := gopacket.NewPacket(b.Bytes(), gopacket.DecodeFunc(decodeGeneve), gopacket.Default)
gnTranslated := p.Layer(LayerTypeGeneve).(*Geneve)
gnTranslated.BaseLayer = BaseLayer{}

if !reflect.DeepEqual(gn, gnTranslated) {
t.Errorf("Geneve isomorph mismatch, \nwant %#v\ngot %#v\n", gn, gnTranslated)
}
}

0 comments on commit 9e6d99b

Please sign in to comment.