From 9dd87afbf1a2f7991a733609bbda6f26cadaa6ce Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Fri, 2 Sep 2016 15:59:34 +0200 Subject: [PATCH] vfscanf: Avoid multiple reads of multi-byte character width This avoids a race condition if the process-global locale is changed while vfscanf is running. MB_LEN_MAX is always larger than MB_CUR_MAX, so we might realloc earlier than necessary (but even MB_CUR_MAX could be larger than the minimum required space). The existing length was a bit questionable because str + MB_LEN_MAX might point past the end of the buffer. --- ChangeLog | 6 ++++++ stdio-common/vfscanf.c | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index ef10db070b..8559e0dfda 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2016-09-02 Florian Weimer + + * stdio-common/vfscanf.c (_IO_vfwscanf): Use MB_LEN_MAX instead of + MB_CUR_MAX to avoid race condition. Avoid pointer arithmetic + outside of allocated array. + 2016-09-02 Florian Weimer * stdio-common/vfprintf.c (process_string_arg): Use MB_LEN_MAX diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c index 8cd59557a6..fe3677ba10 100644 --- a/stdio-common/vfscanf.c +++ b/stdio-common/vfscanf.c @@ -757,7 +757,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, size_t n; if (!(flags & SUPPRESS) && (flags & POSIX_MALLOC) - && str + MB_CUR_MAX >= *strptr + strsize) + && *strptr + strsize - str <= MB_LEN_MAX) { /* We have to enlarge the buffer if the `m' flag was given. */ @@ -769,7 +769,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, { /* Can't allocate that much. Last-ditch effort. */ newstr = (char *) realloc (*strptr, - strleng + MB_CUR_MAX); + strleng + MB_LEN_MAX); if (newstr == NULL) { /* c can't have `a' flag, only `m'. */ @@ -780,7 +780,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, { *strptr = newstr; str = newstr + strleng; - strsize = strleng + MB_CUR_MAX; + strsize = strleng + MB_LEN_MAX; } } else @@ -1048,7 +1048,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, size_t n; if (!(flags & SUPPRESS) && (flags & MALLOC) - && str + MB_CUR_MAX >= *strptr + strsize) + && *strptr + strsize - str <= MB_LEN_MAX) { /* We have to enlarge the buffer if the `a' or `m' flag was given. */ @@ -1061,7 +1061,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, /* Can't allocate that much. Last-ditch effort. */ newstr = (char *) realloc (*strptr, - strleng + MB_CUR_MAX); + strleng + MB_LEN_MAX); if (newstr == NULL) { if (flags & POSIX_MALLOC) @@ -1081,7 +1081,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, { *strptr = newstr; str = newstr + strleng; - strsize = strleng + MB_CUR_MAX; + strsize = strleng + MB_LEN_MAX; } } else @@ -1097,7 +1097,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, if (__glibc_unlikely (n == (size_t) -1)) encode_error (); - assert (n <= MB_CUR_MAX); + assert (n <= MB_LEN_MAX); str += n; } #else @@ -2675,7 +2675,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, /* Possibly correct character, just not enough input. */ ++cnt; - assert (cnt < MB_CUR_MAX); + assert (cnt < MB_LEN_MAX); continue; } cnt = 0; @@ -2827,7 +2827,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, if (!(flags & SUPPRESS)) { if ((flags & MALLOC) - && str + MB_CUR_MAX >= *strptr + strsize) + && *strptr + strsize - str <= MB_LEN_MAX) { /* Enlarge the buffer. */ size_t strleng = str - *strptr; @@ -2839,7 +2839,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, /* Can't allocate that much. Last-ditch effort. */ newstr = (char *) realloc (*strptr, - strleng + MB_CUR_MAX); + strleng + MB_LEN_MAX); if (newstr == NULL) { if (flags & POSIX_MALLOC) @@ -2859,7 +2859,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, { *strptr = newstr; str = newstr + strleng; - strsize = strleng + MB_CUR_MAX; + strsize = strleng + MB_LEN_MAX; } } else @@ -2875,7 +2875,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, if (__glibc_unlikely (n == (size_t) -1)) encode_error (); - assert (n <= MB_CUR_MAX); + assert (n <= MB_LEN_MAX); str += n; } while (--width > 0 && inchar () != WEOF);