printf: protect against bogus format specifiers. Hopefully closes bug 4184

This commit is contained in:
Denis Vlasenko 2008-07-17 09:17:51 +00:00
parent 416914fc61
commit 0f683f818c
2 changed files with 19 additions and 9 deletions

View File

@ -33,7 +33,8 @@
The 'format' argument is re-used as many times as necessary The 'format' argument is re-used as many times as necessary
to convert all of the given arguments. to convert all of the given arguments.
David MacKenzie <djm@gnu.ai.mit.edu> */ David MacKenzie <djm@gnu.ai.mit.edu>
*/
// 19990508 Busy Boxed! Dave Cinege // 19990508 Busy Boxed! Dave Cinege
@ -251,10 +252,12 @@ static char **print_formatted(char *f, char **argv)
++f; ++f;
++direc_length; ++direc_length;
} }
/* /* needed - try "printf %" without it */
if (!strchr ("diouxXfeEgGcs", *f)) if (!strchr("diouxXfeEgGcs", *f)) {
fprintf(stderr, "%%%c: invalid directive", *f); bb_error_msg("invalid directive '%s'", direc_start);
*/ /* causes main() to exit with error */
return saved_argv - 1;
}
++direc_length; ++direc_length;
if (*argv) { if (*argv) {
print_direc(direc_start, direc_length, field_width, print_direc(direc_start, direc_length, field_width,
@ -285,7 +288,8 @@ int printf_main(int argc UNUSED_PARAM, char **argv)
char **argv2; char **argv2;
/* We must check that stdout is not closed. /* We must check that stdout is not closed.
* The reason for this is highly non-obvious. printf_main is used from shell. * The reason for this is highly non-obvious.
* printf_main is used from shell.
* Shell must correctly handle 'printf "%s" foo' * Shell must correctly handle 'printf "%s" foo'
* if stdout is closed. With stdio, output gets shoveled into * if stdout is closed. With stdio, output gets shoveled into
* stdout buffer, and even fflush cannot clear it out. It seems that * stdout buffer, and even fflush cannot clear it out. It seems that
@ -298,7 +302,7 @@ int printf_main(int argc UNUSED_PARAM, char **argv)
/* bash builtin errors out on "printf '-%s-\n' foo", /* bash builtin errors out on "printf '-%s-\n' foo",
* coreutils-6.9 works. Both work with "printf -- '-%s-\n' foo". * coreutils-6.9 works. Both work with "printf -- '-%s-\n' foo".
* We will mimic coreutils. */ * We will mimic coreutils. */
if (argv[1] && argv[1][0] == '-' && argv[1][1] == '-' && argv[1][2] == '\0') if (argv[1] && argv[1][0] == '-' && argv[1][1] == '-' && !argv[1][2])
argv++; argv++;
if (!argv[1]) if (!argv[1])
bb_show_usage(); bb_show_usage();
@ -309,12 +313,12 @@ int printf_main(int argc UNUSED_PARAM, char **argv)
do { do {
argv = argv2; argv = argv2;
argv2 = print_formatted(format, argv); argv2 = print_formatted(format, argv);
} while (argv2 != argv && *argv2); } while (argv2 > argv && *argv2);
/* coreutils compat (bash doesn't do this): /* coreutils compat (bash doesn't do this):
if (*argv) if (*argv)
fprintf(stderr, "excess args ignored"); fprintf(stderr, "excess args ignored");
*/ */
return EXIT_SUCCESS; return (argv2 < argv); /* if true, print_formatted errored out */
} }

View File

@ -24,4 +24,10 @@ testing "printf repeatedly use pattern for each argv" \
"foo\n$HOME\n" \ "foo\n$HOME\n" \
"" "" "" ""
# Why ()s are necessary I have no idea...
testing "printf aborts on bare %" \
"(${bb}printf '%' a b c) 2>&1; echo \$?" \
"printf: invalid directive '%'\n""1\n" \
"" ""
exit $FAILCOUNT exit $FAILCOUNT