Author: br
Date: Mon Oct 31 18:38:58 2016
New Revision: 308145
URL: https://svnweb.freebsd.org/changeset/base/308145

Log:
  Detect integer overflow and limit the number of positional
  arguments in the string format.
  
  Sponsored by: DARPA, AFRL
  Sponsored by: HEIF5
  Differential Revision:        https://reviews.freebsd.org/D8286

Modified:
  head/contrib/netbsd-tests/lib/libc/stdio/t_printf.c
  head/include/limits.h
  head/lib/libc/stdio/printf-pos.c

Modified: head/contrib/netbsd-tests/lib/libc/stdio/t_printf.c
==============================================================================
--- head/contrib/netbsd-tests/lib/libc/stdio/t_printf.c Mon Oct 31 18:38:50 
2016        (r308144)
+++ head/contrib/netbsd-tests/lib/libc/stdio/t_printf.c Mon Oct 31 18:38:58 
2016        (r308145)
@@ -120,12 +120,6 @@ ATF_TC_BODY(snprintf_posarg_error, tc)
 {
        char s[16], fmt[32];
 
-#ifndef __NetBSD__
-       atf_tc_expect_signal(SIGSEGV,
-           "some non-NetBSD platforms including FreeBSD don't validate "
-           "negative size; testcase blows up with SIGSEGV");
-#endif
-
        snprintf(fmt, sizeof(fmt), "%%%zu$d", SIZE_MAX / sizeof(size_t));
 
        ATF_CHECK(snprintf(s, sizeof(s), fmt, -23) == -1);

Modified: head/include/limits.h
==============================================================================
--- head/include/limits.h       Mon Oct 31 18:38:50 2016        (r308144)
+++ head/include/limits.h       Mon Oct 31 18:38:58 2016        (r308145)
@@ -120,7 +120,7 @@
 #endif
 
 #if __XSI_VISIBLE || __POSIX_VISIBLE >= 200809
-#define        NL_ARGMAX               99      /* max # of position args for 
printf */
+#define        NL_ARGMAX               65536   /* max # of position args for 
printf */
 #define        NL_MSGMAX               32767
 #define        NL_SETMAX               255
 #define        NL_TEXTMAX              2048

Modified: head/lib/libc/stdio/printf-pos.c
==============================================================================
--- head/lib/libc/stdio/printf-pos.c    Mon Oct 31 18:38:50 2016        
(r308144)
+++ head/lib/libc/stdio/printf-pos.c    Mon Oct 31 18:38:58 2016        
(r308145)
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
 #include "namespace.h"
 #include <sys/types.h>
 
+#include <limits.h>
 #include <stdarg.h>
 #include <stddef.h>
 #include <stdint.h>
@@ -55,6 +56,12 @@ __FBSDID("$FreeBSD$");
 #include "un-namespace.h"
 #include "printflocal.h"
 
+#ifdef NL_ARGMAX
+#define        MAX_POSARG      NL_ARGMAX
+#else
+#define        MAX_POSARG      65536
+#endif
+
 /*
  * Type ids for argument type table.
  */
@@ -70,9 +77,9 @@ enum typeid {
 struct typetable {
        enum typeid *table; /* table of types */
        enum typeid stattable[STATIC_ARG_TBL_SIZE];
-       int tablesize;          /* current size of type table */
-       int tablemax;           /* largest used index in table */
-       int nextarg;            /* 1-based argument index */
+       u_int tablesize;        /* current size of type table */
+       u_int tablemax;         /* largest used index in table */
+       u_int nextarg;          /* 1-based argument index */
 };
 
 static int     __grow_type_table(struct typetable *);
@@ -84,7 +91,7 @@ static void   build_arg_table (struct type
 static inline void
 inittypes(struct typetable *types)
 {
-       int n;
+       u_int n;
 
        types->table = types->stattable;
        types->tablesize = STATIC_ARG_TBL_SIZE;
@@ -185,7 +192,7 @@ static inline int
 addaster(struct typetable *types, char **fmtp)
 {
        char *cp;
-       int n2;
+       u_int n2;
 
        n2 = 0;
        cp = *fmtp;
@@ -194,7 +201,7 @@ addaster(struct typetable *types, char *
                cp++;
        }
        if (*cp == '$') {
-               int hold = types->nextarg;
+               u_int hold = types->nextarg;
                types->nextarg = n2;
                if (addtype(types, T_INT))
                        return (-1);
@@ -211,7 +218,7 @@ static inline int
 addwaster(struct typetable *types, wchar_t **fmtp)
 {
        wchar_t *cp;
-       int n2;
+       u_int n2;
 
        n2 = 0;
        cp = *fmtp;
@@ -220,7 +227,7 @@ addwaster(struct typetable *types, wchar
                cp++;
        }
        if (*cp == '$') {
-               int hold = types->nextarg;
+               u_int hold = types->nextarg;
                types->nextarg = n2;
                if (addtype(types, T_INT))
                        return (-1);
@@ -245,7 +252,7 @@ __find_arguments (const char *fmt0, va_l
 {
        char *fmt;              /* format string */
        int ch;                 /* character from fmt */
-       int n;                  /* handy integer (short term usage) */
+       u_int n;                /* handy integer (short term usage) */
        int error;
        int flags;              /* flags as above */
        struct typetable types; /* table of types */
@@ -296,6 +303,11 @@ reswitch:  switch (ch) {
                        n = 0;
                        do {
                                n = 10 * n + to_digit(ch);
+                               /* Detect overflow */
+                               if (n > MAX_POSARG) {
+                                       error = -1;
+                                       goto error;
+                               }
                                ch = *fmt++;
                        } while (is_digit(ch));
                        if (ch == '$') {
@@ -433,7 +445,7 @@ __find_warguments (const wchar_t *fmt0, 
 {
        wchar_t *fmt;           /* format string */
        wchar_t ch;             /* character from fmt */
-       int n;                  /* handy integer (short term usage) */
+       u_int n;                /* handy integer (short term usage) */
        int error;
        int flags;              /* flags as above */
        struct typetable types; /* table of types */
@@ -484,6 +496,11 @@ reswitch:  switch (ch) {
                        n = 0;
                        do {
                                n = 10 * n + to_digit(ch);
+                               /* Detect overflow */
+                               if (n > MAX_POSARG) {
+                                       error = -1;
+                                       goto error;
+                               }
                                ch = *fmt++;
                        } while (is_digit(ch));
                        if (ch == '$') {
@@ -624,7 +641,11 @@ __grow_type_table(struct typetable *type
        enum typeid *const oldtable = types->table;
        const int oldsize = types->tablesize;
        enum typeid *newtable;
-       int n, newsize = oldsize * 2;
+       u_int n, newsize = oldsize * 2;
+
+       /* Detect overflow */
+       if (types->nextarg > NL_ARGMAX)
+               return (-1);
 
        if (newsize < types->nextarg + 1)
                newsize = types->nextarg + 1;
@@ -653,7 +674,7 @@ __grow_type_table(struct typetable *type
 static void
 build_arg_table(struct typetable *types, va_list ap, union arg **argtable)
 {
-       int n;
+       u_int n;
 
        if (types->tablemax >= STATIC_ARG_TBL_SIZE) {
                *argtable = (union arg *)
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to