-
Notifications
You must be signed in to change notification settings - Fork 500
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5050 from tamirms/internal-fixes
horizon: Merge internal fixes into master
- Loading branch information
Showing
8 changed files
with
236 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package gxdr | ||
|
||
import ( | ||
"encoding/base64" | ||
"strings" | ||
|
||
goxdr "github.com/xdrpp/goxdr/xdr" | ||
) | ||
|
||
const DefaultMaxDepth = 500 | ||
|
||
type depthLimiter struct { | ||
depth int | ||
maxDepth int | ||
decoder *goxdr.XdrIn | ||
} | ||
|
||
func (*depthLimiter) Sprintf(f string, args ...interface{}) string { | ||
return "" | ||
} | ||
|
||
func (d *depthLimiter) Marshal(field string, i goxdr.XdrType) { | ||
switch t := goxdr.XdrBaseType(i).(type) { | ||
case goxdr.XdrAggregate: | ||
if d.depth > d.maxDepth { | ||
goxdr.XdrPanic("max depth of %d exceeded", d.maxDepth) | ||
} | ||
d.depth++ | ||
t.XdrRecurse(d, field) | ||
d.depth-- | ||
default: | ||
d.decoder.Marshal(field, t) | ||
} | ||
} | ||
|
||
// ValidateTransactionEnvelope validates the given transaction envelope | ||
// to make sure that it does not contain malicious arrays or nested | ||
// structures which are too deep | ||
func ValidateTransactionEnvelope(b64Envelope string, maxDepth int) error { | ||
return validate(b64Envelope, &TransactionEnvelope{}, maxDepth) | ||
} | ||
|
||
// ValidateLedgerKey validates the given ledger key | ||
// to make sure that it does not contain malicious arrays or nested | ||
// structures which are too deep | ||
func ValidateLedgerKey(b64Key string, maxDepth int) error { | ||
return validate(b64Key, &LedgerKey{}, maxDepth) | ||
} | ||
|
||
func validate(b64 string, val goxdr.XdrType, maxDepth int) (err error) { | ||
d := &depthLimiter{ | ||
depth: 0, | ||
maxDepth: maxDepth, | ||
decoder: &goxdr.XdrIn{ | ||
In: base64.NewDecoder(base64.StdEncoding, strings.NewReader(b64)), | ||
}, | ||
} | ||
|
||
defer func() { | ||
switch i := recover().(type) { | ||
case nil: | ||
case goxdr.XdrError: | ||
err = i | ||
default: | ||
panic(i) | ||
} | ||
}() | ||
val.XdrMarshal(d, "") | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
package gxdr | ||
|
||
import ( | ||
"encoding/base64" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
goxdr "github.com/xdrpp/goxdr/xdr" | ||
) | ||
|
||
func buildVec(depth int) SCVal { | ||
if depth <= 0 { | ||
symbol := SCSymbol("s") | ||
return SCVal{ | ||
Type: SCV_SYMBOL, | ||
_u: &symbol, | ||
} | ||
} | ||
vec := &SCVec{ | ||
buildVec(depth - 1), | ||
} | ||
return SCVal{Type: SCV_VEC, _u: &vec} | ||
} | ||
|
||
func buildMaliciousVec(t *testing.T) string { | ||
vals := &SCVec{} | ||
for i := 0; i < 0x0D; i++ { | ||
symbol := SCSymbol("s") | ||
*vals = append(*vals, SCVal{ | ||
Type: SCV_SYMBOL, | ||
_u: &symbol, | ||
}) | ||
} | ||
vec := SCVal{Type: SCV_VEC, _u: &vals} | ||
raw := Dump(&vec) | ||
// raw[8-11] represents the part of the xdr that holds the | ||
// length of the vector | ||
for i, b := range raw { | ||
if b == 0x0D { | ||
assert.Equal(t, 11, i) | ||
} | ||
} | ||
// here we override the most significant byte in the vector length | ||
// so that the vector length in the xdr is 0xFA00000D which | ||
// is equal to 4194304013 | ||
raw[8] = 0xFA | ||
return base64.StdEncoding.EncodeToString(raw) | ||
} | ||
|
||
func TestValidator(t *testing.T) { | ||
shallowVec := buildVec(2) | ||
deepVec := buildVec(100) | ||
for _, testCase := range []struct { | ||
name string | ||
input string | ||
maxDepth int | ||
val goxdr.XdrType | ||
expectedError string | ||
}{ | ||
{ | ||
"invalid base 64 input", | ||
"{}<>~!@$#", | ||
500, | ||
&LedgerEntry{}, | ||
"illegal base64 data at input byte 0", | ||
}, | ||
{ | ||
"valid depth", | ||
base64.StdEncoding.EncodeToString(Dump(&shallowVec)), | ||
500, | ||
&SCVal{}, | ||
"", | ||
}, | ||
{ | ||
"invalid depth", | ||
base64.StdEncoding.EncodeToString(Dump(&deepVec)), | ||
50, | ||
&SCVal{}, | ||
"max depth of 50 exceeded", | ||
}, | ||
{ | ||
"malicious length", | ||
buildMaliciousVec(t), | ||
500, | ||
&SCVal{}, | ||
"EOF", | ||
}, | ||
} { | ||
t.Run(testCase.name, func(t *testing.T) { | ||
err := validate(testCase.input, testCase.val, testCase.maxDepth) | ||
if testCase.expectedError == "" { | ||
assert.NoError(t, err) | ||
assert.Equal(t, testCase.input, base64.StdEncoding.EncodeToString(Dump(testCase.val))) | ||
} else { | ||
assert.EqualError(t, err, testCase.expectedError) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters