| From c7ce5b0ebeeb58934825077d1324960aa0747718 Mon Sep 17 00:00:00 2001 |
| From: Alex Stewart <alex.stewart@ni.com> |
| Date: Tue, 10 Oct 2023 16:10:34 -0400 |
| Subject: [PATCH] mat4/mat5: fix int overflow in dataend calculation |
| |
| The clang sanitizer warns of a possible signed integer overflow when |
| calculating the `dataend` value in `mat4_read_header()`. |
| |
| ``` |
| src/mat4.c:323:41: runtime error: signed integer overflow: 205 * -100663296 cannot be represented in type 'int' |
| SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior src/mat4.c:323:41 in |
| src/mat4.c:323:48: runtime error: signed integer overflow: 838860800 * 4 cannot be represented in type 'int' |
| SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior src/mat4.c:323:48 in |
| ``` |
| |
| Cast the offending `rows` and `cols` ints to `sf_count_t` (the type of |
| `dataend` before performing the calculation, to avoid the issue. |
| |
| CVE: CVE-2022-33065 |
| Fixes: https://github.com/libsndfile/libsndfile/issues/789 |
| Fixes: https://github.com/libsndfile/libsndfile/issues/833 |
| |
| Upstream-Status: Backport [9a829113c88a51e57c1e46473e90609e4b7df151] |
| |
| Signed-off-by: Alex Stewart <alex.stewart@ni.com> |
| --- |
| src/mat4.c | 2 +- |
| 1 file changed, 1 insertion(+), 1 deletion(-) |
| |
| diff --git a/src/mat4.c b/src/mat4.c |
| index 0b1b414b..575683ba 100644 |
| --- a/src/mat4.c |
| +++ b/src/mat4.c |
| @@ -320,7 +320,7 @@ mat4_read_header (SF_PRIVATE *psf) |
| psf->filelength - psf->dataoffset, psf->sf.channels * psf->sf.frames * psf->bytewidth) ; |
| } |
| else if ((psf->filelength - psf->dataoffset) > psf->sf.channels * psf->sf.frames * psf->bytewidth) |
| - psf->dataend = psf->dataoffset + rows * cols * psf->bytewidth ; |
| + psf->dataend = psf->dataoffset + (sf_count_t) rows * (sf_count_t) cols * psf->bytewidth ; |
| |
| psf->datalength = psf->filelength - psf->dataoffset - psf->dataend ; |
| |
| From 842303f984b2081481e74cb84a9a24ecbe3dec1a Mon Sep 17 00:00:00 2001 |
| From: Alex Stewart <alex.stewart@ni.com> |
| Date: Wed, 11 Oct 2023 16:36:02 -0400 |
| Subject: [PATCH] au: avoid int overflow while calculating data_end |
| |
| At several points in au_read_header(), we calculate the functional end |
| of the data segment by adding the (int)au_fmt.dataoffset and the |
| (int)au_fmt.datasize. This can overflow the implicit int_32 return value |
| and cause undefined behavior. |
| |
| Instead, precalculate the value and assign it to a 64-bit |
| (sf_count_t)data_end variable. |
| |
| CVE: CVE-2022-33065 |
| Fixes: https://github.com/libsndfile/libsndfile/issues/833 |
| |
| Signed-off-by: Alex Stewart <alex.stewart@ni.com> |
| --- |
| src/au.c | 10 ++++++---- |
| 1 file changed, 6 insertions(+), 4 deletions(-) |
| |
| diff --git a/src/au.c b/src/au.c |
| index 62bd691d..f68f2587 100644 |
| --- a/src/au.c |
| +++ b/src/au.c |
| @@ -291,6 +291,7 @@ static int |
| au_read_header (SF_PRIVATE *psf) |
| { AU_FMT au_fmt ; |
| int marker, dword ; |
| + sf_count_t data_end ; |
| |
| memset (&au_fmt, 0, sizeof (au_fmt)) ; |
| psf_binheader_readf (psf, "pm", 0, &marker) ; |
| @@ -317,14 +318,15 @@ au_read_header (SF_PRIVATE *psf) |
| return SFE_AU_EMBED_BAD_LEN ; |
| } ; |
| |
| + data_end = (sf_count_t) au_fmt.dataoffset + (sf_count_t) au_fmt.datasize ; |
| if (psf->fileoffset > 0) |
| - { psf->filelength = au_fmt.dataoffset + au_fmt.datasize ; |
| + { psf->filelength = data_end ; |
| psf_log_printf (psf, " Data Size : %d\n", au_fmt.datasize) ; |
| } |
| - else if (au_fmt.datasize == -1 || au_fmt.dataoffset + au_fmt.datasize == psf->filelength) |
| + else if (au_fmt.datasize == -1 || data_end == psf->filelength) |
| psf_log_printf (psf, " Data Size : %d\n", au_fmt.datasize) ; |
| - else if (au_fmt.dataoffset + au_fmt.datasize < psf->filelength) |
| - { psf->filelength = au_fmt.dataoffset + au_fmt.datasize ; |
| + else if (data_end < psf->filelength) |
| + { psf->filelength = data_end ; |
| psf_log_printf (psf, " Data Size : %d\n", au_fmt.datasize) ; |
| } |
| else |
| From 0754d3380a54e3fbdde0f684b88955c80c79f58f Mon Sep 17 00:00:00 2001 |
| From: Alex Stewart <alex.stewart@ni.com> |
| Date: Wed, 11 Oct 2023 16:46:29 -0400 |
| Subject: [PATCH] avr: fix int overflow in avr_read_header() |
| |
| Pre-cast hdr.frames to sf_count_t, to provide the calculation with |
| enough numeric space to avoid an int-overflow. |
| |
| CVE: CVE-2022-33065 |
| Fixes: https://github.com/libsndfile/libsndfile/issues/833 |
| |
| Signed-off-by: Alex Stewart <alex.stewart@ni.com> |
| --- |
| src/avr.c | 2 +- |
| 1 file changed, 1 insertion(+), 1 deletion(-) |
| |
| diff --git a/src/avr.c b/src/avr.c |
| index 6c78ff69..1bc1ffc9 100644 |
| --- a/src/avr.c |
| +++ b/src/avr.c |
| @@ -162,7 +162,7 @@ avr_read_header (SF_PRIVATE *psf) |
| psf->endian = SF_ENDIAN_BIG ; |
| |
| psf->dataoffset = AVR_HDR_SIZE ; |
| - psf->datalength = hdr.frames * (hdr.rez / 8) ; |
| + psf->datalength = (sf_count_t) hdr.frames * (hdr.rez / 8) ; |
| |
| if (psf->fileoffset > 0) |
| psf->filelength = AVR_HDR_SIZE + psf->datalength ; |
| From 6ac31a68a614e2bba4a05b54e5558d6270c98376 Mon Sep 17 00:00:00 2001 |
| From: Alex Stewart <alex.stewart@ni.com> |
| Date: Wed, 11 Oct 2023 16:54:21 -0400 |
| Subject: [PATCH] sds: fix int overflow warning in sample calculations |
| |
| The sds_*byte_read() functions compose their uint_32 sample buffers by |
| shifting 7bit samples into a 32bit wide buffer, and adding them |
| together. Because the 7bit samples are stored in 32bit ints, code |
| fuzzers become concerned that the addition operation can overflow and |
| cause undefined behavior. |
| |
| Instead, bitwise-OR the bytes together - which should accomplish the |
| same arithmetic operation, without risking an int-overflow. |
| |
| CVE: CVE-2022-33065 |
| Fixes: https://github.com/libsndfile/libsndfile/issues/833 |
| |
| Signed-off-by: Alex Stewart <alex.stewart@ni.com> |
| |
| Do the same for the 3byte and 4byte read functions. |
| --- |
| src/sds.c | 6 +++--- |
| 1 file changed, 3 insertions(+), 3 deletions(-) |
| |
| diff --git a/src/sds.c b/src/sds.c |
| index 6bc76171..2a0f164c 100644 |
| --- a/src/sds.c |
| +++ b/src/sds.c |
| @@ -454,7 +454,7 @@ sds_2byte_read (SF_PRIVATE *psf, SDS_PRIVATE *psds) |
| |
| ucptr = psds->read_data + 5 ; |
| for (k = 0 ; k < 120 ; k += 2) |
| - { sample = arith_shift_left (ucptr [k], 25) + arith_shift_left (ucptr [k + 1], 18) ; |
| + { sample = arith_shift_left (ucptr [k], 25) | arith_shift_left (ucptr [k + 1], 18) ; |
| psds->read_samples [k / 2] = (int) (sample - 0x80000000) ; |
| } ; |
| |
| @@ -498,7 +498,7 @@ sds_3byte_read (SF_PRIVATE *psf, SDS_PRIVATE *psds) |
| |
| ucptr = psds->read_data + 5 ; |
| for (k = 0 ; k < 120 ; k += 3) |
| - { sample = (((uint32_t) ucptr [k]) << 25) + (ucptr [k + 1] << 18) + (ucptr [k + 2] << 11) ; |
| + { sample = (((uint32_t) ucptr [k]) << 25) | (ucptr [k + 1] << 18) | (ucptr [k + 2] << 11) ; |
| psds->read_samples [k / 3] = (int) (sample - 0x80000000) ; |
| } ; |
| |
| @@ -542,7 +542,7 @@ sds_4byte_read (SF_PRIVATE *psf, SDS_PRIVATE *psds) |
| |
| ucptr = psds->read_data + 5 ; |
| for (k = 0 ; k < 120 ; k += 4) |
| - { sample = (((uint32_t) ucptr [k]) << 25) + (ucptr [k + 1] << 18) + (ucptr [k + 2] << 11) + (ucptr [k + 3] << 4) ; |
| + { sample = (((uint32_t) ucptr [k]) << 25) | (ucptr [k + 1] << 18) | (ucptr [k + 2] << 11) | (ucptr [k + 3] << 4) ; |
| psds->read_samples [k / 4] = (int) (sample - 0x80000000) ; |
| } ; |
| |
| From 96428e1dd4998f1cd47df24f8fe9b0da35d7b947 Mon Sep 17 00:00:00 2001 |
| From: Alex Stewart <alex.stewart@ni.com> |
| Date: Wed, 11 Oct 2023 17:26:51 -0400 |
| Subject: [PATCH] aiff: fix int overflow when counting header elements |
| |
| aiff_read_basc_chunk() tries to count the AIFF header size by keeping |
| track of the bytes returned by psf_binheader_readf(). Though improbable, |
| it is technically possible for these added bytes to exceed the int-sized |
| `count` accumulator. |
| |
| Use a 64-bit sf_count_t type for `count`, to ensure that it always has |
| enough numeric space. |
| |
| CVE: CVE-2022-33065 |
| Fixes: https://github.com/libsndfile/libsndfile/issues/833 |
| |
| Signed-off-by: Alex Stewart <alex.stewart@ni.com> |
| --- |
| src/aiff.c | 2 +- |
| 1 file changed, 1 insertion(+), 1 deletion(-) |
| |
| diff --git a/src/aiff.c b/src/aiff.c |
| index a2bda8f4..6b244302 100644 |
| --- a/src/aiff.c |
| +++ b/src/aiff.c |
| @@ -1702,7 +1702,7 @@ static int |
| aiff_read_basc_chunk (SF_PRIVATE * psf, int datasize) |
| { const char * type_str ; |
| basc_CHUNK bc ; |
| - int count ; |
| + sf_count_t count ; |
| |
| count = psf_binheader_readf (psf, "E442", &bc.version, &bc.numBeats, &bc.rootNote) ; |
| count += psf_binheader_readf (psf, "E222", &bc.scaleType, &bc.sigNumerator, &bc.sigDenominator) ; |
| From b352c350d35bf978e4d3a32e5d9df1f2284445f4 Mon Sep 17 00:00:00 2001 |
| From: Alex Stewart <alex.stewart@ni.com> |
| Date: Wed, 11 Oct 2023 17:43:02 -0400 |
| Subject: [PATCH] ircam: fix int overflow in ircam_read_header() |
| |
| When reading the IRCAM header, it is possible for the calculated |
| blockwidth to exceed the bounds of a signed int32. |
| |
| Use a 64bit sf_count_t to store the blockwidth. |
| |
| CVE: CVE-2022-33065 |
| Fixes: https://github.com/libsndfile/libsndfile/issues/833 |
| |
| Signed-off-by: Alex Stewart <alex.stewart@ni.com> |
| --- |
| src/common.h | 2 +- |
| src/ircam.c | 10 +++++----- |
| 2 files changed, 6 insertions(+), 6 deletions(-) |
| |
| diff --git a/src/common.h b/src/common.h |
| index d92eabde..5369cb67 100644 |
| --- a/src/common.h |
| +++ b/src/common.h |
| @@ -439,7 +439,7 @@ typedef struct sf_private_tag |
| sf_count_t datalength ; /* Length in bytes of the audio data. */ |
| sf_count_t dataend ; /* Offset to file tailer. */ |
| |
| - int blockwidth ; /* Size in bytes of one set of interleaved samples. */ |
| + sf_count_t blockwidth ; /* Size in bytes of one set of interleaved samples. */ |
| int bytewidth ; /* Size in bytes of one sample (one channel). */ |
| |
| void *dither ; |
| diff --git a/src/ircam.c b/src/ircam.c |
| index 8e7cdba8..3d73ba44 100644 |
| --- a/src/ircam.c |
| +++ b/src/ircam.c |
| @@ -171,35 +171,35 @@ ircam_read_header (SF_PRIVATE *psf) |
| switch (encoding) |
| { case IRCAM_PCM_16 : |
| psf->bytewidth = 2 ; |
| - psf->blockwidth = psf->sf.channels * psf->bytewidth ; |
| + psf->blockwidth = (sf_count_t) psf->sf.channels * psf->bytewidth ; |
| |
| psf->sf.format = SF_FORMAT_IRCAM | SF_FORMAT_PCM_16 ; |
| break ; |
| |
| case IRCAM_PCM_32 : |
| psf->bytewidth = 4 ; |
| - psf->blockwidth = psf->sf.channels * psf->bytewidth ; |
| + psf->blockwidth = (sf_count_t) psf->sf.channels * psf->bytewidth ; |
| |
| psf->sf.format = SF_FORMAT_IRCAM | SF_FORMAT_PCM_32 ; |
| break ; |
| |
| case IRCAM_FLOAT : |
| psf->bytewidth = 4 ; |
| - psf->blockwidth = psf->sf.channels * psf->bytewidth ; |
| + psf->blockwidth = (sf_count_t) psf->sf.channels * psf->bytewidth ; |
| |
| psf->sf.format = SF_FORMAT_IRCAM | SF_FORMAT_FLOAT ; |
| break ; |
| |
| case IRCAM_ALAW : |
| psf->bytewidth = 1 ; |
| - psf->blockwidth = psf->sf.channels * psf->bytewidth ; |
| + psf->blockwidth = (sf_count_t) psf->sf.channels * psf->bytewidth ; |
| |
| psf->sf.format = SF_FORMAT_IRCAM | SF_FORMAT_ALAW ; |
| break ; |
| |
| case IRCAM_ULAW : |
| psf->bytewidth = 1 ; |
| - psf->blockwidth = psf->sf.channels * psf->bytewidth ; |
| + psf->blockwidth = (sf_count_t) psf->sf.channels * psf->bytewidth ; |
| |
| psf->sf.format = SF_FORMAT_IRCAM | SF_FORMAT_ULAW ; |
| break ; |
| From 3bcd291e57867f88f558fa6f80990e84311df78c Mon Sep 17 00:00:00 2001 |
| From: Alex Stewart <alex.stewart@ni.com> |
| Date: Wed, 11 Oct 2023 16:12:22 -0400 |
| Subject: [PATCH] mat4/mat5: fix int overflow when calculating blockwidth |
| |
| Pre-cast the components of the blockwidth calculation to sf_count_t to |
| avoid overflowing integers during calculation. |
| |
| CVE: CVE-2022-33065 |
| Fixes: https://github.com/libsndfile/libsndfile/issues/833 |
| |
| Signed-off-by: Alex Stewart <alex.stewart@ni.com> |
| --- |
| src/mat4.c | 2 +- |
| src/mat5.c | 2 +- |
| 2 files changed, 2 insertions(+), 2 deletions(-) |
| |
| diff --git a/src/mat4.c b/src/mat4.c |
| index 575683ba..9f046f0c 100644 |
| --- a/src/mat4.c |
| +++ b/src/mat4.c |
| @@ -104,7 +104,7 @@ mat4_open (SF_PRIVATE *psf) |
| |
| psf->container_close = mat4_close ; |
| |
| - psf->blockwidth = psf->bytewidth * psf->sf.channels ; |
| + psf->blockwidth = (sf_count_t) psf->bytewidth * psf->sf.channels ; |
| |
| switch (subformat) |
| { case SF_FORMAT_PCM_16 : |
| diff --git a/src/mat5.c b/src/mat5.c |
| index da5a6eca..20f0ea64 100644 |
| --- a/src/mat5.c |
| +++ b/src/mat5.c |
| @@ -114,7 +114,7 @@ mat5_open (SF_PRIVATE *psf) |
| |
| psf->container_close = mat5_close ; |
| |
| - psf->blockwidth = psf->bytewidth * psf->sf.channels ; |
| + psf->blockwidth = (sf_count_t) psf->bytewidth * psf->sf.channels ; |
| |
| switch (subformat) |
| { case SF_FORMAT_PCM_U8 : |
| From c177e292d47ef73b1d3c1bb391320299a0ed2ff9 Mon Sep 17 00:00:00 2001 |
| From: Alex Stewart <alex.stewart@ni.com> |
| Date: Mon, 16 Oct 2023 12:37:47 -0400 |
| Subject: [PATCH] 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 <alex.stewart@ni.com> |
| --- |
| src/common.c | 36 ++++++++++++++++++++++++------------ |
| 1 file changed, 24 insertions(+), 12 deletions(-) |
| |
| diff --git a/src/common.c b/src/common.c |
| index 1c3d951d..7f6cceca 100644 |
| --- a/src/common.c |
| +++ b/src/common.c |
| @@ -18,6 +18,7 @@ |
| |
| #include <config.h> |
| |
| +#include <limits.h> |
| #include <stdarg.h> |
| #include <string.h> |
| #if HAVE_UNISTD_H |
| @@ -990,6 +991,7 @@ psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...) |
| double *doubleptr ; |
| char c ; |
| int byte_count = 0, count = 0 ; |
| + int read_bytes = 0 ; |
| |
| if (! format) |
| return psf_ftell (psf) ; |
| @@ -998,6 +1000,7 @@ psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...) |
| |
| while ((c = *format++)) |
| { |
| + read_bytes = 0 ; |
| if (psf->header.indx + 16 >= psf->header.len && psf_bump_header_allocation (psf, 16)) |
| break ; |
| |
| @@ -1014,7 +1017,7 @@ psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...) |
| 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 ; |
| |
| @@ -1022,7 +1025,7 @@ psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...) |
| 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++) |
| @@ -1034,14 +1037,14 @@ psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...) |
| 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 |
| @@ -1051,7 +1054,7 @@ psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...) |
| 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 |
| @@ -1062,7 +1065,7 @@ psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...) |
| 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 |
| @@ -1072,7 +1075,7 @@ psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...) |
| 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 |
| @@ -1083,7 +1086,7 @@ psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...) |
| 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 |
| @@ -1093,7 +1096,7 @@ psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...) |
| 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 |
| @@ -1117,7 +1120,7 @@ psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...) |
| 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' : |
| @@ -1128,7 +1131,7 @@ psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...) |
| if (psf->header.indx + count >= psf->header.len && psf_bump_header_allocation (psf, count)) |
| break ; |
| |
| - byte_count += header_gets (psf, charptr, count) ; |
| + read_bytes = header_gets (psf, charptr, count) ; |
| break ; |
| |
| case 'z' : |
| @@ -1152,7 +1155,7 @@ psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...) |
| 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 ; |
| |
| case '!' : /* Clear buffer, forcing re-read. */ |
| @@ -1164,8 +1167,17 @@ psf_binheader_readf (SF_PRIVATE *psf, char const *format, ...) |
| 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 ; |
| From a23d563386e7c8d93dcdbe7d5b1d63cad6009116 Mon Sep 17 00:00:00 2001 |
| From: Alex Stewart <alex.stewart@ni.com> |
| Date: Thu, 19 Oct 2023 14:07:19 -0400 |
| Subject: [PATCH] nms_adpcm: fix int overflow in signal estimate |
| |
| It is possible (though functionally incorrect) for the signal estimate |
| calculation in nms_adpcm_update() to overflow the int value of s_e, |
| resulting in undefined behavior. |
| |
| Since adpcm state signal values are never practically larger than |
| 16 bits, use smaller numeric sizes throughout the file to avoid the |
| overflow. |
| |
| CVE: CVE-2022-33065 |
| Fixes: https://github.com/libsndfile/libsndfile/issues/833 |
| |
| Authored-by: Arthur Taylor <art@ified.ca> |
| Signed-off-by: Alex Stewart <alex.stewart@ni.com> |
| Rebased-by: Alex Stewart <alex.stewart@ni.com> |
| --- |
| src/nms_adpcm.c | 85 ++++++++++++++++++++++++------------------------- |
| 1 file changed, 42 insertions(+), 43 deletions(-) |
| |
| diff --git a/src/nms_adpcm.c b/src/nms_adpcm.c |
| index 96d6ad26..460ea077 100644 |
| --- a/src/nms_adpcm.c |
| +++ b/src/nms_adpcm.c |
| @@ -48,36 +48,36 @@ |
| /* Variable names from ITU G.726 spec */ |
| struct nms_adpcm_state |
| { /* Log of the step size multiplier. Operated on by codewords. */ |
| - int yl ; |
| + short yl ; |
| |
| /* Quantizer step size multiplier. Generated from yl. */ |
| - int y ; |
| + short y ; |
| |
| - /* Coefficents of the pole predictor */ |
| - int a [2] ; |
| + /* Coefficients of the pole predictor */ |
| + short a [2] ; |
| |
| - /* Coefficents of the zero predictor */ |
| - int b [6] ; |
| + /* Coefficients of the zero predictor */ |
| + short b [6] ; |
| |
| /* Previous quantized deltas (multiplied by 2^14) */ |
| - int d_q [7] ; |
| + short d_q [7] ; |
| |
| /* d_q [x] + s_ez [x], used by the pole-predictor for signs only. */ |
| - int p [3] ; |
| + short p [3] ; |
| |
| /* Previous reconstructed signal values. */ |
| - int s_r [2] ; |
| + short s_r [2] ; |
| |
| /* Zero predictor components of the signal estimate. */ |
| - int s_ez ; |
| + short s_ez ; |
| |
| /* Signal estimate, (including s_ez). */ |
| - int s_e ; |
| + short s_e ; |
| |
| /* The most recent codeword (enc:generated, dec:inputted) */ |
| - int Ik ; |
| + char Ik ; |
| |
| - int parity ; |
| + char parity ; |
| |
| /* |
| ** Offset into code tables for the bitrate. |
| @@ -109,7 +109,7 @@ typedef struct |
| } NMS_ADPCM_PRIVATE ; |
| |
| /* Pre-computed exponential interval used in the antilog approximation. */ |
| -static unsigned int table_expn [] = |
| +static unsigned short table_expn [] = |
| { 0x4000, 0x4167, 0x42d5, 0x444c, 0x45cb, 0x4752, 0x48e2, 0x4a7a, |
| 0x4c1b, 0x4dc7, 0x4f7a, 0x5138, 0x52ff, 0x54d1, 0x56ac, 0x5892, |
| 0x5a82, 0x5c7e, 0x5e84, 0x6096, 0x62b4, 0x64dd, 0x6712, 0x6954, |
| @@ -117,21 +117,21 @@ static unsigned int table_expn [] = |
| } ; |
| |
| /* Table mapping codewords to scale factor deltas. */ |
| -static int table_scale_factor_step [] = |
| +static short table_scale_factor_step [] = |
| { 0x0, 0x0, 0x0, 0x0, 0x4b0, 0x0, 0x0, 0x0, /* 2-bit */ |
| -0x3c, 0x0, 0x90, 0x0, 0x2ee, 0x0, 0x898, 0x0, /* 3-bit */ |
| -0x30, 0x12, 0x6b, 0xc8, 0x188, 0x2e0, 0x551, 0x1150, /* 4-bit */ |
| } ; |
| |
| /* Table mapping codewords to quantized delta interval steps. */ |
| -static unsigned int table_step [] = |
| +static unsigned short table_step [] = |
| { 0x73F, 0, 0, 0, 0x1829, 0, 0, 0, /* 2-bit */ |
| 0x3EB, 0, 0xC18, 0, 0x1581, 0, 0x226E, 0, /* 3-bit */ |
| 0x20C, 0x635, 0xA83, 0xF12, 0x1418, 0x19E3, 0x211A, 0x2BBA, /* 4-bit */ |
| } ; |
| |
| /* Binary search lookup table for quantizing using table_step. */ |
| -static int table_step_search [] = |
| +static short table_step_search [] = |
| { 0, 0x1F6D, 0, -0x1F6D, 0, 0, 0, 0, /* 2-bit */ |
| 0x1008, 0x1192, 0, -0x219A, 0x1656, -0x1656, 0, 0, /* 3-bit */ |
| 0x872, 0x1277, -0x8E6, -0x232B, 0xD06, -0x17D7, -0x11D3, 0, /* 4-bit */ |
| @@ -179,23 +179,23 @@ static sf_count_t nms_adpcm_seek (SF_PRIVATE *psf, int mode, sf_count_t offset) |
| ** Maps [1,20480] to [1,1024] in an exponential relationship. This is |
| ** approximately ret = b^exp where b = e^(ln(1024)/ln(20480)) ~= 1.0003385 |
| */ |
| -static inline int |
| -nms_adpcm_antilog (int exp) |
| -{ int ret ; |
| +static inline short |
| +nms_adpcm_antilog (short exp) |
| +{ int_fast32_t r ; |
| |
| - ret = 0x1000 ; |
| - ret += (((exp & 0x3f) * 0x166b) >> 12) ; |
| - ret *= table_expn [(exp & 0x7c0) >> 6] ; |
| - ret >>= (26 - (exp >> 11)) ; |
| + r = 0x1000 ; |
| + r += (((int_fast32_t) (exp & 0x3f) * 0x166b) >> 12) ; |
| + r *= table_expn [(exp & 0x7c0) >> 6] ; |
| + r >>= (26 - (exp >> 11)) ; |
| |
| - return ret ; |
| + return (short) r ; |
| } /* nms_adpcm_antilog */ |
| |
| static void |
| nms_adpcm_update (struct nms_adpcm_state *s) |
| { /* Variable names from ITU G.726 spec */ |
| - int a1ul ; |
| - int fa1 ; |
| + short a1ul, fa1 ; |
| + int_fast32_t se ; |
| int i ; |
| |
| /* Decay and Modify the scale factor in the log domain based on the codeword. */ |
| @@ -222,7 +222,7 @@ nms_adpcm_update (struct nms_adpcm_state *s) |
| else if (fa1 > 256) |
| fa1 = 256 ; |
| |
| - s->a [0] = (0xff * s->a [0]) >> 8 ; |
| + s->a [0] = (s->a [0] * 0xff) >> 8 ; |
| if (s->p [0] != 0 && s->p [1] != 0 && ((s->p [0] ^ s->p [1]) < 0)) |
| s->a [0] -= 192 ; |
| else |
| @@ -230,7 +230,7 @@ nms_adpcm_update (struct nms_adpcm_state *s) |
| fa1 = -fa1 ; |
| } |
| |
| - s->a [1] = fa1 + ((0xfe * s->a [1]) >> 8) ; |
| + s->a [1] = fa1 + ((s->a [1] * 0xfe) >> 8) ; |
| if (s->p [0] != 0 && s->p [2] != 0 && ((s->p [0] ^ s->p [2]) < 0)) |
| s->a [1] -= 128 ; |
| else |
| @@ -250,19 +250,18 @@ nms_adpcm_update (struct nms_adpcm_state *s) |
| s->a [0] = a1ul ; |
| } ; |
| |
| - /* Compute the zero predictor estimate. Rotate past deltas too. */ |
| - s->s_ez = 0 ; |
| + /* Compute the zero predictor estimate and rotate past deltas. */ |
| + se = 0 ; |
| for (i = 5 ; i >= 0 ; i--) |
| - { s->s_ez += s->d_q [i] * s->b [i] ; |
| + { se += (int_fast32_t) s->d_q [i] * s->b [i] ; |
| s->d_q [i + 1] = s->d_q [i] ; |
| } ; |
| + s->s_ez = se >> 14 ; |
| |
| - /* Compute the signal estimate. */ |
| - s->s_e = s->a [0] * s->s_r [0] + s->a [1] * s->s_r [1] + s->s_ez ; |
| - |
| - /* Return to scale */ |
| - s->s_ez >>= 14 ; |
| - s->s_e >>= 14 ; |
| + /* Complete the signal estimate. */ |
| + se += (int_fast32_t) s->a [0] * s->s_r [0] ; |
| + se += (int_fast32_t) s->a [1] * s->s_r [1] ; |
| + s->s_e = se >> 14 ; |
| |
| /* Rotate members to prepare for next iteration. */ |
| s->s_r [1] = s->s_r [0] ; |
| @@ -274,7 +273,7 @@ nms_adpcm_update (struct nms_adpcm_state *s) |
| static int16_t |
| nms_adpcm_reconstruct_sample (struct nms_adpcm_state *s, uint8_t I) |
| { /* Variable names from ITU G.726 spec */ |
| - int dqx ; |
| + int_fast32_t dqx ; |
| |
| /* |
| ** The ordering of the 12-bit right-shift is a precision loss. It agrees |
| @@ -308,17 +307,17 @@ nms_adpcm_codec_init (struct nms_adpcm_state *s, enum nms_enc_type type) |
| /* |
| ** nms_adpcm_encode_sample() |
| ** |
| -** Encode a linear 16-bit pcm sample into a 2,3, or 4 bit NMS-ADPCM codeword |
| +** Encode a linear 16-bit pcm sample into a 2, 3, or 4 bit NMS-ADPCM codeword |
| ** using and updating the predictor state. |
| */ |
| static uint8_t |
| nms_adpcm_encode_sample (struct nms_adpcm_state *s, int16_t sl) |
| { /* Variable names from ITU G.726 spec */ |
| - int d ; |
| + int_fast32_t d ; |
| uint8_t I ; |
| |
| /* Down scale the sample from 16 => ~14 bits. */ |
| - sl = (sl * 0x1fdf) / 0x7fff ; |
| + sl = ((int_fast32_t) sl * 0x1fdf) / 0x7fff ; |
| |
| /* Compute estimate, and delta from actual value */ |
| nms_adpcm_update (s) ; |
| @@ -407,7 +406,7 @@ nms_adpcm_encode_sample (struct nms_adpcm_state *s, int16_t sl) |
| */ |
| static int16_t |
| nms_adpcm_decode_sample (struct nms_adpcm_state *s, uint8_t I) |
| -{ int sl ; |
| +{ int_fast32_t sl ; |
| |
| nms_adpcm_update (s) ; |
| sl = nms_adpcm_reconstruct_sample (s, I) ; |