find: Fix buffer overflow in token stack

The stack is used for two purposes: storing operators for the
shunting yard algorithm, and storing primitives when arranging the
operators into a tree. The number of operators is bounded by the
number of arguments, since we only insert at most one extra operator
per primitive. However, the number of primitives may be as high as
argc + 1, since -print may have been added implicitly.

This can triggered with an empty expression, `find .`, since in
this case argc is 0, but we still try to store -print in the stack.

Detected with musl's WIP allocator, mallocng-draft.
This commit is contained in:
Michael Forney 2020-05-12 19:38:04 -07:00
parent 6ff6bb57ce
commit e6b6f34506

5
find.c
View File

@ -785,12 +785,10 @@ parse(int argc, char **argv)
size_t ntok = 0; size_t ntok = 0;
struct tok and = { .u.oinfo = find_op("-a"), .type = AND }; struct tok and = { .u.oinfo = find_op("-a"), .type = AND };
infix = ereallocarray(NULL, 2 * argc + 1, sizeof(*infix));
stack = ereallocarray(NULL, argc, sizeof(*stack));
gflags.print = 1; gflags.print = 1;
/* convert argv to infix expression of tok, inserting in *tok */ /* convert argv to infix expression of tok, inserting in *tok */
infix = ereallocarray(NULL, 2 * argc + 1, sizeof(*infix));
for (arg = argv, tok = infix; *arg; arg++, tok++) { for (arg = argv, tok = infix; *arg; arg++, tok++) {
pri = find_primary(*arg); pri = find_primary(*arg);
@ -833,6 +831,7 @@ parse(int argc, char **argv)
* read from infix, resulting rpn ends up in rpn, next position in rpn is out * read from infix, resulting rpn ends up in rpn, next position in rpn is out
* push operators onto stack, next position in stack is top */ * push operators onto stack, next position in stack is top */
rpn = ereallocarray(NULL, ntok + gflags.print, sizeof(*rpn)); rpn = ereallocarray(NULL, ntok + gflags.print, sizeof(*rpn));
stack = ereallocarray(NULL, argc + gflags.print, sizeof(*stack));
for (tok = infix, out = rpn, top = stack; tok->type != END; tok++) { for (tok = infix, out = rpn, top = stack; tok->type != END; tok++) {
switch (tok->type) { switch (tok->type) {
case PRIM: *out++ = *tok; break; case PRIM: *out++ = *tok; break;