accounts/abi: harden unpacking against malicious input
This commit is contained in:
parent
08c5d4dd27
commit
bd6ed23899
|
@ -95,6 +95,9 @@ func readFixedBytes(t Type, word []byte) (interface{}, error) {
|
||||||
|
|
||||||
// iteratively unpack elements
|
// iteratively unpack elements
|
||||||
func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) {
|
func forEachUnpack(t Type, output []byte, start, size int) (interface{}, error) {
|
||||||
|
if size < 0 {
|
||||||
|
return nil, fmt.Errorf("cannot marshal input to array, size is negative (%d)", size)
|
||||||
|
}
|
||||||
if start+32*size > len(output) {
|
if start+32*size > len(output) {
|
||||||
return nil, fmt.Errorf("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)", len(output), start+32*size)
|
return nil, fmt.Errorf("abi: cannot marshal in to go array: offset %d would go over slice boundary (len=%d)", len(output), start+32*size)
|
||||||
}
|
}
|
||||||
|
@ -181,16 +184,22 @@ func toGoType(index int, t Type, output []byte) (interface{}, error) {
|
||||||
|
|
||||||
// interprets a 32 byte slice as an offset and then determines which indice to look to decode the type.
|
// interprets a 32 byte slice as an offset and then determines which indice to look to decode the type.
|
||||||
func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err error) {
|
func lengthPrefixPointsTo(index int, output []byte) (start int, length int, err error) {
|
||||||
offset := int(binary.BigEndian.Uint64(output[index+24 : index+32]))
|
offsetBig := big.NewInt(0).SetBytes(output[index : index+32])
|
||||||
|
if !offsetBig.IsInt64() {
|
||||||
|
return 0, 0, fmt.Errorf("abi offset larger than int64: %v", offsetBig)
|
||||||
|
}
|
||||||
|
offset := int(offsetBig.Int64())
|
||||||
if offset+32 > len(output) {
|
if offset+32 > len(output) {
|
||||||
return 0, 0, fmt.Errorf("abi: cannot marshal in to go slice: offset %d would go over slice boundary (len=%d)", len(output), offset+32)
|
return 0, 0, fmt.Errorf("abi: cannot marshal in to go slice: offset %d would go over slice boundary (len=%d)", len(output), offset+32)
|
||||||
}
|
}
|
||||||
length = int(binary.BigEndian.Uint64(output[offset+24 : offset+32]))
|
lengthBig := big.NewInt(0).SetBytes(output[offset : offset+32])
|
||||||
|
if !lengthBig.IsInt64() {
|
||||||
|
return 0, 0, fmt.Errorf("abi length larger than int64: %v", lengthBig)
|
||||||
|
}
|
||||||
|
length = int(lengthBig.Int64())
|
||||||
if offset+32+length > len(output) {
|
if offset+32+length > len(output) {
|
||||||
return 0, 0, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32+length)
|
return 0, 0, fmt.Errorf("abi: cannot marshal in to go type: length insufficient %d require %d", len(output), offset+32+length)
|
||||||
}
|
}
|
||||||
start = offset + 32
|
start = offset + 32
|
||||||
|
|
||||||
//fmt.Printf("LENGTH PREFIX INFO: \nsize: %v\noffset: %v\nstart: %v\n", length, offset, start)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -683,3 +683,73 @@ func TestUnmarshal(t *testing.T) {
|
||||||
t.Fatal("expected error:", err)
|
t.Fatal("expected error:", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOOMMaliciousInput(t *testing.T) {
|
||||||
|
oomTests := []unpackTest{
|
||||||
|
{
|
||||||
|
def: `[{"type": "uint8[]"}]`,
|
||||||
|
enc: "0000000000000000000000000000000000000000000000000000000000000020" + // offset
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000003" + // num elems
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
|
||||||
|
},
|
||||||
|
{ // Length larger than 64 bits
|
||||||
|
def: `[{"type": "uint8[]"}]`,
|
||||||
|
enc: "0000000000000000000000000000000000000000000000000000000000000020" + // offset
|
||||||
|
"00ffffffffffffffffffffffffffffffffffffffffffffff0000000000000002" + // num elems
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
|
||||||
|
},
|
||||||
|
{ // Offset very large (over 64 bits)
|
||||||
|
def: `[{"type": "uint8[]"}]`,
|
||||||
|
enc: "00ffffffffffffffffffffffffffffffffffffffffffffff0000000000000020" + // offset
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000002" + // num elems
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
|
||||||
|
},
|
||||||
|
{ // Offset very large (below 64 bits)
|
||||||
|
def: `[{"type": "uint8[]"}]`,
|
||||||
|
enc: "0000000000000000000000000000000000000000000000007ffffffffff00020" + // offset
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000002" + // num elems
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
|
||||||
|
},
|
||||||
|
{ // Offset negative (as 64 bit)
|
||||||
|
def: `[{"type": "uint8[]"}]`,
|
||||||
|
enc: "000000000000000000000000000000000000000000000000f000000000000020" + // offset
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000002" + // num elems
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
|
||||||
|
},
|
||||||
|
|
||||||
|
{ // Negative length
|
||||||
|
def: `[{"type": "uint8[]"}]`,
|
||||||
|
enc: "0000000000000000000000000000000000000000000000000000000000000020" + // offset
|
||||||
|
"000000000000000000000000000000000000000000000000f000000000000002" + // num elems
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
|
||||||
|
},
|
||||||
|
{ // Very large length
|
||||||
|
def: `[{"type": "uint8[]"}]`,
|
||||||
|
enc: "0000000000000000000000000000000000000000000000000000000000000020" + // offset
|
||||||
|
"0000000000000000000000000000000000000000000000007fffffffff000002" + // num elems
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000001" + // elem 1
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000002", // elem 2
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for i, test := range oomTests {
|
||||||
|
def := fmt.Sprintf(`[{ "name" : "method", "outputs": %s}]`, test.def)
|
||||||
|
abi, err := JSON(strings.NewReader(def))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("invalid ABI definition %s: %v", def, err)
|
||||||
|
}
|
||||||
|
encb, err := hex.DecodeString(test.enc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("invalid hex: %s" + test.enc)
|
||||||
|
}
|
||||||
|
_, err = abi.Methods["method"].Outputs.UnpackValues(encb)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("Expected error on malicious input, test %d", i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue