From 955b7b31a52c624bd1a1ced386f490000c0720f8 Mon Sep 17 00:00:00 2001 From: compmaniak <6314398+compmaniak@users.noreply.github.com> Date: Mon, 15 Oct 2018 00:30:19 +0300 Subject: [PATCH] Fix parsing of out-of-bounds hex values fix #1267 --- CHANGELOG.md | 1 + doc/qbk/09_releases.qbk | 2 ++ .../boost/beast/http/detail/basic_parser.hpp | 32 ++++++++++------- test/beast/http/basic_parser.cpp | 35 +++++++++++++++++++ 4 files changed, 57 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80cd15e8..df814ecf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ Version 186: * basic_fields uses intrusive base hooks +* Fix parsing of out-of-bounds hex values -------------------------------------------------------------------------------- diff --git a/doc/qbk/09_releases.qbk b/doc/qbk/09_releases.qbk index 1f571531..40c44af3 100644 --- a/doc/qbk/09_releases.qbk +++ b/doc/qbk/09_releases.qbk @@ -29,6 +29,8 @@ * ([issue 1270]) `basic_fields` uses intrusive base hooks +* ([issue 1267]) Fix parsing of out-of-bounds hex values + * Workaround for http-server-fast and libstdc++ diff --git a/include/boost/beast/http/detail/basic_parser.hpp b/include/boost/beast/http/detail/basic_parser.hpp index 818277be..741de6ed 100644 --- a/include/boost/beast/http/detail/basic_parser.hpp +++ b/include/boost/beast/http/detail/basic_parser.hpp @@ -35,6 +35,12 @@ struct basic_parser_base // static std::size_t constexpr max_obs_fold = 4096; + template + struct is_unsigned_integer: + std::integral_constant::is_integer && + ! std::numeric_limits::is_signed> {}; + enum class state { nothing_yet = 0, @@ -301,9 +307,7 @@ struct basic_parser_base template static - typename std::enable_if< - std::numeric_limits::is_integer && - ! std::numeric_limits::is_signed, bool>::type + typename std::enable_if::value, bool>::type parse_dec(Iter it, Iter last, T& v) { if(it == last) @@ -325,24 +329,26 @@ struct basic_parser_base return true; } - template + template static - bool - parse_hex(Iter& it, Unsigned& v) + typename std::enable_if::value, bool>::type + parse_hex(Iter& it, T& v) { unsigned char d; if(! unhex(d, *it)) return false; - v = d; - for(;;) + T tmp = 0; + do { - if(! unhex(d, *++it)) - break; - auto const v0 = v; - v = 16 * v + d; - if(v < v0) + if(tmp > (std::numeric_limits::max)() / 16) return false; + tmp *= 16; + if((std::numeric_limits::max)() - tmp < d) + return false; + tmp += d; } + while(unhex(d, *++it)); + v = tmp; return true; } diff --git a/test/beast/http/basic_parser.cpp b/test/beast/http/basic_parser.cpp index 0c346021..c98c36ed 100644 --- a/test/beast/http/basic_parser.cpp +++ b/test/beast/http/basic_parser.cpp @@ -1249,6 +1249,40 @@ public: bad ("4294967296"); } + void + testIssue1267() + { + using base = detail::basic_parser_base; + auto const good = + [&](string_view s, std::uint64_t v0) + { + std::uint64_t v; + auto it = s.begin(); + auto const result = + base::parse_hex(it, v); + if(BEAST_EXPECTS(result, s)) + BEAST_EXPECTS(v == v0, s); + }; + auto const bad = + [&](string_view s) + { + std::uint64_t v; + auto it = s.begin(); + auto const result = + base::parse_hex(it, v); + BEAST_EXPECTS(! result, s); + }; + good("f\r\n", 15); + good("ff\r\n", 255); + good("ffff\r\n", 65535); + good("ffffffffr\n", 4294967295); + good("ffffffffffffffff\r\n", 18446744073709551615ULL); + bad ("\r\n"); + bad ("g\r\n"); + bad ("10000000000000000\r\n"); + bad ("ffffffffffffffffffffff\r\n"); + } + //-------------------------------------------------------------------------- void @@ -1274,6 +1308,7 @@ public: testFuzz(); testRegression1(); testIssue1211(); + testIssue1267(); } };