mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 02:12:23 +00:00
Fix EOF Validation issues
Fixes a few EOF validation issues in EEST and found by fuzzing. * subcontainers header with zero subcontainers is invalid * returning code sections require at least one RETF or qualified JUMPF * RETF stack must have stack enough for outputs * JUMPF must not jump into a section with more outputs * Check stack minimums on RJIMPI and RJUMPV
This commit is contained in:
parent
71ffe6e6dd
commit
658e4e5559
4 changed files with 24 additions and 5 deletions
|
|
@ -170,7 +170,7 @@ func ExecuteTest(src []byte) (int, int, error) {
|
||||||
return 0, 0, err
|
return 0, 0, err
|
||||||
}
|
}
|
||||||
passed, total := 0, 0
|
passed, total := 0, 0
|
||||||
for _, tests := range testsByName {
|
for testsName, tests := range testsByName {
|
||||||
for name, tt := range tests.Vectors {
|
for name, tt := range tests.Vectors {
|
||||||
for fork, r := range tt.Results {
|
for fork, r := range tt.Results {
|
||||||
total++
|
total++
|
||||||
|
|
@ -181,11 +181,11 @@ func ExecuteTest(src []byte) (int, int, error) {
|
||||||
err = err2
|
err = err2
|
||||||
}
|
}
|
||||||
if r.Result && err != nil {
|
if r.Result && err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "%s, %s: expected success, got %v\n", name, fork, err)
|
fmt.Fprintf(os.Stderr, "%s %s, %s: expected success, got %v\n", testsName, name, fork, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !r.Result && err == nil {
|
if !r.Result && err == nil {
|
||||||
fmt.Fprintf(os.Stderr, "%s, %s: expected error %s, got %v\n", name, fork, r.Exception, err)
|
fmt.Fprintf(os.Stderr, "%s %s, %s: expected error %s, got %v\n", testsName, name, fork, r.Exception, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -206,6 +206,9 @@ func (c *Container) unmarshalSubContainer(b []byte, isInitcode bool, topLevel bo
|
||||||
if kind != kindContainer {
|
if kind != kindContainer {
|
||||||
panic("somethings wrong")
|
panic("somethings wrong")
|
||||||
}
|
}
|
||||||
|
if len(containerSizes) == 0 {
|
||||||
|
return fmt.Errorf("%w: total container count must not be zero", ErrInvalidContainerSectionSize)
|
||||||
|
}
|
||||||
offset = offset + 2 + 2*len(containerSizes) + 1
|
offset = offset + 2 + 2*len(containerSizes) + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ var (
|
||||||
ErrInvalidEOFInitcode = errors.New("invalid eof initcode")
|
ErrInvalidEOFInitcode = errors.New("invalid eof initcode")
|
||||||
ErrNonceUintOverflow = errors.New("nonce uint64 overflow")
|
ErrNonceUintOverflow = errors.New("nonce uint64 overflow")
|
||||||
ErrInvalidNumberOfOutputs = errors.New("invalid number of outputs")
|
ErrInvalidNumberOfOutputs = errors.New("invalid number of outputs")
|
||||||
|
ErrInvalidNonReturningFlag = errors.New("Invalid non-returning flag, bad RETF")
|
||||||
|
|
||||||
// errStopToken is an internal token indicating interpreter loop termination,
|
// errStopToken is an internal token indicating interpreter loop termination,
|
||||||
// never returned to outside callers.
|
// never returned to outside callers.
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ func validateControlFlow2(code []byte, section int, metadata []*FunctionMetadata
|
||||||
// set the initial stack bounds
|
// set the initial stack bounds
|
||||||
setBounds(0, int(metadata[section].Input), int(metadata[section].Input))
|
setBounds(0, int(metadata[section].Input), int(metadata[section].Input))
|
||||||
|
|
||||||
|
qualifiedExit := false
|
||||||
for pos := 0; pos < len(code); pos++ {
|
for pos := 0; pos < len(code); pos++ {
|
||||||
op := OpCode(code[pos])
|
op := OpCode(code[pos])
|
||||||
currentBounds := stackBounds[pos]
|
currentBounds := stackBounds[pos]
|
||||||
|
|
@ -62,9 +63,14 @@ func validateControlFlow2(code []byte, section int, metadata []*FunctionMetadata
|
||||||
if currentBounds.max != currentBounds.min {
|
if currentBounds.max != currentBounds.min {
|
||||||
return 0, fmt.Errorf("%w: max %d, min %d, at pos %d", ErrInvalidNumberOfOutputs, currentBounds.max, currentBounds.min, pos)
|
return 0, fmt.Errorf("%w: max %d, min %d, at pos %d", ErrInvalidNumberOfOutputs, currentBounds.max, currentBounds.min, pos)
|
||||||
}
|
}
|
||||||
if have, want := int(metadata[section].Output), currentBounds.min; have != want {
|
have := int(metadata[section].Output)
|
||||||
|
if have >= maxOutputItems {
|
||||||
|
return 0, fmt.Errorf("%w: at pos %d", ErrInvalidNonReturningFlag, pos)
|
||||||
|
}
|
||||||
|
if want := currentBounds.min; have != want {
|
||||||
return 0, fmt.Errorf("%w: have %d, want %d, at pos %d", ErrInvalidOutputs, have, want, pos)
|
return 0, fmt.Errorf("%w: have %d, want %d, at pos %d", ErrInvalidOutputs, have, want, pos)
|
||||||
}
|
}
|
||||||
|
qualifiedExit = true
|
||||||
case JUMPF:
|
case JUMPF:
|
||||||
arg, _ := parseUint16(code[pos+1:])
|
arg, _ := parseUint16(code[pos+1:])
|
||||||
newSection := metadata[arg]
|
newSection := metadata[arg]
|
||||||
|
|
@ -76,6 +82,9 @@ func validateControlFlow2(code []byte, section int, metadata []*FunctionMetadata
|
||||||
return 0, fmt.Errorf("%w: at pos %d", ErrStackUnderflow{stackLen: have, required: want}, pos)
|
return 0, fmt.Errorf("%w: at pos %d", ErrStackUnderflow{stackLen: have, required: want}, pos)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if metadata[section].Output < newSection.Output {
|
||||||
|
return 0, fmt.Errorf("%w: at pos %d", ErrInvalidNumberOfOutputs, pos)
|
||||||
|
}
|
||||||
if currentBounds.max != currentBounds.min {
|
if currentBounds.max != currentBounds.min {
|
||||||
return 0, fmt.Errorf("%w: max %d, min %d, at pos %d", ErrInvalidNumberOfOutputs, currentBounds.max, currentBounds.min, pos)
|
return 0, fmt.Errorf("%w: max %d, min %d, at pos %d", ErrInvalidNumberOfOutputs, currentBounds.max, currentBounds.min, pos)
|
||||||
}
|
}
|
||||||
|
|
@ -83,6 +92,7 @@ func validateControlFlow2(code []byte, section int, metadata []*FunctionMetadata
|
||||||
return 0, fmt.Errorf("%w: at pos %d", ErrInvalidNumberOfOutputs, pos)
|
return 0, fmt.Errorf("%w: at pos %d", ErrInvalidNumberOfOutputs, pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
qualifiedExit = qualifiedExit || newSection.Output < maxOutputItems
|
||||||
case DUPN:
|
case DUPN:
|
||||||
arg := int(code[pos+1]) + 1
|
arg := int(code[pos+1]) + 1
|
||||||
if want, have := arg, currentBounds.min; want > have {
|
if want, have := arg, currentBounds.min; want > have {
|
||||||
|
|
@ -175,12 +185,14 @@ func validateControlFlow2(code []byte, section int, metadata []*FunctionMetadata
|
||||||
// target reached via backwards jump
|
// target reached via backwards jump
|
||||||
nextBounds, ok := stackBounds[nextPC]
|
nextBounds, ok := stackBounds[nextPC]
|
||||||
if !ok {
|
if !ok {
|
||||||
fmt.Print("2")
|
|
||||||
return 0, ErrInvalidBackwardJump
|
return 0, ErrInvalidBackwardJump
|
||||||
}
|
}
|
||||||
if currentStackMax != nextBounds.max {
|
if currentStackMax != nextBounds.max {
|
||||||
return 0, fmt.Errorf("%w want %d as current max got %d at pos %d,", ErrInvalidBackwardJump, currentStackMax, nextBounds.max, pos)
|
return 0, fmt.Errorf("%w want %d as current max got %d at pos %d,", ErrInvalidBackwardJump, currentStackMax, nextBounds.max, pos)
|
||||||
}
|
}
|
||||||
|
if currentStackMin != nextBounds.min {
|
||||||
|
return 0, fmt.Errorf("%w want %d as current min got %d at pos %d,", ErrInvalidBackwardJump, currentStackMin, nextBounds.min, pos)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -192,6 +204,9 @@ func validateControlFlow2(code []byte, section int, metadata []*FunctionMetadata
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if qualifiedExit != (metadata[section].Output < maxOutputItems) {
|
||||||
|
return 0, fmt.Errorf("%w no RETF or qualified JUMPF", ErrInvalidNonReturningFlag)
|
||||||
|
}
|
||||||
if maxStackHeight >= int(params.StackLimit) {
|
if maxStackHeight >= int(params.StackLimit) {
|
||||||
return 0, ErrStackOverflow{maxStackHeight, int(params.StackLimit)}
|
return 0, ErrStackOverflow{maxStackHeight, int(params.StackLimit)}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue