From 4d7cb406d6d3829717a93e339000d65270ad34dd Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 23 Mar 2015 11:22:32 +0100 Subject: [PATCH] Stricter RLP. --- libdevcore/Exceptions.h | 2 ++ libdevcore/RLP.cpp | 31 +++++++++++++++++++++++++------ libdevcore/RLP.h | 34 ++++++++++++++++++---------------- 3 files changed, 45 insertions(+), 22 deletions(-) diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h index df9f36030..377420003 100644 --- a/libdevcore/Exceptions.h +++ b/libdevcore/Exceptions.h @@ -44,6 +44,8 @@ struct BadHexCharacter: virtual Exception {}; struct RLPException: virtual Exception {}; struct BadCast: virtual RLPException {}; struct BadRLP: virtual RLPException {}; +struct OversizeRLP: virtual RLPException {}; +struct UndersizeRLP: virtual RLPException {}; struct NoNetworking: virtual Exception {}; struct NoUPnPDevice: virtual Exception {}; struct RootNotFound: virtual Exception {}; diff --git a/libdevcore/RLP.cpp b/libdevcore/RLP.cpp index 0dd61b876..26f10ecf5 100644 --- a/libdevcore/RLP.cpp +++ b/libdevcore/RLP.cpp @@ -26,12 +26,31 @@ using namespace dev; bytes dev::RLPNull = rlp(""); bytes dev::RLPEmptyList = rlpList(); +RLP::RLP(bytesConstRef _d, Strictness _s): + m_data(_d) +{ + if ((_s & FailIfTooBig) && actualSize() < _d.size()) + { + if (_s & ThrowOnFail) + BOOST_THROW_EXCEPTION(OversizeRLP()); + else + m_data.reset(); + } + if ((_s & FailIfTooSmall) && actualSize() > _d.size()) + { + if (_s & ThrowOnFail) + BOOST_THROW_EXCEPTION(UndersizeRLP()); + else + m_data.reset(); + } +} + RLP::iterator& RLP::iterator::operator++() { if (m_remaining) { m_lastItem.retarget(m_lastItem.next().data(), m_remaining); - m_lastItem = m_lastItem.cropped(0, RLP(m_lastItem).actualSize()); + m_lastItem = m_lastItem.cropped(0, RLP(m_lastItem, ThrowOnFail | FailIfTooSmall).actualSize()); m_remaining -= std::min(m_remaining, m_lastItem.size()); } else @@ -44,7 +63,7 @@ RLP::iterator::iterator(RLP const& _parent, bool _begin) if (_begin && _parent.isList()) { auto pl = _parent.payload(); - m_lastItem = pl.cropped(0, RLP(pl).actualSize()); + m_lastItem = pl.cropped(0, RLP(pl, ThrowOnFail | FailIfTooSmall).actualSize()); m_remaining = pl.size() - m_lastItem.size(); } else @@ -58,17 +77,17 @@ RLP RLP::operator[](unsigned _i) const { if (_i < m_lastIndex) { - m_lastEnd = RLP(payload()).actualSize(); + m_lastEnd = RLP(payload(), ThrowOnFail | FailIfTooSmall).actualSize(); m_lastItem = payload().cropped(0, m_lastEnd); m_lastIndex = 0; } for (; m_lastIndex < _i && m_lastItem.size(); ++m_lastIndex) { m_lastItem = payload().cropped(m_lastEnd); - m_lastItem = m_lastItem.cropped(0, RLP(m_lastItem).actualSize()); + m_lastItem = m_lastItem.cropped(0, RLP(m_lastItem, ThrowOnFail | FailIfTooSmall).actualSize()); m_lastEnd += m_lastItem.size(); } - return RLP(m_lastItem); + return RLP(m_lastItem, ThrowOnFail | FailIfTooSmall); } RLPs RLP::toList() const @@ -154,7 +173,7 @@ unsigned RLP::items() const bytesConstRef d = payload().cropped(0, length()); unsigned i = 0; for (; d.size(); ++i) - d = d.cropped(RLP(d).actualSize()); + d = d.cropped(RLP(d, ThrowOnFail | FailIfTooSmall).actualSize()); return i; } return 0; diff --git a/libdevcore/RLP.h b/libdevcore/RLP.h index a538fac21..a837f9221 100644 --- a/libdevcore/RLP.h +++ b/libdevcore/RLP.h @@ -62,20 +62,34 @@ static const byte c_rlpListIndLenZero = c_rlpListStart + c_rlpListImmLenCount - class RLP { public: + /// Conversion flags + enum + { + AllowNonCanon = 1, + ThrowOnFail = 4, + FailIfTooBig = 8, + FailIfTooSmall = 16, + Strict = ThrowOnFail | FailIfTooBig, + VeryStrict = ThrowOnFail | FailIfTooBig | FailIfTooSmall, + LaisezFaire = AllowNonCanon + }; + + using Strictness = int; + /// Construct a null node. RLP() {} /// Construct a node of value given in the bytes. - explicit RLP(bytesConstRef _d): m_data(_d) {} + explicit RLP(bytesConstRef _d, Strictness _s = VeryStrict); /// Construct a node of value given in the bytes. - explicit RLP(bytes const& _d): m_data(&_d) {} + explicit RLP(bytes const& _d, Strictness _s = VeryStrict): RLP(&_d, _s) {} /// Construct a node to read RLP data in the bytes given. - RLP(byte const* _b, unsigned _s): m_data(bytesConstRef(_b, _s)) {} + RLP(byte const* _b, unsigned _s, Strictness _st = VeryStrict): RLP(bytesConstRef(_b, _s), _st) {} /// Construct a node to read RLP data in the string. - explicit RLP(std::string const& _s): m_data(bytesConstRef((byte const*)_s.data(), _s.size())) {} + explicit RLP(std::string const& _s, Strictness _st = VeryStrict): RLP(bytesConstRef((byte const*)_s.data(), _s.size()), _st) {} /// The bare data of the RLP. bytesConstRef data() const { return m_data; } @@ -236,18 +250,6 @@ public: return ret; } - /// Int conversion flags - enum - { - AllowNonCanon = 1, - ThrowOnFail = 4, - FailIfTooBig = 8, - FailIfTooSmall = 16, - Strict = ThrowOnFail | FailIfTooBig, - VeryStrict = ThrowOnFail | FailIfTooBig | FailIfTooSmall, - LaisezFaire = AllowNonCanon - }; - /// Converts to int of type given; if isString(), decodes as big-endian bytestream. @returns 0 if not an int or string. template _T toInt(int _flags = Strict) const {