Skip to content

Commit 39947fd

Browse files
zhenjiaseulihuiba
andauthored
fix trailer for illegal inputs (alibaba#1023) (alibaba#1050)
Co-authored-by: Huiba Li <huiba.lhb@alibaba-inc.com>
1 parent c401a0e commit 39947fd

2 files changed

Lines changed: 37 additions & 5 deletions

File tree

ecosystem/simple_dom.cpp

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -254,15 +254,32 @@ struct JHandler : public BaseReaderHandler<UTF8<>, JHandler> {
254254
// As some parsers don't support text length, they only support null
255255
// terminated strings, so we have to convert the last trailer to '\0',
256256
// while making the parser to treat it as the trailer.
257-
inline void fix_trail(char* text, size_t size, char trailer) {
258-
auto i = estring_view(text, size).rfind(trailer);
259-
if (i != estring_view::npos) text[i] = '\0';
257+
static bool fix_trail(estring_view text, char header, char trailer) {
258+
auto i = text.rfind(trailer);
259+
if (i == estring_view::npos)
260+
LOG_ERROR_RETURN(EINVAL, false, "no trailer found");
261+
for (char c: text.substr(i+1))
262+
if (!isspace(c))
263+
LOG_ERROR_RETURN(EINVAL, false, "illegal character after trailer");
264+
size_t k = 0;
265+
for (char c: text.substr(0, i+1)) {
266+
if (!c)
267+
LOG_ERROR_RETURN(EINVAL, false, "unexpected '\\0'");
268+
if (c == header) ++k;
269+
else if (c == trailer)
270+
if (k-- == 0) goto failed;
271+
}
272+
if (k != 0) failed:
273+
LOG_ERROR_RETURN(EINVAL, false, "unbalanced header/trailer");
274+
auto c = &text[i];
275+
*(char*)c = '\0';
276+
return true;
260277
}
261278

262279
static NodeImpl* parse_json(char* text, size_t size, int flags) {
263280
const auto kFlags = kParseNumbersAsStringsFlag | kParseBoolsAsStringFlag |
264281
kParseInsituFlag | kParseCommentsFlag | kParseTrailingCommasFlag;
265-
fix_trail(text, size, '}');
282+
if (!fix_trail({text, size}, '{', '}')) return nullptr;
266283
JHandler h(text, flags & DOC_FREE_TEXT_ON_DESTRUCTION);
267284
using Encoding = UTF8<>;
268285
GenericInsituStringStream<Encoding> s(text);
@@ -311,7 +328,7 @@ class XMLNode : public DocNode<XMLNode> {
311328
};
312329

313330
static NodeImpl* parse_xml(char* text, size_t size, int flags) {
314-
fix_trail(text, size, '>');
331+
if (!fix_trail({text, size}, '<', '>')) return nullptr;
315332
xml_document<char> doc;
316333
doc.parse<0>(text);
317334
auto root = make_unique<XMLNode>(text, flags & DOC_FREE_TEXT_ON_DESTRUCTION);

ecosystem/test/test_simple_dom.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,21 @@ TEST(simple_dom, json) {
218218
expect_eq_vals(doc["a"], {"1", "2", "3", "4"});
219219
}
220220

221+
TEST(simple_dom, fix_trail) {
222+
static char s0[] = R"({"a":"b"}})";
223+
static char s1[] = R"({"a":"b")";
224+
static char s2[] = R"({"a":"b"} )";
225+
static char s3[] = "{\"a\":\0\"b\"}";
226+
static std::pair<estring_view, bool> json[] = {
227+
{s0, false}, {s1, false}, {s2, true},
228+
{{s3, sizeof(s3) - 1}, false},
229+
};
230+
for (auto x: json) {
231+
auto doc = parse((char*)x.first.data(), x.first.size(), DOC_JSON);
232+
EXPECT_EQ(!!doc, x.second);
233+
}
234+
}
235+
221236
TEST(simple_dom, yaml0) {
222237
static char yaml0[] = "{foo: 1, bar: [2, 3], john: doe}";
223238
auto doc = parse(yaml0, sizeof(yaml0)-1, DOC_YAML);

0 commit comments

Comments
 (0)