diff --git a/libsndfile-progs.spec b/libsndfile-progs.spec index ce911d6..c1797d2 100644 --- a/libsndfile-progs.spec +++ b/libsndfile-progs.spec @@ -1,7 +1,7 @@ # # spec file for package libsndfile-progs # -# Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2015 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed diff --git a/libsndfile.changes b/libsndfile.changes index 6fdf5ef..0a28132 100644 --- a/libsndfile.changes +++ b/libsndfile.changes @@ -1,3 +1,11 @@ +------------------------------------------------------------------- +Wed Jan 7 08:30:31 CET 2015 - tiwai@suse.de + +- VUL-0: two buffer read overflows in sd2_parse_rsrc_fork() + (CVE-2014-9496, bnc#911796): backported upstream fix patches + sndfile-src-sd2.c-Fix-segfault-in-SD2-RSRC-parser.patch + sndfile-src-sd2.c-Fix-two-potential-buffer-read-overflows.patch + ------------------------------------------------------------------- Mon Apr 15 13:57:35 UTC 2013 - mmeister@suse.com diff --git a/libsndfile.spec b/libsndfile.spec index 0fcd03d..24fa687 100644 --- a/libsndfile.spec +++ b/libsndfile.spec @@ -1,7 +1,7 @@ # # spec file for package libsndfile # -# Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2015 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -46,6 +46,10 @@ Patch0: libsndfile-example-fix.diff # PATCH-MISSING-TAG -- See http://en.opensuse.org/openSUSE:Packaging_Patches_guidelines Patch1: libsndfile-paf-zero-division-fix.diff Patch2: sndfile-ocloexec.patch +# PATCH-FIX-UPSTREAM CVE-2014-9496 bnc#911796 +Patch3: sndfile-src-sd2.c-Fix-segfault-in-SD2-RSRC-parser.patch +# PATCH-FIX-UPSTREAM CVE-2014-9496 bnc#911796 +Patch4: sndfile-src-sd2.c-Fix-two-potential-buffer-read-overflows.patch BuildRoot: %{_tmppath}/%{name}-%{version}-build %description @@ -89,6 +93,8 @@ libsndfile library. %patch0 %patch1 -p1 %patch2 +%patch3 -p1 +%patch4 -p1 %build %define warn_flags -W -Wall -Wstrict-prototypes -Wpointer-arith -Wno-unused-parameter diff --git a/sndfile-src-sd2.c-Fix-segfault-in-SD2-RSRC-parser.patch b/sndfile-src-sd2.c-Fix-segfault-in-SD2-RSRC-parser.patch new file mode 100644 index 0000000..744565e --- /dev/null +++ b/sndfile-src-sd2.c-Fix-segfault-in-SD2-RSRC-parser.patch @@ -0,0 +1,200 @@ +From 9341e9c6e70cd3ad76c901c3cf052d4cb52fd827 Mon Sep 17 00:00:00 2001 +From: Erik de Castro Lopo +Date: Thu, 27 Jun 2013 18:04:03 +1000 +Subject: [PATCH] src/sd2.c : Fix segfault in SD2 RSRC parser. + +A specially crafted resource fork for an SD2 file can cause +the SD2 RSRC parser to read data from outside a dynamically +defined buffer. The data that is read is converted into a +short or int and used during further processing. + +Since no write occurs, this is unlikely to be exploitable. + +Bug reported by The Mayhem Team from Cylab, Carnegie Mellon +Univeristy. Paper is: +http://users.ece.cmu.edu/~arebert/papers/mayhem-oakland-12.pdf +--- + src/sd2.c | 93 ++++++++++++++++++++++++++++++++++++-------------------------- + 1 file changed, 55 insertions(+), 38 deletions(-) + +--- a/src/sd2.c ++++ b/src/sd2.c +@@ -1,5 +1,5 @@ + /* +-** Copyright (C) 2001-2011 Erik de Castro Lopo ++** Copyright (C) 2001-2013 Erik de Castro Lopo + ** Copyright (C) 2004 Paavo Jumppanen + ** + ** This program is free software; you can redistribute it and/or modify +@@ -370,44 +370,61 @@ sd2_write_rsrc_fork (SF_PRIVATE *psf, in + */ + + static inline int +-read_char (const unsigned char * data, int offset) +-{ return data [offset] ; +-} /* read_char */ ++read_rsrc_char (const SD2_RSRC *prsrc, int offset) ++{ const unsigned char * data = prsrc->rsrc_data ; ++ if (offset < 0 || offset >= prsrc->rsrc_len) ++ return 0 ; ++ return data [offset] ; ++} /* read_rsrc_char */ + + static inline int +-read_short (const unsigned char * data, int offset) +-{ return (data [offset] << 8) + data [offset + 1] ; +-} /* read_short */ ++read_rsrc_short (const SD2_RSRC *prsrc, int offset) ++{ const unsigned char * data = prsrc->rsrc_data ; ++ if (offset < 0 || offset + 1 >= prsrc->rsrc_len) ++ return 0 ; ++ return (data [offset] << 8) + data [offset + 1] ; ++} /* read_rsrc_short */ + + static inline int +-read_int (const unsigned char * data, int offset) +-{ return (data [offset] << 24) + (data [offset + 1] << 16) + (data [offset + 2] << 8) + data [offset + 3] ; +-} /* read_int */ ++read_rsrc_int (const SD2_RSRC *prsrc, int offset) ++{ const unsigned char * data = prsrc->rsrc_data ; ++ if (offset < 0 || offset + 3 >= prsrc->rsrc_len) ++ return 0 ; ++ return (data [offset] << 24) + (data [offset + 1] << 16) + (data [offset + 2] << 8) + data [offset + 3] ; ++} /* read_rsrc_int */ + + static inline int +-read_marker (const unsigned char * data, int offset) +-{ ++read_rsrc_marker (const SD2_RSRC *prsrc, int offset) ++{ const unsigned char * data = prsrc->rsrc_data ; ++ ++ if (offset < 0 || offset + 3 >= prsrc->rsrc_len) ++ return 0 ; ++ + if (CPU_IS_BIG_ENDIAN) + return (data [offset] << 24) + (data [offset + 1] << 16) + (data [offset + 2] << 8) + data [offset + 3] ; +- else if (CPU_IS_LITTLE_ENDIAN) ++ if (CPU_IS_LITTLE_ENDIAN) + return data [offset] + (data [offset + 1] << 8) + (data [offset + 2] << 16) + (data [offset + 3] << 24) ; +- else +- return 0x666 ; +-} /* read_marker */ ++ ++ return 0 ; ++} /* read_rsrc_marker */ + + static void +-read_str (const unsigned char * data, int offset, char * buffer, int buffer_len) +-{ int k ; ++read_rsrc_str (const SD2_RSRC *prsrc, int offset, char * buffer, int buffer_len) ++{ const unsigned char * data = prsrc->rsrc_data ; ++ int k ; + + memset (buffer, 0, buffer_len) ; + ++ if (offset < 0 || offset + buffer_len >= prsrc->rsrc_len) ++ return ; ++ + for (k = 0 ; k < buffer_len - 1 ; k++) + { if (psf_isprint (data [offset + k]) == 0) + return ; + buffer [k] = data [offset + k] ; + } ; + return ; +-} /* read_str */ ++} /* read_rsrc_str */ + + static int + sd2_parse_rsrc_fork (SF_PRIVATE *psf) +@@ -434,17 +451,17 @@ sd2_parse_rsrc_fork (SF_PRIVATE *psf) + /* Reset the header storage because we have changed to the rsrcdes. */ + psf->headindex = psf->headend = rsrc.rsrc_len ; + +- rsrc.data_offset = read_int (rsrc.rsrc_data, 0) ; +- rsrc.map_offset = read_int (rsrc.rsrc_data, 4) ; +- rsrc.data_length = read_int (rsrc.rsrc_data, 8) ; +- rsrc.map_length = read_int (rsrc.rsrc_data, 12) ; ++ rsrc.data_offset = read_rsrc_int (&rsrc, 0) ; ++ rsrc.map_offset = read_rsrc_int (&rsrc, 4) ; ++ rsrc.data_length = read_rsrc_int (&rsrc, 8) ; ++ rsrc.map_length = read_rsrc_int (&rsrc, 12) ; + + if (rsrc.data_offset == 0x51607 && rsrc.map_offset == 0x20000) + { psf_log_printf (psf, "Trying offset of 0x52 bytes.\n") ; +- rsrc.data_offset = read_int (rsrc.rsrc_data, 0x52 + 0) + 0x52 ; +- rsrc.map_offset = read_int (rsrc.rsrc_data, 0x52 + 4) + 0x52 ; +- rsrc.data_length = read_int (rsrc.rsrc_data, 0x52 + 8) ; +- rsrc.map_length = read_int (rsrc.rsrc_data, 0x52 + 12) ; ++ rsrc.data_offset = read_rsrc_int (&rsrc, 0x52 + 0) + 0x52 ; ++ rsrc.map_offset = read_rsrc_int (&rsrc, 0x52 + 4) + 0x52 ; ++ rsrc.data_length = read_rsrc_int (&rsrc, 0x52 + 8) ; ++ rsrc.map_length = read_rsrc_int (&rsrc, 0x52 + 12) ; + } ; + + psf_log_printf (psf, " data offset : 0x%04X\n map offset : 0x%04X\n" +@@ -487,7 +504,7 @@ sd2_parse_rsrc_fork (SF_PRIVATE *psf) + goto parse_rsrc_fork_cleanup ; + } ; + +- rsrc.string_offset = rsrc.map_offset + read_short (rsrc.rsrc_data, rsrc.map_offset + 26) ; ++ rsrc.string_offset = rsrc.map_offset + read_rsrc_short (&rsrc, rsrc.map_offset + 26) ; + if (rsrc.string_offset > rsrc.rsrc_len) + { psf_log_printf (psf, "Bad string offset (%d).\n", rsrc.string_offset) ; + error = SFE_SD2_BAD_RSRC ; +@@ -496,7 +513,7 @@ sd2_parse_rsrc_fork (SF_PRIVATE *psf) + + rsrc.type_offset = rsrc.map_offset + 30 ; + +- rsrc.type_count = read_short (rsrc.rsrc_data, rsrc.map_offset + 28) + 1 ; ++ rsrc.type_count = read_rsrc_short (&rsrc, rsrc.map_offset + 28) + 1 ; + if (rsrc.type_count < 1) + { psf_log_printf (psf, "Bad type count.\n") ; + error = SFE_SD2_BAD_RSRC ; +@@ -512,11 +529,11 @@ sd2_parse_rsrc_fork (SF_PRIVATE *psf) + + rsrc.str_index = -1 ; + for (k = 0 ; k < rsrc.type_count ; k ++) +- { marker = read_marker (rsrc.rsrc_data, rsrc.type_offset + k * 8) ; ++ { marker = read_rsrc_marker (&rsrc, rsrc.type_offset + k * 8) ; + + if (marker == STR_MARKER) + { rsrc.str_index = k ; +- rsrc.str_count = read_short (rsrc.rsrc_data, rsrc.type_offset + k * 8 + 4) + 1 ; ++ rsrc.str_count = read_rsrc_short (&rsrc, rsrc.type_offset + k * 8 + 4) + 1 ; + error = parse_str_rsrc (psf, &rsrc) ; + goto parse_rsrc_fork_cleanup ; + } ; +@@ -548,26 +565,26 @@ parse_str_rsrc (SF_PRIVATE *psf, SD2_RSR + for (k = 0 ; data_offset + data_len < rsrc->rsrc_len ; k++) + { int slen ; + +- slen = read_char (rsrc->rsrc_data, str_offset) ; +- read_str (rsrc->rsrc_data, str_offset + 1, name, SF_MIN (SIGNED_SIZEOF (name), slen + 1)) ; ++ slen = read_rsrc_char (rsrc, str_offset) ; ++ read_rsrc_str (rsrc, str_offset + 1, name, SF_MIN (SIGNED_SIZEOF (name), slen + 1)) ; + str_offset += slen + 1 ; + +- rsrc_id = read_short (rsrc->rsrc_data, rsrc->item_offset + k * 12) ; ++ rsrc_id = read_rsrc_short (rsrc, rsrc->item_offset + k * 12) ; + +- data_offset = rsrc->data_offset + read_int (rsrc->rsrc_data, rsrc->item_offset + k * 12 + 4) ; ++ data_offset = rsrc->data_offset + read_rsrc_int (rsrc, rsrc->item_offset + k * 12 + 4) ; + if (data_offset < 0 || data_offset > rsrc->rsrc_len) + { psf_log_printf (psf, "Exiting parser on data offset of %d.\n", data_offset) ; + break ; + } ; + +- data_len = read_int (rsrc->rsrc_data, data_offset) ; ++ data_len = read_rsrc_int (rsrc, data_offset) ; + if (data_len < 0 || data_len > rsrc->rsrc_len) + { psf_log_printf (psf, "Exiting parser on data length of %d.\n", data_len) ; + break ; + } ; + +- slen = read_char (rsrc->rsrc_data, data_offset + 4) ; +- read_str (rsrc->rsrc_data, data_offset + 5, value, SF_MIN (SIGNED_SIZEOF (value), slen + 1)) ; ++ slen = read_rsrc_char (rsrc, data_offset + 4) ; ++ read_rsrc_str (rsrc, data_offset + 5, value, SF_MIN (SIGNED_SIZEOF (value), slen + 1)) ; + + psf_log_printf (psf, " 0x%04x %4d %4d %3d '%s'\n", data_offset, rsrc_id, data_len, slen, value) ; + diff --git a/sndfile-src-sd2.c-Fix-two-potential-buffer-read-overflows.patch b/sndfile-src-sd2.c-Fix-two-potential-buffer-read-overflows.patch new file mode 100644 index 0000000..686071f --- /dev/null +++ b/sndfile-src-sd2.c-Fix-two-potential-buffer-read-overflows.patch @@ -0,0 +1,38 @@ +From dbe14f00030af5d3577f4cabbf9861db59e9c378 Mon Sep 17 00:00:00 2001 +From: Erik de Castro Lopo +Date: Thu, 25 Dec 2014 19:23:12 +1100 +Subject: [PATCH] src/sd2.c : Fix two potential buffer read overflows. + +Closes: https://github.com/erikd/libsndfile/issues/93 +--- + src/sd2.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +--- a/src/sd2.c ++++ b/src/sd2.c +@@ -513,6 +513,11 @@ sd2_parse_rsrc_fork (SF_PRIVATE *psf) + + rsrc.type_offset = rsrc.map_offset + 30 ; + ++ if (rsrc.map_offset + 28 > rsrc.rsrc_len) ++ { psf_log_printf (psf, "Bad map offset.\n") ; ++ goto parse_rsrc_fork_cleanup ; ++ } ; ++ + rsrc.type_count = read_rsrc_short (&rsrc, rsrc.map_offset + 28) + 1 ; + if (rsrc.type_count < 1) + { psf_log_printf (psf, "Bad type count.\n") ; +@@ -529,7 +534,12 @@ sd2_parse_rsrc_fork (SF_PRIVATE *psf) + + rsrc.str_index = -1 ; + for (k = 0 ; k < rsrc.type_count ; k ++) +- { marker = read_rsrc_marker (&rsrc, rsrc.type_offset + k * 8) ; ++ { if (rsrc.type_offset + k * 8 > rsrc.rsrc_len) ++ { psf_log_printf (psf, "Bad rsrc marker.\n") ; ++ goto parse_rsrc_fork_cleanup ; ++ } ; ++ ++ marker = read_rsrc_marker (&rsrc, rsrc.type_offset + k * 8) ; + + if (marker == STR_MARKER) + { rsrc.str_index = k ;