Merge pull request #71 from multiformats/fix/panic

fully validate multiaddr byte representations on construction
This commit is contained in:
Steven Allen 2018-06-22 21:55:16 +00:00 committed by GitHub
commit 9680498266
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 76 additions and 62 deletions

View File

@ -1 +1 @@
1.2.7: QmUxSEGbv2nmYNnfXi7839wwQqTN3kwQeUxe8dTjZWZs7J 1.3.0: QmYmsdtJ3HsodkePE3eU3TsCaP2YvPZJ4LoXnNkDE5Tpt7

View File

@ -26,7 +26,7 @@ func stringToBytes(s string) ([]byte, error) {
if p.Code == 0 { if p.Code == 0 {
return nil, fmt.Errorf("no protocol with name %s", sp[0]) return nil, fmt.Errorf("no protocol with name %s", sp[0])
} }
b.Write(CodeToVarint(p.Code)) _, _ = b.Write(CodeToVarint(p.Code))
sp = sp[1:] sp = sp[1:]
if p.Size == 0 { // no length. if p.Size == 0 { // no length.
@ -50,6 +50,9 @@ func stringToBytes(s string) ([]byte, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to parse %s: %s %s", p.Name, sp[0], err) return nil, fmt.Errorf("failed to parse %s: %s %s", p.Name, sp[0], err)
} }
if p.Size < 0 { // varint size.
_, _ = b.Write(CodeToVarint(len(a)))
}
b.Write(a) b.Write(a)
sp = sp[1:] sp = sp[1:]
} }
@ -74,15 +77,22 @@ func validateBytes(b []byte) (err error) {
continue continue
} }
size, err := sizeForAddr(p, b) n, size, err := sizeForAddr(p, b)
if err != nil { if err != nil {
return err return err
} }
b = b[n:]
if len(b) < size || size < 0 { if len(b) < size || size < 0 {
return fmt.Errorf("invalid value for size") return fmt.Errorf("invalid value for size")
} }
err = p.Transcoder.ValidateBytes(b[:size])
if err != nil {
return err
}
b = b[size:] b = b[size:]
} }
@ -109,11 +119,13 @@ func bytesToString(b []byte) (ret string, err error) {
continue continue
} }
size, err := sizeForAddr(p, b) n, size, err := sizeForAddr(p, b)
if err != nil { if err != nil {
return "", err return "", err
} }
b = b[n:]
if len(b) < size || size < 0 { if len(b) < size || size < 0 {
return "", fmt.Errorf("invalid value for size") return "", fmt.Errorf("invalid value for size")
} }
@ -125,6 +137,9 @@ func bytesToString(b []byte) (ret string, err error) {
if err != nil { if err != nil {
return "", err return "", err
} }
if p.Path && len(a) > 0 && a[0] == '/' {
a = a[1:]
}
if len(a) > 0 { if len(a) > 0 {
s += "/" + a s += "/" + a
} }
@ -134,24 +149,24 @@ func bytesToString(b []byte) (ret string, err error) {
return s, nil return s, nil
} }
func sizeForAddr(p Protocol, b []byte) (int, error) { func sizeForAddr(p Protocol, b []byte) (skip, size int, err error) {
switch { switch {
case p.Size > 0: case p.Size > 0:
return (p.Size / 8), nil return 0, (p.Size / 8), nil
case p.Size == 0: case p.Size == 0:
return 0, nil return 0, 0, nil
case p.Path: case p.Path:
size, n, err := ReadVarintCode(b) size, n, err := ReadVarintCode(b)
if err != nil { if err != nil {
return 0, err return 0, 0, err
} }
return size + n, nil return n, size, nil
default: default:
size, n, err := ReadVarintCode(b) size, n, err := ReadVarintCode(b)
if err != nil { if err != nil {
return 0, err return 0, 0, err
} }
return size + n, nil return n, size, nil
} }
} }
@ -168,12 +183,12 @@ func bytesSplit(b []byte) ([][]byte, error) {
return nil, fmt.Errorf("no protocol with code %d", b[0]) return nil, fmt.Errorf("no protocol with code %d", b[0])
} }
size, err := sizeForAddr(p, b[n:]) n2, size, err := sizeForAddr(p, b[n:])
if err != nil { if err != nil {
return nil, err return nil, err
} }
length := n + size length := n + n2 + size
ret = append(ret, b[:length]) ret = append(ret, b[:length])
b = b[length:] b = b[length:]
} }

View File

@ -86,12 +86,12 @@ func (m *multiaddr) Protocols() []Protocol {
ps = append(ps, p) ps = append(ps, p)
b = b[n:] b = b[n:]
size, err := sizeForAddr(p, b) n, size, err := sizeForAddr(p, b)
if err != nil { if err != nil {
panic(err) panic(err)
} }
b = b[size:] b = b[n+size:]
} }
return ps return ps
} }

View File

@ -478,3 +478,17 @@ func TestIPFSvP2P(t *testing.T) {
} }
} }
} }
func TestInvalidP2PAddr(t *testing.T) {
badAddr := "a503221221c05877cbae039d70a5e600ea02c6f9f2942439285c9e344e26f8d280c850fad6"
bts, err := hex.DecodeString(badAddr)
if err != nil {
t.Fatal(err)
}
ma, err := NewMultiaddrBytes(bts)
if err == nil {
t.Error("should have failed")
// Check for panic
_ = ma.String()
}
}

View File

@ -18,6 +18,6 @@
"license": "MIT", "license": "MIT",
"name": "go-multiaddr", "name": "go-multiaddr",
"releaseCmd": "git commit -a -m \"gx publish $VERSION\"", "releaseCmd": "git commit -a -m \"gx publish $VERSION\"",
"version": "1.2.7" "version": "1.3.0"
} }

View File

@ -3,8 +3,8 @@ package multiaddr
import ( import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"strings"
"math/bits" "math/bits"
"strings"
) )
// Protocol is a Multiaddr protocol description structure. // Protocol is a Multiaddr protocol description structure.
@ -170,7 +170,7 @@ func ProtocolsWithString(s string) ([]Protocol, error) {
// CodeToVarint converts an integer to a varint-encoded []byte // CodeToVarint converts an integer to a varint-encoded []byte
func CodeToVarint(num int) []byte { func CodeToVarint(num int) []byte {
buf := make([]byte, bits.Len(uint(num))/7 + 1) buf := make([]byte, bits.Len(uint(num))/7+1)
n := binary.PutUvarint(buf, uint64(num)) n := binary.PutUvarint(buf, uint64(num))
return buf[:n] return buf[:n]
} }

View File

@ -3,7 +3,6 @@ package multiaddr
import ( import (
"encoding/base32" "encoding/base32"
"encoding/binary" "encoding/binary"
"errors"
"fmt" "fmt"
"net" "net"
"strconv" "strconv"
@ -15,17 +14,21 @@ import (
type Transcoder interface { type Transcoder interface {
StringToBytes(string) ([]byte, error) StringToBytes(string) ([]byte, error)
BytesToString([]byte) (string, error) BytesToString([]byte) (string, error)
ValidateBytes([]byte) error
} }
func NewTranscoderFromFunctions(s2b func(string) ([]byte, error), func NewTranscoderFromFunctions(
b2s func([]byte) (string, error)) Transcoder { s2b func(string) ([]byte, error),
b2s func([]byte) (string, error),
return twrp{s2b, b2s} val func([]byte) error,
) Transcoder {
return twrp{s2b, b2s, val}
} }
type twrp struct { type twrp struct {
strtobyte func(string) ([]byte, error) strtobyte func(string) ([]byte, error)
bytetostr func([]byte) (string, error) bytetostr func([]byte) (string, error)
validbyte func([]byte) error
} }
func (t twrp) StringToBytes(s string) ([]byte, error) { func (t twrp) StringToBytes(s string) ([]byte, error) {
@ -35,8 +38,15 @@ func (t twrp) BytesToString(b []byte) (string, error) {
return t.bytetostr(b) return t.bytetostr(b)
} }
var TranscoderIP4 = NewTranscoderFromFunctions(ip4StB, ipBtS) func (t twrp) ValidateBytes(b []byte) error {
var TranscoderIP6 = NewTranscoderFromFunctions(ip6StB, ipBtS) if t.validbyte == nil {
return nil
}
return t.validbyte(b)
}
var TranscoderIP4 = NewTranscoderFromFunctions(ip4StB, ipBtS, nil)
var TranscoderIP6 = NewTranscoderFromFunctions(ip6StB, ipBtS, nil)
func ip4StB(s string) ([]byte, error) { func ip4StB(s string) ([]byte, error) {
i := net.ParseIP(s).To4() i := net.ParseIP(s).To4()
@ -58,7 +68,7 @@ func ipBtS(b []byte) (string, error) {
return net.IP(b).String(), nil return net.IP(b).String(), nil
} }
var TranscoderPort = NewTranscoderFromFunctions(portStB, portBtS) var TranscoderPort = NewTranscoderFromFunctions(portStB, portBtS, nil)
func portStB(s string) ([]byte, error) { func portStB(s string) ([]byte, error) {
i, err := strconv.Atoi(s) i, err := strconv.Atoi(s)
@ -78,7 +88,7 @@ func portBtS(b []byte) (string, error) {
return strconv.Itoa(int(i)), nil return strconv.Itoa(int(i)), nil
} }
var TranscoderOnion = NewTranscoderFromFunctions(onionStB, onionBtS) var TranscoderOnion = NewTranscoderFromFunctions(onionStB, onionBtS, nil)
func onionStB(s string) ([]byte, error) { func onionStB(s string) ([]byte, error) {
addr := strings.Split(s, ":") addr := strings.Split(s, ":")
@ -121,7 +131,7 @@ func onionBtS(b []byte) (string, error) {
return addr + ":" + strconv.Itoa(int(port)), nil return addr + ":" + strconv.Itoa(int(port)), nil
} }
var TranscoderP2P = NewTranscoderFromFunctions(p2pStB, p2pBtS) var TranscoderP2P = NewTranscoderFromFunctions(p2pStB, p2pBtS, p2pVal)
func p2pStB(s string) ([]byte, error) { func p2pStB(s string) ([]byte, error) {
// the address is a varint prefixed multihash string representation // the address is a varint prefixed multihash string representation
@ -129,22 +139,15 @@ func p2pStB(s string) ([]byte, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to parse p2p addr: %s %s", s, err) return nil, fmt.Errorf("failed to parse p2p addr: %s %s", s, err)
} }
size := CodeToVarint(len(m)) return m, nil
b := append(size, m...) }
return b, nil
func p2pVal(b []byte) error {
_, err := mh.Cast(b)
return err
} }
func p2pBtS(b []byte) (string, error) { func p2pBtS(b []byte) (string, error) {
// the address is a varint-prefixed multihash string representation
size, n, err := ReadVarintCode(b)
if err != nil {
return "", err
}
b = b[n:]
if len(b) != size {
return "", errors.New("inconsistent lengths")
}
m, err := mh.Cast(b) m, err := mh.Cast(b)
if err != nil { if err != nil {
return "", err return "", err
@ -152,30 +155,12 @@ func p2pBtS(b []byte) (string, error) {
return m.B58String(), nil return m.B58String(), nil
} }
var TranscoderUnix = NewTranscoderFromFunctions(unixStB, unixBtS) var TranscoderUnix = NewTranscoderFromFunctions(unixStB, unixBtS, nil)
func unixStB(s string) ([]byte, error) { func unixStB(s string) ([]byte, error) {
// the address is the whole remaining string, prefixed by a varint len return []byte(s), nil
size := CodeToVarint(len(s))
b := append(size, []byte(s)...)
return b, nil
} }
func unixBtS(b []byte) (string, error) { func unixBtS(b []byte) (string, error) {
// the address is a varint len prefixed string return string(b), nil
size, n, err := ReadVarintCode(b)
if err != nil {
return "", err
}
b = b[n:]
if len(b) != size {
return "", errors.New("inconsistent lengths")
}
if size == 0 {
return "", errors.New("invalid length")
}
s := string(b)
s = s[1:] // remove starting slash
return s, nil
} }