diff options
author | Ting-Wei Lan <tingwei.lan@cobinhood.com> | 2019-03-04 16:06:14 +0800 |
---|---|---|
committer | Jhih-Ming Huang <jm.huang@cobinhood.com> | 2019-05-06 10:44:04 +0800 |
commit | 126145a7eca2c054367abc65291ab1c90c51b998 (patch) | |
tree | 549ad2d5eb4c70f096d265cc3a7a6a9f1bb3c120 /core/vm/sqlvm/parser/parser.go | |
parent | efabc336cf705aab463d81dd20e8d95df97e0965 (diff) | |
download | dexon-126145a7eca2c054367abc65291ab1c90c51b998.tar dexon-126145a7eca2c054367abc65291ab1c90c51b998.tar.gz dexon-126145a7eca2c054367abc65291ab1c90c51b998.tar.bz2 dexon-126145a7eca2c054367abc65291ab1c90c51b998.tar.lz dexon-126145a7eca2c054367abc65291ab1c90c51b998.tar.xz dexon-126145a7eca2c054367abc65291ab1c90c51b998.tar.zst dexon-126145a7eca2c054367abc65291ab1c90c51b998.zip |
core: vm: sqlvm: limit the depth of AST to 1024
Since we traverse an AST by calling functions recursively, we have to
protect the parser by limiting the depth of an AST.
Diffstat (limited to 'core/vm/sqlvm/parser/parser.go')
-rw-r--r-- | core/vm/sqlvm/parser/parser.go | 48 |
1 files changed, 41 insertions, 7 deletions
diff --git a/core/vm/sqlvm/parser/parser.go b/core/vm/sqlvm/parser/parser.go index a90fec71c..8ed94e7aa 100644 --- a/core/vm/sqlvm/parser/parser.go +++ b/core/vm/sqlvm/parser/parser.go @@ -9,20 +9,40 @@ import ( "github.com/dexon-foundation/dexon/core/vm/sqlvm/parser/internal" ) -func walkSelfFirst(n ast.Node, v func(ast.Node, []ast.Node)) { +type visitor func(ast.Node, []ast.Node) + +func walkSelfFirst(n ast.Node, v visitor) bool { + return walkSelfFirstWithDepth(n, v, 0) +} + +func walkSelfFirstWithDepth(n ast.Node, v visitor, d int) bool { + if d >= ast.DepthLimit { + return false + } c := n.GetChildren() + r := true v(n, c) for i := range c { - walkSelfFirst(c[i], v) + r = r && walkSelfFirstWithDepth(c[i], v, d+1) } + return r } -func walkChildrenFirst(n ast.Node, v func(ast.Node, []ast.Node)) { +func walkChildrenFirst(n ast.Node, v visitor) bool { + return walkChildrenFirstWithDepth(n, v, 0) +} + +func walkChildrenFirstWithDepth(n ast.Node, v visitor, d int) bool { + if d >= ast.DepthLimit { + return false + } c := n.GetChildren() + r := true for i := range c { - walkChildrenFirst(c[i], v) + r = r && walkChildrenFirstWithDepth(c[i], v, d+1) } v(n, c) + return r } // Parse parses SQL commands text and return an AST. @@ -65,7 +85,8 @@ func Parse(b []byte) ([]ast.Node, error) { if stmts[i] == nil { continue } - walkChildrenFirst(stmts[i], func(n ast.Node, c []ast.Node) { + r := true + r = r && walkChildrenFirst(stmts[i], func(n ast.Node, c []ast.Node) { minBegin := uint32(len(eb)) maxEnd := uint32(0) for _, cn := range append(c, n) { @@ -83,7 +104,7 @@ func Parse(b []byte) ([]ast.Node, error) { n.SetPosition(minBegin) n.SetLength(maxEnd - minBegin) }) - walkSelfFirst(stmts[i], func(n ast.Node, _ []ast.Node) { + r = r && walkSelfFirst(stmts[i], func(n ast.Node, _ []ast.Node) { begin := n.GetPosition() end := begin + n.GetLength() fixedBegin, ok := encMap[begin] @@ -97,9 +118,22 @@ func Parse(b []byte) ([]ast.Node, error) { n.SetPosition(fixedBegin) n.SetLength(fixedEnd - fixedBegin) }) + if !r { + return nil, errors.ErrorList{ + errors.Error{ + Position: 0, + Category: errors.ErrorCategoryLimit, + Code: errors.ErrorCodeDepthLimitReached, + Token: "", + Prefix: "", + Message: fmt.Sprintf("reach syntax tree depth limit %d", + ast.DepthLimit), + }, + } + } } if pigeonErr == nil { - return stmts, pigeonErr + return stmts, nil } // Process errors. |