00db10
commit 0262507918cfad7223bf81b8f162b7adc7a2af01
00db10
Author: Florian Weimer <fweimer@redhat.com>
00db10
Date:   Fri Jun 1 10:43:06 2018 +0200
00db10
00db10
    libio: Avoid _allocate_buffer, _free_buffer function pointers [BZ #23236]
00db10
    
00db10
    These unmangled function pointers reside on the heap and could
00db10
    be targeted by exploit writers, effectively bypassing libio vtable
00db10
    validation.  Instead, we ignore these pointers and always call
00db10
    malloc or free.
00db10
    
00db10
    In theory, this is a backwards-incompatible change, but using the
00db10
    global heap instead of the user-supplied callback functions should
00db10
    have little application impact.  (The old libstdc++ implementation
00db10
    exposed this functionality via a public, undocumented constructor
00db10
    in its strstreambuf class.)
00db10
    
00db10
    (cherry picked from commit 4e8a6346cd3da2d88bbad745a1769260d36f2783)
00db10
00db10
Backported from the upstream release/2.27/master branch.
00db10
00db10
diff --git a/debug/vasprintf_chk.c b/debug/vasprintf_chk.c
00db10
index a8ca32bad57b4d13..113354749ccf8d9a 100644
00db10
--- a/debug/vasprintf_chk.c
00db10
+++ b/debug/vasprintf_chk.c
00db10
@@ -55,8 +55,8 @@ __vasprintf_chk (char **result_ptr, int flags, const char *format,
00db10
   _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
00db10
   _IO_str_init_static_internal (&sf, string, init_string_size, string);
00db10
   sf._sbf._f._flags &= ~_IO_USER_BUF;
00db10
-  sf._s._allocate_buffer = (_IO_alloc_type) malloc;
00db10
-  sf._s._free_buffer = (_IO_free_type) free;
00db10
+  sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc;
00db10
+  sf._s._free_buffer_unused = (_IO_free_type) free;
00db10
 
00db10
   /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
00db10
      can only come from read-only format strings.  */
00db10
diff --git a/libio/memstream.c b/libio/memstream.c
00db10
index e18a7756b297c9f4..9a51331e525c3468 100644
00db10
--- a/libio/memstream.c
00db10
+++ b/libio/memstream.c
00db10
@@ -87,8 +87,8 @@ open_memstream (char **bufloc, _IO_size_t *sizeloc)
00db10
   _IO_JUMPS ((struct _IO_FILE_plus *) &new_f->fp._sf._sbf) = &_IO_mem_jumps;
00db10
   _IO_str_init_static_internal (&new_f->fp._sf, buf, _IO_BUFSIZ, buf);
00db10
   new_f->fp._sf._sbf._f._flags &= ~_IO_USER_BUF;
00db10
-  new_f->fp._sf._s._allocate_buffer = (_IO_alloc_type) malloc;
00db10
-  new_f->fp._sf._s._free_buffer = (_IO_free_type) free;
00db10
+  new_f->fp._sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc;
00db10
+  new_f->fp._sf._s._free_buffer_unused = (_IO_free_type) free;
00db10
 
00db10
   new_f->fp.bufloc = bufloc;
00db10
   new_f->fp.sizeloc = sizeloc;
00db10
diff --git a/libio/strfile.h b/libio/strfile.h
00db10
index 4ea7548f9fa92638..9cd8e7c466616b52 100644
00db10
--- a/libio/strfile.h
00db10
+++ b/libio/strfile.h
00db10
@@ -34,8 +34,11 @@ typedef void (*_IO_free_type) (void*);
00db10
 
00db10
 struct _IO_str_fields
00db10
 {
00db10
-  _IO_alloc_type _allocate_buffer;
00db10
-  _IO_free_type _free_buffer;
00db10
+  /* These members are preserved for ABI compatibility.  The glibc
00db10
+     implementation always calls malloc/free for user buffers if
00db10
+     _IO_USER_BUF or _IO_FLAGS2_USER_WBUF are not set.  */
00db10
+  _IO_alloc_type _allocate_buffer_unused;
00db10
+  _IO_free_type _free_buffer_unused;
00db10
 };
00db10
 
00db10
 /* This is needed for the Irix6 N32 ABI, which has a 64 bit off_t type,
00db10
@@ -55,10 +58,6 @@ typedef struct _IO_strfile_
00db10
   struct _IO_str_fields _s;
00db10
 } _IO_strfile;
00db10
 
00db10
-/* dynamic: set when the array object is allocated (or reallocated)  as
00db10
-   necessary to hold a character sequence that can change in length. */
00db10
-#define _IO_STR_DYNAMIC(FP) ((FP)->_s._allocate_buffer != (_IO_alloc_type)0)
00db10
-
00db10
 /* frozen: set when the program has requested that the array object not
00db10
    be altered, reallocated, or freed. */
00db10
 #define _IO_STR_FROZEN(FP) ((FP)->_f._IO_file_flags & _IO_USER_BUF)
00db10
diff --git a/libio/strops.c b/libio/strops.c
00db10
index fdd113a60811e593..129a0f6aeca818fd 100644
00db10
--- a/libio/strops.c
00db10
+++ b/libio/strops.c
00db10
@@ -61,7 +61,7 @@ _IO_str_init_static_internal (_IO_strfile *sf, char *ptr, _IO_size_t size,
00db10
       fp->_IO_read_end = end;
00db10
     }
00db10
   /* A null _allocate_buffer function flags the strfile as being static. */
00db10
-  sf->_s._allocate_buffer = (_IO_alloc_type) 0;
00db10
+  sf->_s._allocate_buffer_unused = (_IO_alloc_type) 0;
00db10
 }
00db10
 
00db10
 void
00db10
@@ -103,8 +103,7 @@ _IO_str_overflow (_IO_FILE *fp, int c)
00db10
 	  _IO_size_t new_size = 2 * old_blen + 100;
00db10
 	  if (new_size < old_blen)
00db10
 	    return EOF;
00db10
-	  new_buf
00db10
-	    = (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size);
00db10
+	  new_buf = malloc (new_size);
00db10
 	  if (new_buf == NULL)
00db10
 	    {
00db10
 	      /*	  __ferror(fp) = 1; */
00db10
@@ -113,7 +112,7 @@ _IO_str_overflow (_IO_FILE *fp, int c)
00db10
 	  if (old_buf)
00db10
 	    {
00db10
 	      memcpy (new_buf, old_buf, old_blen);
00db10
-	      (*((_IO_strfile *) fp)->_s._free_buffer) (old_buf);
00db10
+	      free (old_buf);
00db10
 	      /* Make sure _IO_setb won't try to delete _IO_buf_base. */
00db10
 	      fp->_IO_buf_base = NULL;
00db10
 	    }
00db10
@@ -182,15 +181,14 @@ enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading)
00db10
 
00db10
   _IO_size_t newsize = offset + 100;
00db10
   char *oldbuf = fp->_IO_buf_base;
00db10
-  char *newbuf
00db10
-    = (char *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (newsize);
00db10
+  char *newbuf = malloc (newsize);
00db10
   if (newbuf == NULL)
00db10
     return 1;
00db10
 
00db10
   if (oldbuf != NULL)
00db10
     {
00db10
       memcpy (newbuf, oldbuf, _IO_blen (fp));
00db10
-      (*((_IO_strfile *) fp)->_s._free_buffer) (oldbuf);
00db10
+      free (oldbuf);
00db10
       /* Make sure _IO_setb won't try to delete
00db10
 	 _IO_buf_base. */
00db10
       fp->_IO_buf_base = NULL;
00db10
@@ -317,7 +315,7 @@ void
00db10
 _IO_str_finish (_IO_FILE *fp, int dummy)
00db10
 {
00db10
   if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
00db10
-    (((_IO_strfile *) fp)->_s._free_buffer) (fp->_IO_buf_base);
00db10
+    free (fp->_IO_buf_base);
00db10
   fp->_IO_buf_base = NULL;
00db10
 
00db10
   _IO_default_finish (fp, 0);
00db10
diff --git a/libio/vasprintf.c b/libio/vasprintf.c
00db10
index 282c86fff0a7ae0e..867ef4fe4ca4ec56 100644
00db10
--- a/libio/vasprintf.c
00db10
+++ b/libio/vasprintf.c
00db10
@@ -54,8 +54,8 @@ _IO_vasprintf (char **result_ptr, const char *format, _IO_va_list args)
00db10
   _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
00db10
   _IO_str_init_static_internal (&sf, string, init_string_size, string);
00db10
   sf._sbf._f._flags &= ~_IO_USER_BUF;
00db10
-  sf._s._allocate_buffer = (_IO_alloc_type) malloc;
00db10
-  sf._s._free_buffer = (_IO_free_type) free;
00db10
+  sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc;
00db10
+  sf._s._free_buffer_unused = (_IO_free_type) free;
00db10
   ret = _IO_vfprintf (&sf._sbf._f, format, args);
00db10
   if (ret < 0)
00db10
     {
00db10
diff --git a/libio/wmemstream.c b/libio/wmemstream.c
00db10
index bd6d1798b1685fe9..3a9a681c80a321a7 100644
00db10
--- a/libio/wmemstream.c
00db10
+++ b/libio/wmemstream.c
00db10
@@ -90,8 +90,8 @@ open_wmemstream (wchar_t **bufloc, _IO_size_t *sizeloc)
00db10
   _IO_wstr_init_static (&new_f->fp._sf._sbf._f, buf,
00db10
 			_IO_BUFSIZ / sizeof (wchar_t), buf);
00db10
   new_f->fp._sf._sbf._f._flags2 &= ~_IO_FLAGS2_USER_WBUF;
00db10
-  new_f->fp._sf._s._allocate_buffer = (_IO_alloc_type) malloc;
00db10
-  new_f->fp._sf._s._free_buffer = (_IO_free_type) free;
00db10
+  new_f->fp._sf._s._allocate_buffer_unused = (_IO_alloc_type) malloc;
00db10
+  new_f->fp._sf._s._free_buffer_unused = (_IO_free_type) free;
00db10
 
00db10
   new_f->fp.bufloc = bufloc;
00db10
   new_f->fp.sizeloc = sizeloc;
00db10
diff --git a/libio/wstrops.c b/libio/wstrops.c
00db10
index 7a9a33ab8763b8ff..a31d0e23341b2aad 100644
00db10
--- a/libio/wstrops.c
00db10
+++ b/libio/wstrops.c
00db10
@@ -63,7 +63,7 @@ _IO_wstr_init_static (_IO_FILE *fp, wchar_t *ptr, _IO_size_t size,
00db10
       fp->_wide_data->_IO_read_end = end;
00db10
     }
00db10
   /* A null _allocate_buffer function flags the strfile as being static. */
00db10
-  (((_IO_strfile *) fp)->_s._allocate_buffer) = (_IO_alloc_type)0;
00db10
+  (((_IO_strfile *) fp)->_s._allocate_buffer_unused) = (_IO_alloc_type)0;
00db10
 }
00db10
 
00db10
 _IO_wint_t
00db10
@@ -95,9 +95,7 @@ _IO_wstr_overflow (_IO_FILE *fp, _IO_wint_t c)
00db10
 	      || __glibc_unlikely (new_size > SIZE_MAX / sizeof (wchar_t)))
00db10
 	    return EOF;
00db10
 
00db10
-	  new_buf
00db10
-	    = (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (new_size
00db10
-									* sizeof (wchar_t));
00db10
+	  new_buf = malloc (new_size * sizeof (wchar_t));
00db10
 	  if (new_buf == NULL)
00db10
 	    {
00db10
 	      /*	  __ferror(fp) = 1; */
00db10
@@ -106,7 +104,7 @@ _IO_wstr_overflow (_IO_FILE *fp, _IO_wint_t c)
00db10
 	  if (old_buf)
00db10
 	    {
00db10
 	      __wmemcpy (new_buf, old_buf, old_wblen);
00db10
-	      (*((_IO_strfile *) fp)->_s._free_buffer) (old_buf);
00db10
+	      free (old_buf);
00db10
 	      /* Make sure _IO_setb won't try to delete _IO_buf_base. */
00db10
 	      fp->_wide_data->_IO_buf_base = NULL;
00db10
 	    }
00db10
@@ -186,16 +184,14 @@ enlarge_userbuf (_IO_FILE *fp, _IO_off64_t offset, int reading)
00db10
     return 1;
00db10
 
00db10
   wchar_t *oldbuf = wd->_IO_buf_base;
00db10
-  wchar_t *newbuf
00db10
-    = (wchar_t *) (*((_IO_strfile *) fp)->_s._allocate_buffer) (newsize
00db10
-								* sizeof (wchar_t));
00db10
+  wchar_t *newbuf = malloc (newsize * sizeof (wchar_t));
00db10
   if (newbuf == NULL)
00db10
     return 1;
00db10
 
00db10
   if (oldbuf != NULL)
00db10
     {
00db10
       __wmemcpy (newbuf, oldbuf, _IO_wblen (fp));
00db10
-      (*((_IO_strfile *) fp)->_s._free_buffer) (oldbuf);
00db10
+      free (oldbuf);
00db10
       /* Make sure _IO_setb won't try to delete
00db10
 	 _IO_buf_base. */
00db10
       wd->_IO_buf_base = NULL;
00db10
@@ -326,7 +322,7 @@ void
00db10
 _IO_wstr_finish (_IO_FILE *fp, int dummy)
00db10
 {
00db10
   if (fp->_wide_data->_IO_buf_base && !(fp->_flags2 & _IO_FLAGS2_USER_WBUF))
00db10
-    (((_IO_strfile *) fp)->_s._free_buffer) (fp->_wide_data->_IO_buf_base);
00db10
+    free (fp->_wide_data->_IO_buf_base);
00db10
   fp->_wide_data->_IO_buf_base = NULL;
00db10
 
00db10
   _IO_wdefault_finish (fp, 0);