printf: fix format string sanity check
authorRon Yorston <rmy@pobox.com>
Tue, 18 Jul 2017 08:33:22 +0000 (09:33 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 18 Jul 2017 14:00:38 +0000 (16:00 +0200)
One of the tests for printf checks for an invalid bare '%' in the
format string:

   $ busybox printf '%' a b c
   printf: %: invalid format

On x86_64 a slightly different test doesn't work correctly:

   $ busybox printf '%' d e f
   printf: invalid number 'd'
   printf: invalid number 'e'
   printf: invalid number 'f'

On other platforms the test fails randomly depending on how the
arguments are laid out in memory.

There are two places in the code where strchr is used to determine if
a character in the format string is valid.  However, strchr also returns
a valid pointer if the character being searched for is the null terminator
thus causing the code to incorrectly suppose that a valid character has
been found.

Add explicit checks for the null terminator.

Signed-off-by: Ron Yorston <rmy@pobox.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
coreutils/printf.c

index bc22e0ee7a488c47114e63a43a062a8803964269..65bb5a935ee67c01fc72e174ec002605400e6e47 100644 (file)
@@ -305,7 +305,7 @@ static char **print_formatted(char *f, char **argv, int *conv_err)
                                }
                                break;
                        }
-                       if (strchr("-+ #", *f)) {
+                       if (*f && strchr("-+ #", *f)) {
                                ++f;
                                ++direc_length;
                        }
@@ -348,7 +348,7 @@ static char **print_formatted(char *f, char **argv, int *conv_err)
                                static const char format_chars[] ALIGN1 = "diouxXfeEgGcs";
                                char *p = strchr(format_chars, *f);
                                /* needed - try "printf %" without it */
-                               if (p == NULL) {
+                               if (p == NULL || *f == '\0') {
                                        bb_error_msg("%s: invalid format", direc_start);
                                        /* causes main() to exit with error */
                                        return saved_argv - 1;