e6061c
From cf7a8182c2642c50f1cf90dddea9ce96a8bad2e8 Mon Sep 17 00:00:00 2001
e6061c
From: =?UTF-8?q?J=C3=B6rn=20Heusipp?= <osmanx@problemloesungsmaschine.de>
e6061c
Date: Wed, 14 Jun 2017 12:25:40 +0200
e6061c
Subject: [PATCH] src/common.c: Fix heap buffer overflows when writing strings
e6061c
 in binheader
e6061c
e6061c
Fixes the following problems:
e6061c
 1. Case 's' only enlarges the buffer by 16 bytes instead of size bytes.
e6061c
 2. psf_binheader_writef() enlarges the header buffer (if needed) prior to the
e6061c
    big switch statement by an amount (16 bytes) which is enough for all cases
e6061c
    where only a single value gets added. Cases 's', 'S', 'p' however
e6061c
    additionally write an arbitrary length block of data and again enlarge the
e6061c
    buffer to the required amount. However, the required space calculation does
e6061c
    not take into account the size of the length field which gets output before
e6061c
    the data.
e6061c
 3. Buffer size requirement calculation in case 'S' does not account for the
e6061c
    padding byte ("size += (size & 1) ;" happens after the calculation which
e6061c
    uses "size").
e6061c
 4. Case 'S' can overrun the header buffer by 1 byte when no padding is
e6061c
    involved
e6061c
    ("memcpy (&(psf->header.ptr [psf->header.indx]), strptr, size + 1) ;" while
e6061c
    the buffer is only guaranteed to have "size" space available).
e6061c
 5. "psf->header.ptr [psf->header.indx] = 0 ;" in case 'S' always writes 1 byte
e6061c
    beyond the space which is guaranteed to be allocated in the header buffer.
e6061c
 6. Case 's' can overrun the provided source string by 1 byte if padding is
e6061c
    involved ("memcpy (&(psf->header.ptr [psf->header.indx]), strptr, size) ;"
e6061c
    where "size" is "strlen (strptr) + 1" (which includes the 0 terminator,
e6061c
    plus optionally another 1 which is padding and not guaranteed to be
e6061c
    readable via the source string pointer).
e6061c
e6061c
Closes: https://github.com/erikd/libsndfile/issues/292
e6061c
---
e6061c
 src/common.c | 15 +++++++--------
e6061c
 1 file changed, 7 insertions(+), 8 deletions(-)
e6061c
e6061c
diff --git a/src/common.c b/src/common.c
e6061c
index 1a6204ca..6b2a2ee9 100644
e6061c
--- a/src/common.c
e6061c
+++ b/src/common.c
e6061c
@@ -681,16 +681,16 @@ psf_binheader_writef (SF_PRIVATE *psf, const char *format, ...)
e6061c
 					/* Write a C string (guaranteed to have a zero terminator). */
e6061c
 					strptr = va_arg (argptr, char *) ;
e6061c
 					size = strlen (strptr) + 1 ;
e6061c
-					size += (size & 1) ;
e6061c
 
e6061c
-					if (psf->header.indx + (sf_count_t) size >= psf->header.len && psf_bump_header_allocation (psf, 16))
e6061c
+					if (psf->header.indx + 4 + (sf_count_t) size + (sf_count_t) (size & 1) > psf->header.len && psf_bump_header_allocation (psf, 4 + size + (size & 1)))
e6061c
 						return count ;
e6061c
 
e6061c
 					if (psf->rwf_endian == SF_ENDIAN_BIG)
e6061c
-						header_put_be_int (psf, size) ;
e6061c
+						header_put_be_int (psf, size + (size & 1)) ;
e6061c
 					else
e6061c
-						header_put_le_int (psf, size) ;
e6061c
+						header_put_le_int (psf, size + (size & 1)) ;
e6061c
 					memcpy (&(psf->header.ptr [psf->header.indx]), strptr, size) ;
e6061c
+					size += (size & 1) ;
e6061c
 					psf->header.indx += size ;
e6061c
 					psf->header.ptr [psf->header.indx - 1] = 0 ;
e6061c
 					count += 4 + size ;
e6061c
@@ -703,16 +703,15 @@ psf_binheader_writef (SF_PRIVATE *psf, const char *format, ...)
e6061c
 					*/
e6061c
 					strptr = va_arg (argptr, char *) ;
e6061c
 					size = strlen (strptr) ;
e6061c
-					if (psf->header.indx + (sf_count_t) size > psf->header.len && psf_bump_header_allocation (psf, size))
e6061c
+					if (psf->header.indx + 4 + (sf_count_t) size + (sf_count_t) (size & 1) > psf->header.len && psf_bump_header_allocation (psf, 4 + size + (size & 1)))
e6061c
 						return count ;
e6061c
 					if (psf->rwf_endian == SF_ENDIAN_BIG)
e6061c
 						header_put_be_int (psf, size) ;
e6061c
 					else
e6061c
 						header_put_le_int (psf, size) ;
e6061c
-					memcpy (&(psf->header.ptr [psf->header.indx]), strptr, size + 1) ;
e6061c
+					memcpy (&(psf->header.ptr [psf->header.indx]), strptr, size + (size & 1)) ;
e6061c
 					size += (size & 1) ;
e6061c
 					psf->header.indx += size ;
e6061c
-					psf->header.ptr [psf->header.indx] = 0 ;
e6061c
 					count += 4 + size ;
e6061c
 					break ;
e6061c
 
e6061c
@@ -724,7 +723,7 @@ psf_binheader_writef (SF_PRIVATE *psf, const char *format, ...)
e6061c
 					size = (size & 1) ? size : size + 1 ;
e6061c
 					size = (size > 254) ? 254 : size ;
e6061c
 
e6061c
-					if (psf->header.indx + (sf_count_t) size > psf->header.len && psf_bump_header_allocation (psf, size))
e6061c
+					if (psf->header.indx + 1 + (sf_count_t) size > psf->header.len && psf_bump_header_allocation (psf, 1 + size))
e6061c
 						return count ;
e6061c
 
e6061c
 					header_put_byte (psf, size) ;