printf: protect against bogus format specifiers. Hopefully closes bug 4184
This commit is contained in:
parent
416914fc61
commit
0f683f818c
@ -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 */
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user