0
0
Fork 0
mirror of https://github.com/matrix-construct/construct synced 2024-11-25 16:22:35 +01:00

ircd::json: Add recursion depth checking.

This commit is contained in:
Jason Volk 2018-01-18 03:39:19 -08:00
parent c9b89ec6ef
commit 90ea730a04
5 changed files with 54 additions and 25 deletions

View file

@ -55,6 +55,8 @@ struct ircd::json::array
using size_type = size_t;
using difference_type = ptrdiff_t;
static const uint max_recursion_depth;
const_iterator end() const;
const_iterator begin() const;

View file

@ -31,6 +31,7 @@ namespace ircd::json
IRCD_EXCEPTION(error, print_error);
IRCD_EXCEPTION(error, type_error);
IRCD_EXCEPTION(error, not_found);
IRCD_EXCEPTION(parse_error, recursion_limit);
struct value;
struct member;

View file

@ -80,6 +80,8 @@ struct ircd::json::object
using difference_type = ptrdiff_t;
using key_compare = std::less<member>;
static const uint max_recursion_depth;
// fundamental
const_iterator end() const;
const_iterator begin() const;

View file

@ -30,6 +30,7 @@
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>

View file

@ -45,6 +45,7 @@ namespace ircd::json
using qi::eps;
using qi::attr;
using qi::repeat;
using qi::_r1_type;
using karma::lit;
using karma::char_;
@ -161,29 +162,35 @@ struct ircd::json::input
,"name"
};
rule<> member
// recursion depth
_r1_type depth;
[[noreturn]] static void throws_exceeded();
const rule<unused_type(uint)> member
{
name >> name_sep >> value
name >> name_sep >> value(depth)
,"member"
};
rule<> object
const rule<unused_type(uint)> object
{
//TODO: XXX: Recursion depth check attribute
object_begin >> -(member % value_sep) >> object_end
(eps(depth < json::object::max_recursion_depth) | eps[throws_exceeded]) >>
object_begin >> -(member(depth) % value_sep) >> object_end
,"object"
};
rule<> array
const rule<unused_type(uint)> array
{
//TODO: XXX: Recursion depth check attribute
array_begin >> -(value % value_sep) >> array_end
(eps(depth < json::array::max_recursion_depth) | eps[throws_exceeded]) >>
array_begin >> -(value(depth) % value_sep) >> array_end
,"array"
};
rule<> value
const rule<unused_type(uint)> value
{
lit_false | lit_null | lit_true | object | array | number | string
lit_false | lit_null | lit_true | object(depth + 1) | array(depth + 1) | number | string
,"value"
};
@ -199,13 +206,7 @@ struct ircd::json::input
input()
:input::base_type{rule<>{}}
{
//TODO: Recursion seems to require these restatements
//TODO: Can they be eliminated for DRY?
member %= name >> name_sep >> value;
array %= array_begin >> -(value % value_sep) >> array_end;
object %= object_begin >> -(member % value_sep) >> object_end;
}
{}
};
template<class it>
@ -376,6 +377,16 @@ ircd::json::printer::list_protocol(mutable_buffer &buffer,
}
}
template<class it>
void
ircd::json::input<it>::throws_exceeded()
{
throw recursion_limit
{
"Maximum recursion depth exceeded"
};
}
///////////////////////////////////////////////////////////////////////////////
//
// iov.h
@ -546,7 +557,7 @@ try
{
static const qi::rule<const char *, string_view> parse_next
{
raw[parser.object] | qi::eoi
raw[parser.object(0)] | qi::eoi
,"next vector element or end"
};
@ -566,7 +577,7 @@ const try
{
static const qi::rule<const char *, string_view> parse_begin
{
raw[parser.object]
raw[parser.object(0)]
,"object vector element"
};
@ -679,6 +690,12 @@ ircd::json::serialized(const member &member)
// json/object.h
//
decltype(ircd::json::object::max_recursion_depth)
const ircd::json::object::max_recursion_depth
{
32
};
std::ostream &
ircd::json::operator<<(std::ostream &s, const object::member &member)
{
@ -750,7 +767,7 @@ try
{
static const qi::rule<const char *, json::object::member> member
{
parser.name >> parser.name_sep >> raw[parser.value]
parser.name >> parser.name_sep >> raw[parser.value(0)]
,"next object member"
};
@ -782,7 +799,7 @@ const try
{
static const qi::rule<const char *, json::object::member> object_member
{
parser.name >> parser.name_sep >> raw[parser.value]
parser.name >> parser.name_sep >> raw[parser.value(0)]
,"object member"
};
@ -819,6 +836,12 @@ const
// json/array.h
//
decltype(ircd::json::array::max_recursion_depth)
ircd::json::array::max_recursion_depth
{
32
};
ircd::string_view
ircd::json::stringify(mutable_buffer &buf,
const array &v)
@ -900,7 +923,7 @@ try
{
static const qi::rule<const char *, string_view> value
{
raw[parser.value]
raw[parser.value(0)]
,"array element"
};
@ -931,7 +954,7 @@ const try
{
static const qi::rule<const char *, string_view> value
{
raw[parser.value]
raw[parser.value(0)]
,"array element"
};
@ -1575,7 +1598,7 @@ ircd::json::valid(const string_view &s,
noexcept try
{
const char *start(begin(s)), *const stop(end(s));
return qi::parse(start, stop, parser.value >> eoi);
return qi::parse(start, stop, parser.value(0) >> eoi);
}
catch(...)
{
@ -1587,7 +1610,7 @@ ircd::json::valid(const string_view &s)
try
{
const char *start(begin(s)), *const stop(end(s));
qi::parse(start, stop, eps > (parser.value >> eoi));
qi::parse(start, stop, eps > (parser.value(0) >> eoi));
}
catch(const qi::expectation_failure<const char *> &e)
{