- 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 OBS-URL: https://build.opensuse.org/request/show/280133 OBS-URL: https://build.opensuse.org/package/show/multimedia:libs/libsndfile?expand=0&rev=43
201 lines
7.7 KiB
Diff
201 lines
7.7 KiB
Diff
From 9341e9c6e70cd3ad76c901c3cf052d4cb52fd827 Mon Sep 17 00:00:00 2001
|
|
From: Erik de Castro Lopo <erikd@mega-nerd.com>
|
|
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 <erikd@mega-nerd.com>
|
|
+** Copyright (C) 2001-2013 Erik de Castro Lopo <erikd@mega-nerd.com>
|
|
** 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) ;
|
|
|