check for size bounds when reading varints

This commit is contained in:
Dmitriy Ryajov 2020-02-12 09:38:19 -05:00
parent 94fc4e6fd2
commit 53e163abf2
2 changed files with 16 additions and 7 deletions

View File

@ -15,7 +15,7 @@ import peerinfo,
varint, varint,
vbuffer vbuffer
const DefaultReadSize*: uint = 1 shl 20 # 1mb, in order to fit mplex spec const DefaultReadSize* = 1 shl 20
type type
Connection* = ref object of LPStream Connection* = ref object of LPStream
@ -24,10 +24,14 @@ type
observedAddrs*: Multiaddress observedAddrs*: Multiaddress
InvalidVarintException = object of LPStreamError InvalidVarintException = object of LPStreamError
InvalidVarintSizeException = object of LPStreamError
proc newInvalidVarintException*(): ref InvalidVarintException = proc newInvalidVarintException*(): ref InvalidVarintException =
newException(InvalidVarintException, "unable to parse varint") newException(InvalidVarintException, "unable to parse varint")
proc newInvalidVarintSizeException*(): ref InvalidVarintSizeException =
newException(InvalidVarintSizeException, "wrong varint size")
proc init*[T: Connection](self: var T, stream: LPStream) = proc init*[T: Connection](self: var T, stream: LPStream) =
## create a new Connection for the specified async reader/writer ## create a new Connection for the specified async reader/writer
new self new self
@ -124,8 +128,8 @@ proc readLp*(s: Connection): Future[seq[byte]] {.async, gcsafe.} =
break break
if res != VarintStatus.Success: if res != VarintStatus.Success:
raise newInvalidVarintException() raise newInvalidVarintException()
if size > DefaultReadSize: if size.int > DefaultReadSize:
raise newLPStreamLimitError() raise newInvalidVarintSizeException()
buff.setLen(size) buff.setLen(size)
if size > 0.uint: if size > 0.uint:
trace "reading exact bytes from stream", size = size trace "reading exact bytes from stream", size = size

View File

@ -7,7 +7,7 @@
## This file may not be copied, modified, or distributed except according to ## This file may not be copied, modified, or distributed except according to
## those terms. ## those terms.
import chronos, options import chronos
import nimcrypto/utils, chronicles import nimcrypto/utils, chronicles
import types, import types,
../../connection, ../../connection,
@ -18,30 +18,35 @@ import types,
logScope: logScope:
topic = "MplexCoder" topic = "MplexCoder"
const DefaultChannelSize* = 1 shr 20
type type
Msg* = tuple Msg* = tuple
id: uint id: uint
msgType: MessageType msgType: MessageType
data: seq[byte] data: seq[byte]
proc readMplexVarint(conn: Connection): Future[Option[uint]] {.async, gcsafe.} = proc readMplexVarint(conn: Connection): Future[uint] {.async, gcsafe.} =
var var
varint: uint varint: uint
length: int length: int
res: VarintStatus res: VarintStatus
buffer = newSeq[byte](10) buffer = newSeq[byte](10)
result = none(uint)
try: try:
for i in 0..<len(buffer): for i in 0..<len(buffer):
await conn.readExactly(addr buffer[i], 1) await conn.readExactly(addr buffer[i], 1)
res = PB.getUVarint(buffer.toOpenArray(0, i), length, varint) res = PB.getUVarint(buffer.toOpenArray(0, i), length, varint)
if res == VarintStatus.Success: if res == VarintStatus.Success:
return some(varint) break
if res != VarintStatus.Success: if res != VarintStatus.Success:
raise newInvalidVarintException() raise newInvalidVarintException()
if varint.int > DefaultReadSize:
raise newInvalidVarintSizeException()
return varint
except LPStreamIncompleteError as exc: except LPStreamIncompleteError as exc:
trace "unable to read varint", exc = exc.msg trace "unable to read varint", exc = exc.msg
raise exc
proc readMsg*(conn: Connection): Future[Msg] {.async, gcsafe.} = proc readMsg*(conn: Connection): Future[Msg] {.async, gcsafe.} =
let headerVarint = await conn.readMplexVarint() let headerVarint = await conn.readMplexVarint()