Преглед на файлове

icmp: fix potential misaligned memory access

Also makes use of encoding/binary package.

Change-Id: Ia771290aaccb936fbb7052abaaf96290a9ed4644
Reviewed-on: https://go-review.googlesource.com/19535
Run-TryBot: Mikio Hara <mikioh.mikioh@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Mikio Hara преди 9 години
родител
ревизия
a896e565e9
променени са 9 файла, в които са добавени 69 реда и са изтрити 34 реда
  1. 5 3
      icmp/echo.go
  2. 4 2
      icmp/extension.go
  3. 27 0
      icmp/helper.go
  4. 9 8
      icmp/interface.go
  5. 8 13
      icmp/ipv4.go
  6. 3 2
      icmp/message.go
  7. 3 1
      icmp/mpls.go
  8. 4 2
      icmp/packettoobig.go
  9. 6 3
      icmp/paramprob.go

+ 5 - 3
icmp/echo.go

@@ -4,6 +4,8 @@
 
 package icmp
 
+import "encoding/binary"
+
 // An Echo represents an ICMP echo request or reply message body.
 type Echo struct {
 	ID   int    // identifier
@@ -22,8 +24,8 @@ func (p *Echo) Len(proto int) int {
 // Marshal implements the Marshal method of MessageBody interface.
 func (p *Echo) Marshal(proto int) ([]byte, error) {
 	b := make([]byte, 4+len(p.Data))
-	b[0], b[1] = byte(p.ID>>8), byte(p.ID)
-	b[2], b[3] = byte(p.Seq>>8), byte(p.Seq)
+	binary.BigEndian.PutUint16(b[:2], uint16(p.ID))
+	binary.BigEndian.PutUint16(b[2:4], uint16(p.Seq))
 	copy(b[4:], p.Data)
 	return b, nil
 }
@@ -34,7 +36,7 @@ func parseEcho(proto int, b []byte) (MessageBody, error) {
 	if bodyLen < 4 {
 		return nil, errMessageTooShort
 	}
-	p := &Echo{ID: int(b[0])<<8 | int(b[1]), Seq: int(b[2])<<8 | int(b[3])}
+	p := &Echo{ID: int(binary.BigEndian.Uint16(b[:2])), Seq: int(binary.BigEndian.Uint16(b[2:4]))}
 	if bodyLen > 4 {
 		p.Data = make([]byte, bodyLen-4)
 		copy(p.Data, b[4:])

+ 4 - 2
icmp/extension.go

@@ -4,6 +4,8 @@
 
 package icmp
 
+import "encoding/binary"
+
 // An Extension represents an ICMP extension.
 type Extension interface {
 	// Len returns the length of ICMP extension.
@@ -19,7 +21,7 @@ const extensionVersion = 2
 
 func validExtensionHeader(b []byte) bool {
 	v := int(b[0]&0xf0) >> 4
-	s := uint16(b[2])<<8 | uint16(b[3])
+	s := binary.BigEndian.Uint16(b[2:4])
 	if s != 0 {
 		s = checksum(b)
 	}
@@ -63,7 +65,7 @@ func parseExtensions(b []byte, l int) ([]Extension, int, error) {
 	}
 	var exts []Extension
 	for b = b[l+4:]; len(b) >= 4; {
-		ol := int(b[0])<<8 | int(b[1])
+		ol := int(binary.BigEndian.Uint16(b[:2]))
 		if 4 > ol || ol > len(b) {
 			break
 		}

+ 27 - 0
icmp/helper.go

@@ -0,0 +1,27 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package icmp
+
+import (
+	"encoding/binary"
+	"unsafe"
+)
+
+var (
+	// See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html.
+	freebsdVersion uint32
+
+	nativeEndian binary.ByteOrder
+)
+
+func init() {
+	i := uint32(1)
+	b := (*[4]byte)(unsafe.Pointer(&i))
+	if b[0] == 1 {
+		nativeEndian = binary.LittleEndian
+	} else {
+		nativeEndian = binary.BigEndian
+	}
+}

+ 9 - 8
icmp/interface.go

@@ -5,6 +5,7 @@
 package icmp
 
 import (
+	"encoding/binary"
 	"net"
 	"strings"
 
@@ -89,7 +90,7 @@ func (ifi *InterfaceInfo) Marshal(proto int) ([]byte, error) {
 }
 
 func (ifi *InterfaceInfo) marshal(proto int, b []byte, attrs, l int) error {
-	b[0], b[1] = byte(l>>8), byte(l)
+	binary.BigEndian.PutUint16(b[:2], uint16(l))
 	b[2], b[3] = classInterfaceInfo, byte(ifi.Type)
 	for b = b[4:]; len(b) > 0 && attrs != 0; {
 		switch {
@@ -111,7 +112,7 @@ func (ifi *InterfaceInfo) marshal(proto int, b []byte, attrs, l int) error {
 }
 
 func (ifi *InterfaceInfo) marshalIfIndex(proto int, b []byte) []byte {
-	b[0], b[1], b[2], b[3] = byte(ifi.Interface.Index>>24), byte(ifi.Interface.Index>>16), byte(ifi.Interface.Index>>8), byte(ifi.Interface.Index)
+	binary.BigEndian.PutUint32(b[:4], uint32(ifi.Interface.Index))
 	return b[4:]
 }
 
@@ -119,18 +120,18 @@ func (ifi *InterfaceInfo) parseIfIndex(b []byte) ([]byte, error) {
 	if len(b) < 4 {
 		return nil, errMessageTooShort
 	}
-	ifi.Interface.Index = int(b[0])<<24 | int(b[1])<<16 | int(b[2])<<8 | int(b[3])
+	ifi.Interface.Index = int(binary.BigEndian.Uint32(b[:4]))
 	return b[4:], nil
 }
 
 func (ifi *InterfaceInfo) marshalIPAddr(proto int, b []byte) []byte {
 	switch proto {
 	case iana.ProtocolICMP:
-		b[0], b[1] = byte(afiIPv4>>8), byte(afiIPv4)
+		binary.BigEndian.PutUint16(b[:2], uint16(afiIPv4))
 		copy(b[4:4+net.IPv4len], ifi.Addr.IP.To4())
 		b = b[4+net.IPv4len:]
 	case iana.ProtocolIPv6ICMP:
-		b[0], b[1] = byte(afiIPv6>>8), byte(afiIPv6)
+		binary.BigEndian.PutUint16(b[:2], uint16(afiIPv6))
 		copy(b[4:4+net.IPv6len], ifi.Addr.IP.To16())
 		b = b[4+net.IPv6len:]
 	}
@@ -141,7 +142,7 @@ func (ifi *InterfaceInfo) parseIPAddr(b []byte) ([]byte, error) {
 	if len(b) < 4 {
 		return nil, errMessageTooShort
 	}
-	afi := int(b[0])<<8 | int(b[1])
+	afi := int(binary.BigEndian.Uint16(b[:2]))
 	b = b[4:]
 	switch afi {
 	case afiIPv4:
@@ -184,7 +185,7 @@ func (ifi *InterfaceInfo) parseName(b []byte) ([]byte, error) {
 }
 
 func (ifi *InterfaceInfo) marshalMTU(proto int, b []byte) []byte {
-	b[0], b[1], b[2], b[3] = byte(ifi.Interface.MTU>>24), byte(ifi.Interface.MTU>>16), byte(ifi.Interface.MTU>>8), byte(ifi.Interface.MTU)
+	binary.BigEndian.PutUint32(b[:4], uint32(ifi.Interface.MTU))
 	return b[4:]
 }
 
@@ -192,7 +193,7 @@ func (ifi *InterfaceInfo) parseMTU(b []byte) ([]byte, error) {
 	if len(b) < 4 {
 		return nil, errMessageTooShort
 	}
-	ifi.Interface.MTU = int(b[0])<<24 | int(b[1])<<16 | int(b[2])<<8 | int(b[3])
+	ifi.Interface.MTU = int(binary.BigEndian.Uint32(b[:4]))
 	return b[4:], nil
 }
 

+ 8 - 13
icmp/ipv4.go

@@ -5,16 +5,13 @@
 package icmp
 
 import (
+	"encoding/binary"
 	"net"
 	"runtime"
-	"unsafe"
 
 	"golang.org/x/net/ipv4"
 )
 
-// See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html.
-var freebsdVersion uint32
-
 // ParseIPv4Header parses b as an IPv4 header of ICMP error message
 // invoking packet, which is contained in ICMP error message.
 func ParseIPv4Header(b []byte) (*ipv4.Header, error) {
@@ -29,27 +26,25 @@ func ParseIPv4Header(b []byte) (*ipv4.Header, error) {
 		Version:  int(b[0] >> 4),
 		Len:      hdrlen,
 		TOS:      int(b[1]),
-		ID:       int(b[4])<<8 | int(b[5]),
-		FragOff:  int(b[6])<<8 | int(b[7]),
+		ID:       int(binary.BigEndian.Uint16(b[4:6])),
+		FragOff:  int(binary.BigEndian.Uint16(b[6:8])),
 		TTL:      int(b[8]),
 		Protocol: int(b[9]),
-		Checksum: int(b[10])<<8 | int(b[11]),
+		Checksum: int(binary.BigEndian.Uint16(b[10:12])),
 		Src:      net.IPv4(b[12], b[13], b[14], b[15]),
 		Dst:      net.IPv4(b[16], b[17], b[18], b[19]),
 	}
 	switch runtime.GOOS {
 	case "darwin":
-		// TODO(mikio): fix potential misaligned memory access
-		h.TotalLen = int(*(*uint16)(unsafe.Pointer(&b[2:3][0])))
+		h.TotalLen = int(nativeEndian.Uint16(b[2:4]))
 	case "freebsd":
 		if freebsdVersion >= 1000000 {
-			h.TotalLen = int(b[2])<<8 | int(b[3])
+			h.TotalLen = int(binary.BigEndian.Uint16(b[2:4]))
 		} else {
-			// TODO(mikio): fix potential misaligned memory access
-			h.TotalLen = int(*(*uint16)(unsafe.Pointer(&b[2:3][0])))
+			h.TotalLen = int(nativeEndian.Uint16(b[2:4]))
 		}
 	default:
-		h.TotalLen = int(b[2])<<8 | int(b[3])
+		h.TotalLen = int(binary.BigEndian.Uint16(b[2:4]))
 	}
 	h.Flags = ipv4.HeaderFlags(h.FragOff&0xe000) >> 13
 	h.FragOff = h.FragOff & 0x1fff

+ 3 - 2
icmp/message.go

@@ -14,6 +14,7 @@
 package icmp // import "golang.org/x/net/icmp"
 
 import (
+	"encoding/binary"
 	"errors"
 	"net"
 	"syscall"
@@ -94,7 +95,7 @@ func (m *Message) Marshal(psh []byte) ([]byte, error) {
 			return b, nil
 		}
 		off, l := 2*net.IPv6len, len(b)-len(psh)
-		b[off], b[off+1], b[off+2], b[off+3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
+		binary.BigEndian.PutUint32(b[off:off+4], uint32(l))
 	}
 	s := checksum(b)
 	// Place checksum back in header; using ^= avoids the
@@ -128,7 +129,7 @@ func ParseMessage(proto int, b []byte) (*Message, error) {
 		return nil, errMessageTooShort
 	}
 	var err error
-	m := &Message{Code: int(b[1]), Checksum: int(b[2])<<8 | int(b[3])}
+	m := &Message{Code: int(b[1]), Checksum: int(binary.BigEndian.Uint16(b[2:4]))}
 	switch proto {
 	case iana.ProtocolICMP:
 		m.Type = ipv4.ICMPType(b[0])

+ 3 - 1
icmp/mpls.go

@@ -4,6 +4,8 @@
 
 package icmp
 
+import "encoding/binary"
+
 // A MPLSLabel represents a MPLS label stack entry.
 type MPLSLabel struct {
 	Label int  // label value
@@ -40,7 +42,7 @@ func (ls *MPLSLabelStack) Marshal(proto int) ([]byte, error) {
 
 func (ls *MPLSLabelStack) marshal(proto int, b []byte) error {
 	l := ls.Len(proto)
-	b[0], b[1] = byte(l>>8), byte(l)
+	binary.BigEndian.PutUint16(b[:2], uint16(l))
 	b[2], b[3] = classMPLSLabelStack, typeIncomingMPLSLabelStack
 	off := 4
 	for _, ll := range ls.Labels {

+ 4 - 2
icmp/packettoobig.go

@@ -4,6 +4,8 @@
 
 package icmp
 
+import "encoding/binary"
+
 // A PacketTooBig represents an ICMP packet too big message body.
 type PacketTooBig struct {
 	MTU  int    // maximum transmission unit of the nexthop link
@@ -21,7 +23,7 @@ func (p *PacketTooBig) Len(proto int) int {
 // Marshal implements the Marshal method of MessageBody interface.
 func (p *PacketTooBig) Marshal(proto int) ([]byte, error) {
 	b := make([]byte, 4+len(p.Data))
-	b[0], b[1], b[2], b[3] = byte(p.MTU>>24), byte(p.MTU>>16), byte(p.MTU>>8), byte(p.MTU)
+	binary.BigEndian.PutUint32(b[:4], uint32(p.MTU))
 	copy(b[4:], p.Data)
 	return b, nil
 }
@@ -32,7 +34,7 @@ func parsePacketTooBig(proto int, b []byte) (MessageBody, error) {
 	if bodyLen < 4 {
 		return nil, errMessageTooShort
 	}
-	p := &PacketTooBig{MTU: int(b[0])<<24 | int(b[1])<<16 | int(b[2])<<8 | int(b[3])}
+	p := &PacketTooBig{MTU: int(binary.BigEndian.Uint32(b[:4]))}
 	if bodyLen > 4 {
 		p.Data = make([]byte, bodyLen-4)
 		copy(p.Data, b[4:])

+ 6 - 3
icmp/paramprob.go

@@ -4,7 +4,10 @@
 
 package icmp
 
-import "golang.org/x/net/internal/iana"
+import (
+	"encoding/binary"
+	"golang.org/x/net/internal/iana"
+)
 
 // A ParamProb represents an ICMP parameter problem message body.
 type ParamProb struct {
@@ -26,7 +29,7 @@ func (p *ParamProb) Len(proto int) int {
 func (p *ParamProb) Marshal(proto int) ([]byte, error) {
 	if proto == iana.ProtocolIPv6ICMP {
 		b := make([]byte, p.Len(proto))
-		b[0], b[1], b[2], b[3] = byte(p.Pointer>>24), byte(p.Pointer>>16), byte(p.Pointer>>8), byte(p.Pointer)
+		binary.BigEndian.PutUint32(b[:4], uint32(p.Pointer))
 		copy(b[4:], p.Data)
 		return b, nil
 	}
@@ -45,7 +48,7 @@ func parseParamProb(proto int, b []byte) (MessageBody, error) {
 	}
 	p := &ParamProb{}
 	if proto == iana.ProtocolIPv6ICMP {
-		p.Pointer = uintptr(b[0])<<24 | uintptr(b[1])<<16 | uintptr(b[2])<<8 | uintptr(b[3])
+		p.Pointer = uintptr(binary.BigEndian.Uint32(b[:4]))
 		p.Data = make([]byte, len(b)-4)
 		copy(p.Data, b[4:])
 		return p, nil