From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 28830 invoked by alias); 30 Nov 2017 10:56:18 -0000 Mailing-List: contact newlib-cvs-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: newlib-cvs-owner@sourceware.org Received: (qmail 28556 invoked by uid 9078); 30 Nov 2017 10:56:15 -0000 Date: Thu, 30 Nov 2017 10:56:00 -0000 Message-ID: <20171130105615.28553.qmail@sourceware.org> Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Corinna Vinschen To: newlib-cvs@sourceware.org Subject: [newlib-cygwin] newlib: vf[w]scanf: add validity checks X-Act-Checkin: newlib-cygwin X-Git-Author: Corinna Vinschen X-Git-Refname: refs/heads/master X-Git-Oldrev: 31f11d0572495ed16f9fbdab9fefaeb64b665a79 X-Git-Newrev: 0fd2c9bd1290c84d2160191d105147bf75629411 X-SW-Source: 2017-q4/txt/msg00042.txt.bz2 https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=0fd2c9bd1290c84d2160191d105147bf75629411 commit 0fd2c9bd1290c84d2160191d105147bf75629411 Author: Corinna Vinschen Date: Thu Nov 30 11:55:27 2017 +0100 newlib: vf[w]scanf: add validity checks POSIX requires that directive characters appear in a certain sequence: 1. '%' or '%$' 2. optional '*' 3. optional field width digits 4. optional 'm' (not yet implemented) 5. optional length modifier ('l', 'L', 'll', 'h', 'hh', 'j', 't', 'z') 6. conversion specifier ('d', 's', etc) Add a few basic validity checks to that effect, otherwise reject directive as match failure. Signed-off-by: Corinna Vinschen Diff: --- newlib/libc/stdio/vfscanf.c | 19 +++++++++++++++++++ newlib/libc/stdio/vfwscanf.c | 18 ++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/newlib/libc/stdio/vfscanf.c b/newlib/libc/stdio/vfscanf.c index a81ebd5..9d6f124 100644 --- a/newlib/libc/stdio/vfscanf.c +++ b/newlib/libc/stdio/vfscanf.c @@ -564,9 +564,14 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), continue; case '*': + if ((flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS)) + || width) + goto match_failure; flags |= SUPPRESS; goto again; case 'l': + if (flags & (CHAR | SHORT | LONG | LONGDBL)) + goto match_failure; #if defined _WANT_IO_C99_FORMATS || !defined _NO_LONGLONG if (*fmt == 'l') /* Check for 'll' = long long (SUSv3) */ { @@ -578,9 +583,13 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), flags |= LONG; goto again; case 'L': + if (flags & (CHAR | SHORT | LONG | LONGDBL)) + goto match_failure; flags |= LONGDBL; goto again; case 'h': + if (flags & (CHAR | SHORT | LONG | LONGDBL)) + goto match_failure; #ifdef _WANT_IO_C99_FORMATS if (*fmt == 'h') /* Check for 'hh' = char int (SUSv3) */ { @@ -593,12 +602,16 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), goto again; #ifdef _WANT_IO_C99_FORMATS case 'j': /* intmax_t */ + if (flags & (CHAR | SHORT | LONG | LONGDBL)) + goto match_failure; if (sizeof (intmax_t) == sizeof (long)) flags |= LONG; else flags |= LONGDBL; goto again; case 't': /* ptrdiff_t */ + if (flags & (CHAR | SHORT | LONG | LONGDBL)) + goto match_failure; if (sizeof (ptrdiff_t) < sizeof (int)) /* POSIX states ptrdiff_t is 16 or more bits, as is short. */ @@ -615,6 +628,8 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), flags |= LONGDBL; goto again; case 'z': /* size_t */ + if (flags & (CHAR | SHORT | LONG | LONGDBL)) + goto match_failure; if (sizeof (size_t) < sizeof (int)) /* POSIX states size_t is 16 or more bits, as is short. */ flags |= SHORT; @@ -641,11 +656,15 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap), case '7': case '8': case '9': + if (flags & (CHAR | SHORT | LONG | LONGDBL)) + goto match_failure; width = width * 10 + c - '0'; goto again; #ifndef _NO_POS_ARGS case '$': + if (flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS)) + goto match_failure; if (width <= MAX_POS_ARGS) { N = width - 1; diff --git a/newlib/libc/stdio/vfwscanf.c b/newlib/libc/stdio/vfwscanf.c index 0d34fb1..54bbb09 100644 --- a/newlib/libc/stdio/vfwscanf.c +++ b/newlib/libc/stdio/vfwscanf.c @@ -518,9 +518,13 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap), continue; case L'*': + if ((flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS)) + || width) flags |= SUPPRESS; goto again; case L'l': + if (flags & (CHAR | SHORT | LONG | LONGDBL)) + goto match_failure; #if defined _WANT_IO_C99_FORMATS || !defined _NO_LONGLONG if (*fmt == L'l') /* Check for 'll' = long long (SUSv3) */ { @@ -532,10 +536,14 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap), flags |= LONG; goto again; case L'L': + if (flags & (CHAR | SHORT | LONG | LONGDBL)) + goto match_failure; flags |= LONGDBL; goto again; case L'h': #ifdef _WANT_IO_C99_FORMATS + if (flags & (CHAR | SHORT | LONG | LONGDBL)) + goto match_failure; if (*fmt == 'h') /* Check for 'hh' = char int (SUSv3) */ { ++fmt; @@ -547,12 +555,16 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap), goto again; #ifdef _WANT_IO_C99_FORMATS case L'j': /* intmax_t */ + if (flags & (CHAR | SHORT | LONG | LONGDBL)) + goto match_failure; if (sizeof (intmax_t) == sizeof (long)) flags |= LONG; else flags |= LONGDBL; goto again; case L't': /* ptrdiff_t */ + if (flags & (CHAR | SHORT | LONG | LONGDBL)) + goto match_failure; if (sizeof (ptrdiff_t) < sizeof (int)) /* POSIX states ptrdiff_t is 16 or more bits, as is short. */ @@ -569,6 +581,8 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap), flags |= LONGDBL; goto again; case L'z': /* size_t */ + if (flags & (CHAR | SHORT | LONG | LONGDBL)) + goto match_failure; if (sizeof (size_t) < sizeof (int)) /* POSIX states size_t is 16 or more bits, as is short. */ flags |= SHORT; @@ -595,11 +609,15 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap), case L'7': case L'8': case L'9': + if (flags & (CHAR | SHORT | LONG | LONGDBL)) + goto match_failure; width = width * 10 + c - L'0'; goto again; #ifndef _NO_POS_ARGS case L'$': + if (flags & (CHAR | SHORT | LONG | LONGDBL | SUPPRESS)) + goto match_failure; if (width <= MAX_POS_ARGS) { N = width - 1;