From 4e29164ddb69a54f163a35f3c570ddaf275b9f26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D7=A0=CF=85=CE=B1=CE=B7=20=D7=A0=CF=85=CE=B1=CE=B7=D1=95?= =?UTF-8?q?=CF=83=CE=B7?= Date: Fri, 5 Aug 2022 17:15:38 -0700 Subject: [PATCH 1/3] Add Geneve SerializeTo support Added missing SerializeTo functionality to Geneve. Fixes: #1043 --- layers/geneve.go | 57 +++++++++++++++++++++++++++++++++++++++++++ layers/geneve_test.go | 38 ++++++++++++++++++++++++++++- 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/layers/geneve.go b/layers/geneve.go index e9a142880..f47bc6302 100644 --- a/layers/geneve.go +++ b/layers/geneve.go @@ -9,6 +9,7 @@ package layers import ( "encoding/binary" "errors" + "fmt" "github.com/google/gopacket" ) @@ -119,3 +120,59 @@ func decodeGeneve(data []byte, p gopacket.PacketBuilder) error { gn := &Geneve{} return decodingLayerDecoder(gn, data, p) } + +// SerializeTo writes the serialized form of this layer into the +// 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) + bytes, err := b.PrependBytes(plen) + if err != nil { + return err + } + + // PrependBytes does not guarantee that bytes are zeroed. Setting flags via OR requires that they start off at zero + bytes[0] = 0 + bytes[1] = 0 + + // Construct Geneve + + bytes[0] |= gn.Version << 6 + bytes[0] |= ((gn.OptionsLength >> 2) & 0x3f) + + if gn.OAMPacket { + bytes[1] |= 0x80 + } + + if gn.CriticalOption { + bytes[1] |= 0x40 + } + + binary.BigEndian.PutUint16(bytes[2:4], uint16(gn.Protocol)) + + if gn.VNI >= 1<<24 { + return fmt.Errorf("Virtual Network Identifier = %x exceeds max for 24-bit uint", gn.VNI) + } + binary.BigEndian.PutUint32(bytes[4:8], gn.VNI<<8) + + // Construct Options + + offset, _ := uint8(8), int32(gn.OptionsLength) + for _, o := range gn.Options { + binary.BigEndian.PutUint16(bytes[offset:(offset+2)], uint16(o.Class)) + + offset += 2 + bytes[offset] = o.Type + + offset += 1 + bytes[offset] |= o.Flags << 5 + bytes[offset] |= ((o.Length - 4) >> 2) & 0x1f + + offset += 1 + copy(bytes[offset:(offset+o.Length-4)], o.Data) + + offset += o.Length - 4 + } + + return nil +} diff --git a/layers/geneve_test.go b/layers/geneve_test.go index f1a420bc6..f07d2b1be 100644 --- a/layers/geneve_test.go +++ b/layers/geneve_test.go @@ -136,7 +136,7 @@ func TestDecodeGeneve3(t *testing.T) { Protocol: EthernetTypeTransparentEthernetBridging, VNI: 0xa, Options: []*GeneveOption{ - &GeneveOption{ + { Class: 0x0, Type: 0x80, Length: 8, @@ -155,3 +155,39 @@ func BenchmarkDecodeGeneve1(b *testing.B) { gopacket.NewPacket(testPacketGeneve1, LinkTypeEthernet, gopacket.NoCopy) } } + +func TestIsomorphicPacketGeneve(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}, + }, + }, + } + + b := gopacket.NewSerializeBuffer() + gn.SerializeTo(b, gopacket.SerializeOptions{}) + + 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("VXLAN isomorph mismatch, \nwant %#v\ngot %#v\n", gn, gnTranslated) + } +} From 65a1dfb3db2ad85763f26417f8699486bc253369 Mon Sep 17 00:00:00 2001 From: Chris Golden Date: Sat, 6 Aug 2022 22:35:06 -0700 Subject: [PATCH 2/3] Fix two panics identified by fuzz testing This commit adds additional bounds checking, one for DNSResourceRecord and another for DNSQuestion. The DNSResourceRecord panic was observed in production and the second panic was caught by fuzzing. Add a fuzz test with seeds to reproduce these two panics. --- layers/dns.go | 8 ++++++++ layers/dns_test.go | 7 +++++++ ...ce7b719228870c23869cf21bf8829d7160c82da88f80aeff2d861c | 2 ++ ...21f20980b59f64e1617d6b334b152a90b141a7407c3c8fa4837a31 | 2 ++ ...cf68c2129abd63d4c7cfb1979c489ad9bad6898510a4d4759bb85f | 2 ++ ...2057b406a06ec4f04065f6d0dda6b2b362c0a89192c1933e927adf | 2 ++ 6 files changed, 23 insertions(+) create mode 100644 layers/testdata/fuzz/FuzzDecodeFromBytes/27d23183d8ce7b719228870c23869cf21bf8829d7160c82da88f80aeff2d861c create mode 100644 layers/testdata/fuzz/FuzzDecodeFromBytes/3b53f220d321f20980b59f64e1617d6b334b152a90b141a7407c3c8fa4837a31 create mode 100644 layers/testdata/fuzz/FuzzDecodeFromBytes/f539b7a397cf68c2129abd63d4c7cfb1979c489ad9bad6898510a4d4759bb85f create mode 100644 layers/testdata/fuzz/FuzzDecodeFromBytes/fe20300d6b2057b406a06ec4f04065f6d0dda6b2b362c0a89192c1933e927adf diff --git a/layers/dns.go b/layers/dns.go index b639dec15..21b6de6e5 100644 --- a/layers/dns.go +++ b/layers/dns.go @@ -639,6 +639,10 @@ func (q *DNSQuestion) decode(data []byte, offset int, df gopacket.DecodeFeedback return 0, err } + if len(data) < endq+4 { + return 0, errors.New("DNS question too small") + } + q.Name = name q.Type = DNSType(binary.BigEndian.Uint16(data[endq : endq+2])) q.Class = DNSClass(binary.BigEndian.Uint16(data[endq+2 : endq+4])) @@ -709,6 +713,10 @@ func (rr *DNSResourceRecord) decode(data []byte, offset int, df gopacket.DecodeF return 0, err } + if len(data) < endq+10 { + return 0, errors.New("DNS record too small") + } + rr.Name = name rr.Type = DNSType(binary.BigEndian.Uint16(data[endq : endq+2])) rr.Class = DNSClass(binary.BigEndian.Uint16(data[endq+2 : endq+4])) diff --git a/layers/dns_test.go b/layers/dns_test.go index 8c16766df..5d7cbad32 100644 --- a/layers/dns_test.go +++ b/layers/dns_test.go @@ -15,6 +15,13 @@ import ( "github.com/google/gopacket" ) +func FuzzDecodeFromBytes(f *testing.F) { + f.Fuzz(func(t *testing.T, bytes []byte) { + dns := DNS{} + dns.DecodeFromBytes(bytes, gopacket.NilDecodeFeedback) + }) +} + // it have a layer like that: // name: xxx.com // type: CNAME diff --git a/layers/testdata/fuzz/FuzzDecodeFromBytes/27d23183d8ce7b719228870c23869cf21bf8829d7160c82da88f80aeff2d861c b/layers/testdata/fuzz/FuzzDecodeFromBytes/27d23183d8ce7b719228870c23869cf21bf8829d7160c82da88f80aeff2d861c new file mode 100644 index 000000000..9752921be --- /dev/null +++ b/layers/testdata/fuzz/FuzzDecodeFromBytes/27d23183d8ce7b719228870c23869cf21bf8829d7160c82da88f80aeff2d861c @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000000\x10\x10\x00\x01\x01\x01\x01\x01\x01\x00") diff --git a/layers/testdata/fuzz/FuzzDecodeFromBytes/3b53f220d321f20980b59f64e1617d6b334b152a90b141a7407c3c8fa4837a31 b/layers/testdata/fuzz/FuzzDecodeFromBytes/3b53f220d321f20980b59f64e1617d6b334b152a90b141a7407c3c8fa4837a31 new file mode 100644 index 000000000..80df1f957 --- /dev/null +++ b/layers/testdata/fuzz/FuzzDecodeFromBytes/3b53f220d321f20980b59f64e1617d6b334b152a90b141a7407c3c8fa4837a31 @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("000000000000\x00") diff --git a/layers/testdata/fuzz/FuzzDecodeFromBytes/f539b7a397cf68c2129abd63d4c7cfb1979c489ad9bad6898510a4d4759bb85f b/layers/testdata/fuzz/FuzzDecodeFromBytes/f539b7a397cf68c2129abd63d4c7cfb1979c489ad9bad6898510a4d4759bb85f new file mode 100644 index 000000000..4c717ec9d --- /dev/null +++ b/layers/testdata/fuzz/FuzzDecodeFromBytes/f539b7a397cf68c2129abd63d4c7cfb1979c489ad9bad6898510a4d4759bb85f @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("01000\x10\x10\xdfd\x01\x01\x01\x00d\x01\x01\x01\x00") diff --git a/layers/testdata/fuzz/FuzzDecodeFromBytes/fe20300d6b2057b406a06ec4f04065f6d0dda6b2b362c0a89192c1933e927adf b/layers/testdata/fuzz/FuzzDecodeFromBytes/fe20300d6b2057b406a06ec4f04065f6d0dda6b2b362c0a89192c1933e927adf new file mode 100644 index 000000000..e9da5747d --- /dev/null +++ b/layers/testdata/fuzz/FuzzDecodeFromBytes/fe20300d6b2057b406a06ec4f04065f6d0dda6b2b362c0a89192c1933e927adf @@ -0,0 +1,2 @@ +go test fuzz v1 +[]byte("0000\x00\x00000000\x010\x000") From 32ee38206866f44a74a6033ec26aeeb474506804 Mon Sep 17 00:00:00 2001 From: hallelujah-shih Date: Sat, 6 Aug 2022 09:55:03 +0800 Subject: [PATCH 3/3] add af-packet support ebpf filter --- afpacket/afpacket.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/afpacket/afpacket.go b/afpacket/afpacket.go index bdf888840..6600ae25e 100644 --- a/afpacket/afpacket.go +++ b/afpacket/afpacket.go @@ -4,6 +4,7 @@ // that can be found in the LICENSE file in the root of the source // tree. +//go:build linux // +build linux // Package afpacket provides Go bindings for MMap'd AF_PACKET socket reading. @@ -273,6 +274,11 @@ func (h *TPacket) SetBPF(filter []bpf.RawInstruction) error { return setsockopt(h.fd, unix.SOL_SOCKET, unix.SO_ATTACH_FILTER, unsafe.Pointer(&p), unix.SizeofSockFprog) } +// attach ebpf filter to af-packet +func (h *TPacket) SetEBPF(progFd int32) error { + return setsockopt(h.fd, unix.SOL_SOCKET, unix.SO_ATTACH_BPF, unsafe.Pointer(&progFd), 4) +} + func (h *TPacket) releaseCurrentPacket() error { h.current.clearStatus() h.offset++