Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 13 additions & 8 deletions async_postgres/pg_types/decoding.nim
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,12 @@ proc decodeBinaryTsVector*(data: openArray[byte]): string =
parts[i] = part
parts.join(" ")

proc parseTsQueryNode(data: openArray[byte], pos: var int): string =
proc parseTsQueryNode(data: openArray[byte], pos: var int, depth: int = 0): string =
const maxDepth = 1000
if depth >= maxDepth:
raise newException(
PgTypeError, "tsquery binary: nesting depth exceeds limit (" & $maxDepth & ")"
)
if pos >= data.len:
raise newException(PgTypeError, "tsquery binary truncated")
let tokenType = data[pos]
Expand Down Expand Up @@ -698,23 +703,23 @@ proc parseTsQueryNode(data: openArray[byte], pos: var int): string =
inc pos
case op
of 1: # NOT
let arg = parseTsQueryNode(data, pos)
let arg = parseTsQueryNode(data, pos, depth + 1)
"!" & arg
of 2: # AND
let left = parseTsQueryNode(data, pos)
let right = parseTsQueryNode(data, pos)
let left = parseTsQueryNode(data, pos, depth + 1)
let right = parseTsQueryNode(data, pos, depth + 1)
left & " & " & right
of 3: # OR
let left = parseTsQueryNode(data, pos)
let right = parseTsQueryNode(data, pos)
let left = parseTsQueryNode(data, pos, depth + 1)
let right = parseTsQueryNode(data, pos, depth + 1)
"( " & left & " | " & right & " )"
of 4: # PHRASE
if pos + 1 >= data.len:
raise newException(PgTypeError, "tsquery PHRASE distance truncated")
let distance = int(fromBE16(data.toOpenArray(pos, pos + 1)))
pos += 2
let left = parseTsQueryNode(data, pos)
let right = parseTsQueryNode(data, pos)
let left = parseTsQueryNode(data, pos, depth + 1)
let right = parseTsQueryNode(data, pos, depth + 1)
if distance == 1:
left & " <-> " & right
else:
Expand Down
16 changes: 16 additions & 0 deletions tests/test_protocol_fuzz.nim
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,22 @@ suite "Binary type decoders: malformed input":
expectTypeError:
discard decodeBinaryTsQuery(data)

test "decodeBinaryTsQuery nesting depth limit":
# Build a chain of 1001 NOT operators (depth >= 1000) wrapping an operand.
# Each NOT = [2, 1], operand = [1, 0, 0, 'x', 0].
const nNot = 1001
const operand = @[byte 1, 0, 0, byte('x'), 0]
var data = newSeq[byte](4 + nNot * 2 + operand.len)
data[0 .. 3] = toBE32((nNot + 1).int32)
var pos = 4
for _ in 0 ..< nNot:
data[pos] = 2
data[pos + 1] = 1
pos += 2
data[pos ..^ 1] = operand
expectTypeError:
discard decodeBinaryTsQuery(data)

# Seeded random fuzz on binary type decoders

suite "Binary type decoders: seeded random fuzz":
Expand Down