Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion libpromises/evalfunction.c
Original file line number Diff line number Diff line change
Expand Up @@ -10246,7 +10246,10 @@ void ModuleProtocol(EvalContext *ctx, const char *command, const char *line, int
// context name once it's in the vartable. Maybe this can be relaxed.
sscanf(line + 1, "%256[^=]=", name);

if (CheckID(name))
/* A well-formed line is "%name=<json>". Without the '=' delimiter
* sscanf() leaves the whole tail in name, so strlen(name) == length-1
* and the "length - strlen(name) - 1 - 1" below underflows. */
if (CheckID(name) && line[strlen(name) + 1] == '=')
Comment on lines -10249 to +10252

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your test passes without this change

{
JsonElement *json = NULL;
Buffer *holder = BufferNewFrom(line+strlen(name)+1+1,
Expand Down
34 changes: 34 additions & 0 deletions tests/unit/evalfunction_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,47 @@ static void test_basename(void)
basename_single_testcase("//a//b///c.csv////", ".csv", "c");
}

static void test_module_protocol_percent_no_delimiter(void)
{
EvalContext *ctx = EvalContextNew();
StringSet *tags = StringSetNew();
long persistence = 0;
char context[CF_BUFSIZE] = "test";

/* Lines come from CfReadLine() on the heap, so allocate them that way:
* the out-of-bounds read past the line is then flagged by ASan/valgrind. */

/* A well-formed '%name=<json>' line still defines the container. */
char *ok = xstrdup("%good={\"k\":1}");
ModuleProtocol(ctx, "/dev/null", ok, false, context, sizeof(context),
tags, &persistence);
VarRef *good = VarRefParseFromScope("good", context);
assert_true(EvalContextVariableGet(ctx, good, NULL) != NULL);
VarRefDestroy(good);
free(ok);

/* A '%' line with no '=' delimiter must be skipped, not underflow the
* BufferNewFrom() length and read past the line buffer. */
char *bad = xstrdup("%bad");
ModuleProtocol(ctx, "/dev/null", bad, false, context, sizeof(context),
tags, &persistence);
VarRef *ref = VarRefParseFromScope("bad", context);
assert_true(EvalContextVariableGet(ctx, ref, NULL) == NULL);
VarRefDestroy(ref);
free(bad);

StringSetDestroy(tags);
EvalContextDestroy(ctx);
}

int main()
{
PRINT_TEST_BANNER();
const UnitTest tests[] = {
unit_test(test_hostinnetgroup_found),
unit_test(test_hostinnetgroup_not_found),
unit_test(test_basename),
unit_test(test_module_protocol_percent_no_delimiter),
};

return run_tests(tests);
Expand Down
Loading