Commit a896e565 authored by Mikio Hara's avatar Mikio Hara

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: 's avatarIan Lance Taylor <iant@golang.org>
parent cbbbe2bc
......@@ -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,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
}
......
// 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
}
}
......@@ -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
}
......
......@@ -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
......
......@@ -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])
......
......@@ -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,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:])
......
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment