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
|
||||
}
|
||||
passed, total := 0, 0
|
||||
for _, tests := range testsByName {
|
||||
for testsName, tests := range testsByName {
|
||||
for name, tt := range tests.Vectors {
|
||||
for fork, r := range tt.Results {
|
||||
total++
|
||||
|
|
@ -181,11 +181,11 @@ func ExecuteTest(src []byte) (int, int, error) {
|
|||
err = err2
|
||||
}
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -206,6 +206,9 @@ func (c *Container) unmarshalSubContainer(b []byte, isInitcode bool, topLevel bo
|
|||
if kind != kindContainer {
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ var (
|
|||
ErrInvalidEOFInitcode = errors.New("invalid eof initcode")
|
||||
ErrNonceUintOverflow = errors.New("nonce uint64 overflow")
|
||||
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,
|
||||
// never returned to outside callers.
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ func validateControlFlow2(code []byte, section int, metadata []*FunctionMetadata
|
|||
// set the initial stack bounds
|
||||
setBounds(0, int(metadata[section].Input), int(metadata[section].Input))
|
||||
|
||||
qualifiedExit := false
|
||||
for pos := 0; pos < len(code); pos++ {
|
||||
op := OpCode(code[pos])
|
||||
currentBounds := stackBounds[pos]
|
||||
|
|
@ -62,9 +63,14 @@ func validateControlFlow2(code []byte, section int, metadata []*FunctionMetadata
|
|||
if currentBounds.max != currentBounds.min {
|
||||
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)
|
||||
}
|
||||
qualifiedExit = true
|
||||
case JUMPF:
|
||||
arg, _ := parseUint16(code[pos+1:])
|
||||
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)
|
||||
}
|
||||
} else {
|
||||
if metadata[section].Output < newSection.Output {
|
||||
return 0, fmt.Errorf("%w: at pos %d", ErrInvalidNumberOfOutputs, pos)
|
||||
}
|
||||
if currentBounds.max != currentBounds.min {
|
||||
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)
|
||||
}
|
||||
}
|
||||
qualifiedExit = qualifiedExit || newSection.Output < maxOutputItems
|
||||
case DUPN:
|
||||
arg := int(code[pos+1]) + 1
|
||||
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
|
||||
nextBounds, ok := stackBounds[nextPC]
|
||||
if !ok {
|
||||
fmt.Print("2")
|
||||
return 0, ErrInvalidBackwardJump
|
||||
}
|
||||
if currentStackMax != nextBounds.max {
|
||||
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) {
|
||||
return 0, ErrStackOverflow{maxStackHeight, int(params.StackLimit)}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue