From owner-svn-src-head@freebsd.org Mon Oct 31 18:38:59 2016 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id CCE26C27490; Mon, 31 Oct 2016 18:38:59 +0000 (UTC) (envelope-from br@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 917251304; Mon, 31 Oct 2016 18:38:59 +0000 (UTC) (envelope-from br@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u9VIcw86023693; Mon, 31 Oct 2016 18:38:58 GMT (envelope-from br@FreeBSD.org) Received: (from br@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u9VIcwii023690; Mon, 31 Oct 2016 18:38:58 GMT (envelope-from br@FreeBSD.org) Message-Id: <201610311838.u9VIcwii023690@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: br set sender to br@FreeBSD.org using -f From: Ruslan Bukin Date: Mon, 31 Oct 2016 18:38:58 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r308145 - in head: contrib/netbsd-tests/lib/libc/stdio include lib/libc/stdio X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 31 Oct 2016 18:38:59 -0000 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 +#include #include #include #include @@ -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 *)