From 4ec860910a4ee91ed4fdf1c0a49f2dad96d595c9 Mon Sep 17 00:00:00 2001 From: Alex Stewart Date: Mon, 16 Oct 2023 12:37:47 -0400 Subject: [PATCH 12/17] common: fix int overflow in psf_binheader_readf() The psf_binheader_readf() function attempts to count and return the number of bytes traversed in the header. During this accumulation, it is possible to overflow the int-sized byte_count variable. Avoid this overflow by checking that the accumulated bytes do not exceed INT_MAX and throwing an error if they do. This implies that files with multi-gigabyte headers threaten to produce this error, but I imagine those files don't really exist - and this error is better than the undefined behavior which would have resulted previously. CVE: CVE-2022-33065 Fixes: https://github.com/libsndfile/libsndfile/issues/833 Signed-off-by: Alex Stewart Upstream-Status: Backport [import from ubuntu https://git.launchpad.net/ubuntu/+source/libsndfile/tree/debian/patches/CVE-2022-33065/CVE-2022-33065-8.patch?h=ubuntu/jammy-security Upstream commit https://github.com/libsndfile/libsndfile/commit/4ec860910a4ee91ed4fdf1c0a49f2dad96d595c9] CVE: CVE-2022-33065 Signed-off-by: Vijay Anusuri --- src/common.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) --- libsndfile-1.0.31.orig/src/common.c +++ libsndfile-1.0.31/src/common.c @@ -18,6 +18,7 @@ #include +#include #include #include #if HAVE_UNISTD_H @@ -962,6 +963,7 @@ psf_binheader_readf (SF_PRIVATE *psf, ch double *doubleptr ; char c ; int byte_count = 0, count = 0 ; + int read_bytes = 0 ; if (! format) return psf_ftell (psf) ; @@ -970,6 +972,7 @@ psf_binheader_readf (SF_PRIVATE *psf, ch while ((c = *format++)) { + read_bytes = 0 ; if (psf->header.indx + 16 >= psf->header.len && psf_bump_header_allocation (psf, 16)) return count ; @@ -986,7 +989,7 @@ psf_binheader_readf (SF_PRIVATE *psf, ch intptr = va_arg (argptr, unsigned int*) ; *intptr = 0 ; ucptr = (unsigned char*) intptr ; - byte_count += header_read (psf, ucptr, sizeof (int)) ; + read_bytes = header_read (psf, ucptr, sizeof (int)) ; *intptr = GET_MARKER (ucptr) ; break ; @@ -994,7 +997,7 @@ psf_binheader_readf (SF_PRIVATE *psf, ch intptr = va_arg (argptr, unsigned int*) ; *intptr = 0 ; ucptr = (unsigned char*) intptr ; - byte_count += header_read (psf, sixteen_bytes, sizeof (sixteen_bytes)) ; + read_bytes = header_read (psf, sixteen_bytes, sizeof (sixteen_bytes)) ; { int k ; intdata = 0 ; for (k = 0 ; k < 16 ; k++) @@ -1006,14 +1009,14 @@ psf_binheader_readf (SF_PRIVATE *psf, ch case '1' : charptr = va_arg (argptr, char*) ; *charptr = 0 ; - byte_count += header_read (psf, charptr, sizeof (char)) ; + read_bytes = header_read (psf, charptr, sizeof (char)) ; break ; case '2' : /* 2 byte value with the current endian-ness */ shortptr = va_arg (argptr, unsigned short*) ; *shortptr = 0 ; ucptr = (unsigned char*) shortptr ; - byte_count += header_read (psf, ucptr, sizeof (short)) ; + read_bytes = header_read (psf, ucptr, sizeof (short)) ; if (psf->rwf_endian == SF_ENDIAN_BIG) *shortptr = GET_BE_SHORT (ucptr) ; else @@ -1023,7 +1026,7 @@ psf_binheader_readf (SF_PRIVATE *psf, ch case '3' : /* 3 byte value with the current endian-ness */ intptr = va_arg (argptr, unsigned int*) ; *intptr = 0 ; - byte_count += header_read (psf, sixteen_bytes, 3) ; + read_bytes = header_read (psf, sixteen_bytes, 3) ; if (psf->rwf_endian == SF_ENDIAN_BIG) *intptr = GET_BE_3BYTE (sixteen_bytes) ; else @@ -1034,7 +1037,7 @@ psf_binheader_readf (SF_PRIVATE *psf, ch intptr = va_arg (argptr, unsigned int*) ; *intptr = 0 ; ucptr = (unsigned char*) intptr ; - byte_count += header_read (psf, ucptr, sizeof (int)) ; + read_bytes = header_read (psf, ucptr, sizeof (int)) ; if (psf->rwf_endian == SF_ENDIAN_BIG) *intptr = psf_get_be32 (ucptr, 0) ; else @@ -1044,7 +1047,7 @@ psf_binheader_readf (SF_PRIVATE *psf, ch case '8' : /* 8 byte value with the current endian-ness */ countptr = va_arg (argptr, sf_count_t *) ; *countptr = 0 ; - byte_count += header_read (psf, sixteen_bytes, 8) ; + read_bytes = header_read (psf, sixteen_bytes, 8) ; if (psf->rwf_endian == SF_ENDIAN_BIG) countdata = psf_get_be64 (sixteen_bytes, 0) ; else @@ -1055,7 +1058,7 @@ psf_binheader_readf (SF_PRIVATE *psf, ch case 'f' : /* Float conversion */ floatptr = va_arg (argptr, float *) ; *floatptr = 0.0 ; - byte_count += header_read (psf, floatptr, sizeof (float)) ; + read_bytes = header_read (psf, floatptr, sizeof (float)) ; if (psf->rwf_endian == SF_ENDIAN_BIG) *floatptr = float32_be_read ((unsigned char*) floatptr) ; else @@ -1065,7 +1068,7 @@ psf_binheader_readf (SF_PRIVATE *psf, ch case 'd' : /* double conversion */ doubleptr = va_arg (argptr, double *) ; *doubleptr = 0.0 ; - byte_count += header_read (psf, doubleptr, sizeof (double)) ; + read_bytes = header_read (psf, doubleptr, sizeof (double)) ; if (psf->rwf_endian == SF_ENDIAN_BIG) *doubleptr = double64_be_read ((unsigned char*) doubleptr) ; else @@ -1089,7 +1092,7 @@ psf_binheader_readf (SF_PRIVATE *psf, ch charptr = va_arg (argptr, char*) ; count = va_arg (argptr, size_t) ; memset (charptr, 0, count) ; - byte_count += header_read (psf, charptr, count) ; + read_bytes = header_read (psf, charptr, count) ; break ; case 'G' : @@ -1100,7 +1103,7 @@ psf_binheader_readf (SF_PRIVATE *psf, ch if (psf->header.indx + count >= psf->header.len && psf_bump_header_allocation (psf, count)) return 0 ; - byte_count += header_gets (psf, charptr, count) ; + read_bytes = header_gets (psf, charptr, count) ; break ; case 'z' : @@ -1124,7 +1127,7 @@ psf_binheader_readf (SF_PRIVATE *psf, ch case 'j' : /* Seek to position from current position. */ count = va_arg (argptr, size_t) ; header_seek (psf, count, SEEK_CUR) ; - byte_count += count ; + read_bytes = count ; break ; default : @@ -1132,8 +1135,17 @@ psf_binheader_readf (SF_PRIVATE *psf, ch psf->error = SFE_INTERNAL ; break ; } ; + + if (read_bytes > 0 && byte_count > (INT_MAX - read_bytes)) + { psf_log_printf (psf, "Header size exceeds INT_MAX. Aborting.", c) ; + psf->error = SFE_INTERNAL ; + break ; + } else + { byte_count += read_bytes ; } ; + } ; /*end while*/ + va_end (argptr) ; return byte_count ;