core/vm: correctly validate container types

This commit is contained in:
Marius van der Wijden 2024-08-30 13:53:45 +02:00
parent 5475bc96ca
commit e4af62e5f2
2 changed files with 88 additions and 86 deletions

View file

@ -319,10 +319,14 @@ func (c *Container) unmarshaSubContainer(b []byte, isInitcode bool, topLevel boo
// ValidateCode validates each code section of the container against the EOF v1 // ValidateCode validates each code section of the container against the EOF v1
// rule set. // rule set.
func (c *Container) ValidateCode(jt *JumpTable, isInitCode bool) error { func (c *Container) ValidateCode(jt *JumpTable, isInitCode bool) error {
return c.validateSubContainer(jt, isInitCode, NotRefByEither) refBy := NotRefByEither
if isInitCode {
refBy = RefByEOFCreate
}
return c.validateSubContainer(jt, refBy)
} }
func (c *Container) validateSubContainer(jt *JumpTable, isInitCode bool, refBy int) error { func (c *Container) validateSubContainer(jt *JumpTable, refBy int) error {
visited := make(map[int]struct{}) visited := make(map[int]struct{})
subContainerVisited := make(map[int]int) subContainerVisited := make(map[int]int)
toVisit := []int{0} toVisit := []int{0}
@ -338,7 +342,7 @@ func (c *Container) validateSubContainer(jt *JumpTable, isInitCode bool, refBy i
code = c.Code[index] code = c.Code[index]
) )
if _, ok := visited[index]; !ok { if _, ok := visited[index]; !ok {
res, err := validateCode(code, index, c, jt, isInitCode || refBy == RefByEOFCreate) res, err := validateCode(code, index, c, jt, refBy == RefByEOFCreate)
if err != nil { if err != nil {
return err return err
} }
@ -375,7 +379,7 @@ func (c *Container) validateSubContainer(jt *JumpTable, isInitCode bool, refBy i
if !ok { if !ok {
return ErrOrphanedSubcontainer return ErrOrphanedSubcontainer
} }
if err := container.validateSubContainer(jt, isInitCode, reference); err != nil { if err := container.validateSubContainer(jt, reference); err != nil {
return err return err
} }
} }

View file

@ -84,8 +84,8 @@ func validateCode(code []byte, section int, container *Container, jt *JumpTable,
if jt[op].undefined { if jt[op].undefined {
return nil, fmt.Errorf("%w: op %s, pos %d", ErrUndefinedInstruction, op, i) return nil, fmt.Errorf("%w: op %s, pos %d", ErrUndefinedInstruction, op, i)
} }
if size := jt[op].immediate; size != 0 { size := jt[op].immediate
if len(code) <= i+size { if size != 0 && len(code) <= i+size {
return nil, fmt.Errorf("%w: op %s, pos %d", ErrTruncatedImmediate, op, i) return nil, fmt.Errorf("%w: op %s, pos %d", ErrTruncatedImmediate, op, i)
} }
switch { switch {
@ -168,9 +168,7 @@ func validateCode(code []byte, section int, container *Container, jt *JumpTable,
} }
hasStop = true hasStop = true
} }
i += size i += size + 1
}
i += 1
} }
// Code sections may not "fall through" and require proper termination. // Code sections may not "fall through" and require proper termination.
// Therefore, the last instruction must be considered terminal or RJUMP. // Therefore, the last instruction must be considered terminal or RJUMP.