Skip to content

Commit

Permalink
src/common.c: Fix heap buffer overflows when writing strings in binhe…
Browse files Browse the repository at this point in the history
…ader

Fixes the following problems:
 1. Case 's' only enlarges the buffer by 16 bytes instead of size bytes.
 2. psf_binheader_writef() enlarges the header buffer (if needed) prior to the
    big switch statement by an amount (16 bytes) which is enough for all cases
    where only a single value gets added. Cases 's', 'S', 'p' however
    additionally write an arbitrary length block of data and again enlarge the
    buffer to the required amount. However, the required space calculation does
    not take into account the size of the length field which gets output before
    the data.
 3. Buffer size requirement calculation in case 'S' does not account for the
    padding byte ("size += (size & 1) ;" happens after the calculation which
    uses "size").
 4. Case 'S' can overrun the header buffer by 1 byte when no padding is
    involved
    ("memcpy (&(psf->header.ptr [psf->header.indx]), strptr, size + 1) ;" while
    the buffer is only guaranteed to have "size" space available).
 5. "psf->header.ptr [psf->header.indx] = 0 ;" in case 'S' always writes 1 byte
    beyond the space which is guaranteed to be allocated in the header buffer.
 6. Case 's' can overrun the provided source string by 1 byte if padding is
    involved ("memcpy (&(psf->header.ptr [psf->header.indx]), strptr, size) ;"
    where "size" is "strlen (strptr) + 1" (which includes the 0 terminator,
    plus optionally another 1 which is padding and not guaranteed to be
    readable via the source string pointer).

Closes: libsndfile#292
  • Loading branch information
manxorist committed Jun 14, 2017
1 parent c368828 commit b6a9d7e
Showing 1 changed file with 7 additions and 8 deletions.
15 changes: 7 additions & 8 deletions src/common.c
Expand Up @@ -681,16 +681,16 @@ psf_binheader_writef (SF_PRIVATE *psf, const char *format, ...)
/* Write a C string (guaranteed to have a zero terminator). */
strptr = va_arg (argptr, char *) ;
size = strlen (strptr) + 1 ;
size += (size & 1) ;

if (psf->header.indx + (sf_count_t) size >= psf->header.len && psf_bump_header_allocation (psf, 16))
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)))
return count ;

if (psf->rwf_endian == SF_ENDIAN_BIG)
header_put_be_int (psf, size) ;
header_put_be_int (psf, size + (size & 1)) ;
else
header_put_le_int (psf, size) ;
header_put_le_int (psf, size + (size & 1)) ;
memcpy (&(psf->header.ptr [psf->header.indx]), strptr, size) ;
size += (size & 1) ;
psf->header.indx += size ;
psf->header.ptr [psf->header.indx - 1] = 0 ;
count += 4 + size ;
Expand All @@ -703,16 +703,15 @@ psf_binheader_writef (SF_PRIVATE *psf, const char *format, ...)
*/
strptr = va_arg (argptr, char *) ;
size = strlen (strptr) ;
if (psf->header.indx + (sf_count_t) size > psf->header.len && psf_bump_header_allocation (psf, size))
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)))
return count ;
if (psf->rwf_endian == SF_ENDIAN_BIG)
header_put_be_int (psf, size) ;
else
header_put_le_int (psf, size) ;
memcpy (&(psf->header.ptr [psf->header.indx]), strptr, size + 1) ;
memcpy (&(psf->header.ptr [psf->header.indx]), strptr, size + (size & 1)) ;
size += (size & 1) ;
psf->header.indx += size ;
psf->header.ptr [psf->header.indx] = 0 ;
count += 4 + size ;
break ;

Expand All @@ -724,7 +723,7 @@ psf_binheader_writef (SF_PRIVATE *psf, const char *format, ...)
size = (size & 1) ? size : size + 1 ;
size = (size > 254) ? 254 : size ;

if (psf->header.indx + (sf_count_t) size > psf->header.len && psf_bump_header_allocation (psf, size))
if (psf->header.indx + 1 + (sf_count_t) size > psf->header.len && psf_bump_header_allocation (psf, 1 + size))
return count ;

header_put_byte (psf, size) ;
Expand Down

0 comments on commit b6a9d7e

Please sign in to comment.