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