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