Skip to content

Commit

Permalink
Check for overflow in Jörmungandr.Binary
Browse files Browse the repository at this point in the history
- Particulary in encoders (putX)
- Somewhat for decoders (getX)
  • Loading branch information
Anviking committed Jul 1, 2019
1 parent 899bd88 commit c837bcc
Showing 1 changed file with 21 additions and 8 deletions.
29 changes: 21 additions & 8 deletions lib/jormungandr/src/Cardano/Wallet/Jormungandr/Binary.hs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ import Cardano.Wallet.Primitive.Types
import Control.Applicative
( many )
import Control.Monad
( replicateM )
( replicateM, unless )
import Data.Binary.Get
( Get
, bytesRead
Expand Down Expand Up @@ -138,8 +138,8 @@ getBlockHeader = label "getBlockHeader" $
-- Common structure.
version <- getWord16be
contentSize <- getWord32be
slotEpoch <- fromIntegral <$> getWord32be
slotId <- fromIntegral <$> getWord32be
slotEpoch <- unsafeFromIntegral <$> getWord32be
slotId <- unsafeFromIntegral <$> getWord32be
chainLength <- getWord32be
contentHash <- Hash <$> getByteString 32 -- or 256 bits
parentHeaderHash <- Hash <$> getByteString 32
Expand Down Expand Up @@ -246,9 +246,12 @@ getTransaction = label "getTransaction" $ do
outs <- replicateM outCount getOutput
return (ins, outs)
where
convert :: Word8 -> Word32
convert = fromIntegral

getInput = isolate 41 $ do
-- NOTE: special value 0xff indicates account spending
index <- fromIntegral <$> getWord8
index <- convert <$> getWord8
coin <- Coin <$> getWord64be
tx <- Hash <$> getByteString 32
return (TxIn tx index, coin)
Expand All @@ -265,9 +268,11 @@ getTransaction = label "getTransaction" $ do
putSignedTx :: (Tx, [TxWitness]) -> Put
putSignedTx (tx@(Tx inputs outputs), witnesses) = withSizeHeader16be $ do
putWord8 2
putWord8 $ fromIntegral $ length inputs
putWord8 $ fromIntegral $ length outputs
putWord8 $ toEnum $ length inputs
putWord8 $ toEnum $ length outputs
putTx tx
unless (length inputs == length witnesses) $
fail "number of witnesses must equal number of inputs"
mapM_ putWitness witnesses
where
-- Assumes the `TxWitness` has been faithfully constructed
Expand All @@ -278,13 +283,17 @@ putSignedTx (tx@(Tx inputs outputs), witnesses) = withSizeHeader16be $ do

putTx :: Tx -> Put
putTx (Tx inputs outputs) = do
unless (length inputs <= fromIntegral (maxBound :: Word8)) $
fail "number of inputs cannot be greater than 255"
unless (length outputs <= fromIntegral (maxBound :: Word8)) $
fail "number of outputs cannot be greater than 255"
mapM_ putInput inputs
mapM_ putOutput outputs
where
putInput (TxIn inputId inputIx, coin) = do
-- NOTE: special value 0xff indicates account spending
-- only old utxo/address scheme supported for now
putWord8 $ fromIntegral inputIx
putWord8 . unsafeFromIntegral $ inputIx
putWord64be $ getCoin coin
putByteString $ getHash inputId

Expand Down Expand Up @@ -460,9 +469,13 @@ isolatePut l x = do
withSizeHeader16be :: Put -> Put
withSizeHeader16be x = do
let bs = BL.toStrict $ runPut x
putWord16be (fromIntegral $ BS.length bs)
putWord16be (toEnum $ BS.length bs)
putByteString bs

-- Like 'fromIntegral', but throws an exception instead of overflowing.
unsafeFromIntegral :: (Enum a, Enum b) => a -> b
unsafeFromIntegral = toEnum . fromEnum

{-------------------------------------------------------------------------------
Conversions
-------------------------------------------------------------------------------}
Expand Down

0 comments on commit c837bcc

Please sign in to comment.