Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 1 | From 9341e9c6e70cd3ad76c901c3cf052d4cb52fd827 Mon Sep 17 00:00:00 2001 |
| 2 | From: Erik de Castro Lopo <erikd@mega-nerd.com> |
| 3 | Date: Thu, 27 Jun 2013 18:04:03 +1000 |
| 4 | Subject: [PATCH] src/sd2.c : Fix segfault in SD2 RSRC parser. |
| 5 | |
| 6 | (Upstream commit 9341e9c6e70cd3ad76c901c3cf052d4cb52fd827) |
| 7 | |
| 8 | A specially crafted resource fork for an SD2 file can cause |
| 9 | the SD2 RSRC parser to read data from outside a dynamically |
| 10 | defined buffer. The data that is read is converted into a |
| 11 | short or int and used during further processing. |
| 12 | |
| 13 | Since no write occurs, this is unlikely to be exploitable. |
| 14 | |
| 15 | Bug reported by The Mayhem Team from Cylab, Carnegie Mellon |
| 16 | Univeristy. Paper is: |
| 17 | http://users.ece.cmu.edu/~arebert/papers/mayhem-oakland-12.pdf |
| 18 | |
| 19 | Upstream-Status: Backport |
| 20 | |
| 21 | Signed-off-by: Yue Tao <yue.tao@windriver.com> |
| 22 | --- |
| 23 | src/sd2.c | 93 ++++++++++++++++++++++++++++++++++++------------------------- |
| 24 | 1 file changed, 55 insertions(+), 38 deletions(-) |
| 25 | |
| 26 | diff --git a/src/sd2.c b/src/sd2.c |
| 27 | index 35ce36b..6be150c 100644 |
| 28 | --- a/src/sd2.c |
| 29 | +++ b/src/sd2.c |
| 30 | @@ -1,5 +1,5 @@ |
| 31 | /* |
| 32 | -** Copyright (C) 2001-2011 Erik de Castro Lopo <erikd@mega-nerd.com> |
| 33 | +** Copyright (C) 2001-2013 Erik de Castro Lopo <erikd@mega-nerd.com> |
| 34 | ** Copyright (C) 2004 Paavo Jumppanen |
| 35 | ** |
| 36 | ** This program is free software; you can redistribute it and/or modify |
| 37 | @@ -371,44 +371,61 @@ sd2_write_rsrc_fork (SF_PRIVATE *psf, int UNUSED (calc_length)) |
| 38 | */ |
| 39 | |
| 40 | static inline int |
| 41 | -read_char (const unsigned char * data, int offset) |
| 42 | -{ return data [offset] ; |
| 43 | -} /* read_char */ |
| 44 | +read_rsrc_char (const SD2_RSRC *prsrc, int offset) |
| 45 | +{ const unsigned char * data = prsrc->rsrc_data ; |
| 46 | + if (offset < 0 || offset >= prsrc->rsrc_len) |
| 47 | + return 0 ; |
| 48 | + return data [offset] ; |
| 49 | +} /* read_rsrc_char */ |
| 50 | |
| 51 | static inline int |
| 52 | -read_short (const unsigned char * data, int offset) |
| 53 | -{ return (data [offset] << 8) + data [offset + 1] ; |
| 54 | -} /* read_short */ |
| 55 | +read_rsrc_short (const SD2_RSRC *prsrc, int offset) |
| 56 | +{ const unsigned char * data = prsrc->rsrc_data ; |
| 57 | + if (offset < 0 || offset + 1 >= prsrc->rsrc_len) |
| 58 | + return 0 ; |
| 59 | + return (data [offset] << 8) + data [offset + 1] ; |
| 60 | +} /* read_rsrc_short */ |
| 61 | |
| 62 | static inline int |
| 63 | -read_int (const unsigned char * data, int offset) |
| 64 | -{ return (data [offset] << 24) + (data [offset + 1] << 16) + (data [offset + 2] << 8) + data [offset + 3] ; |
| 65 | -} /* read_int */ |
| 66 | +read_rsrc_int (const SD2_RSRC *prsrc, int offset) |
| 67 | +{ const unsigned char * data = prsrc->rsrc_data ; |
| 68 | + if (offset < 0 || offset + 3 >= prsrc->rsrc_len) |
| 69 | + return 0 ; |
| 70 | + return (data [offset] << 24) + (data [offset + 1] << 16) + (data [offset + 2] << 8) + data [offset + 3] ; |
| 71 | +} /* read_rsrc_int */ |
| 72 | |
| 73 | static inline int |
| 74 | -read_marker (const unsigned char * data, int offset) |
| 75 | -{ |
| 76 | +read_rsrc_marker (const SD2_RSRC *prsrc, int offset) |
| 77 | +{ const unsigned char * data = prsrc->rsrc_data ; |
| 78 | + |
| 79 | + if (offset < 0 || offset + 3 >= prsrc->rsrc_len) |
| 80 | + return 0 ; |
| 81 | + |
| 82 | if (CPU_IS_BIG_ENDIAN) |
| 83 | return (data [offset] << 24) + (data [offset + 1] << 16) + (data [offset + 2] << 8) + data [offset + 3] ; |
| 84 | - else if (CPU_IS_LITTLE_ENDIAN) |
| 85 | + if (CPU_IS_LITTLE_ENDIAN) |
| 86 | return data [offset] + (data [offset + 1] << 8) + (data [offset + 2] << 16) + (data [offset + 3] << 24) ; |
| 87 | - else |
| 88 | - return 0x666 ; |
| 89 | -} /* read_marker */ |
| 90 | + |
| 91 | + return 0 ; |
| 92 | +} /* read_rsrc_marker */ |
| 93 | |
| 94 | static void |
| 95 | -read_str (const unsigned char * data, int offset, char * buffer, int buffer_len) |
| 96 | -{ int k ; |
| 97 | +read_rsrc_str (const SD2_RSRC *prsrc, int offset, char * buffer, int buffer_len) |
| 98 | +{ const unsigned char * data = prsrc->rsrc_data ; |
| 99 | + int k ; |
| 100 | |
| 101 | memset (buffer, 0, buffer_len) ; |
| 102 | |
| 103 | + if (offset < 0 || offset + buffer_len >= prsrc->rsrc_len) |
| 104 | + return ; |
| 105 | + |
| 106 | for (k = 0 ; k < buffer_len - 1 ; k++) |
| 107 | { if (psf_isprint (data [offset + k]) == 0) |
| 108 | return ; |
| 109 | buffer [k] = data [offset + k] ; |
| 110 | } ; |
| 111 | return ; |
| 112 | -} /* read_str */ |
| 113 | +} /* read_rsrc_str */ |
| 114 | |
| 115 | static int |
| 116 | sd2_parse_rsrc_fork (SF_PRIVATE *psf) |
| 117 | @@ -435,17 +452,17 @@ sd2_parse_rsrc_fork (SF_PRIVATE *psf) |
| 118 | /* Reset the header storage because we have changed to the rsrcdes. */ |
| 119 | psf->headindex = psf->headend = rsrc.rsrc_len ; |
| 120 | |
| 121 | - rsrc.data_offset = read_int (rsrc.rsrc_data, 0) ; |
| 122 | - rsrc.map_offset = read_int (rsrc.rsrc_data, 4) ; |
| 123 | - rsrc.data_length = read_int (rsrc.rsrc_data, 8) ; |
| 124 | - rsrc.map_length = read_int (rsrc.rsrc_data, 12) ; |
| 125 | + rsrc.data_offset = read_rsrc_int (&rsrc, 0) ; |
| 126 | + rsrc.map_offset = read_rsrc_int (&rsrc, 4) ; |
| 127 | + rsrc.data_length = read_rsrc_int (&rsrc, 8) ; |
| 128 | + rsrc.map_length = read_rsrc_int (&rsrc, 12) ; |
| 129 | |
| 130 | if (rsrc.data_offset == 0x51607 && rsrc.map_offset == 0x20000) |
| 131 | { psf_log_printf (psf, "Trying offset of 0x52 bytes.\n") ; |
| 132 | - rsrc.data_offset = read_int (rsrc.rsrc_data, 0x52 + 0) + 0x52 ; |
| 133 | - rsrc.map_offset = read_int (rsrc.rsrc_data, 0x52 + 4) + 0x52 ; |
| 134 | - rsrc.data_length = read_int (rsrc.rsrc_data, 0x52 + 8) ; |
| 135 | - rsrc.map_length = read_int (rsrc.rsrc_data, 0x52 + 12) ; |
| 136 | + rsrc.data_offset = read_rsrc_int (&rsrc, 0x52 + 0) + 0x52 ; |
| 137 | + rsrc.map_offset = read_rsrc_int (&rsrc, 0x52 + 4) + 0x52 ; |
| 138 | + rsrc.data_length = read_rsrc_int (&rsrc, 0x52 + 8) ; |
| 139 | + rsrc.map_length = read_rsrc_int (&rsrc, 0x52 + 12) ; |
| 140 | } ; |
| 141 | |
| 142 | psf_log_printf (psf, " data offset : 0x%04X\n map offset : 0x%04X\n" |
| 143 | @@ -488,7 +505,7 @@ sd2_parse_rsrc_fork (SF_PRIVATE *psf) |
| 144 | goto parse_rsrc_fork_cleanup ; |
| 145 | } ; |
| 146 | |
| 147 | - rsrc.string_offset = rsrc.map_offset + read_short (rsrc.rsrc_data, rsrc.map_offset + 26) ; |
| 148 | + rsrc.string_offset = rsrc.map_offset + read_rsrc_short (&rsrc, rsrc.map_offset + 26) ; |
| 149 | if (rsrc.string_offset > rsrc.rsrc_len) |
| 150 | { psf_log_printf (psf, "Bad string offset (%d).\n", rsrc.string_offset) ; |
| 151 | error = SFE_SD2_BAD_RSRC ; |
| 152 | @@ -497,7 +514,7 @@ sd2_parse_rsrc_fork (SF_PRIVATE *psf) |
| 153 | |
| 154 | rsrc.type_offset = rsrc.map_offset + 30 ; |
| 155 | |
| 156 | - rsrc.type_count = read_short (rsrc.rsrc_data, rsrc.map_offset + 28) + 1 ; |
| 157 | + rsrc.type_count = read_rsrc_short (&rsrc, rsrc.map_offset + 28) + 1 ; |
| 158 | if (rsrc.type_count < 1) |
| 159 | { psf_log_printf (psf, "Bad type count.\n") ; |
| 160 | error = SFE_SD2_BAD_RSRC ; |
| 161 | @@ -513,11 +530,11 @@ sd2_parse_rsrc_fork (SF_PRIVATE *psf) |
| 162 | |
| 163 | rsrc.str_index = -1 ; |
| 164 | for (k = 0 ; k < rsrc.type_count ; k ++) |
| 165 | - { marker = read_marker (rsrc.rsrc_data, rsrc.type_offset + k * 8) ; |
| 166 | + { marker = read_rsrc_marker (&rsrc, rsrc.type_offset + k * 8) ; |
| 167 | |
| 168 | if (marker == STR_MARKER) |
| 169 | { rsrc.str_index = k ; |
| 170 | - rsrc.str_count = read_short (rsrc.rsrc_data, rsrc.type_offset + k * 8 + 4) + 1 ; |
| 171 | + rsrc.str_count = read_rsrc_short (&rsrc, rsrc.type_offset + k * 8 + 4) + 1 ; |
| 172 | error = parse_str_rsrc (psf, &rsrc) ; |
| 173 | goto parse_rsrc_fork_cleanup ; |
| 174 | } ; |
| 175 | @@ -549,26 +566,26 @@ parse_str_rsrc (SF_PRIVATE *psf, SD2_RSRC * rsrc) |
| 176 | for (k = 0 ; data_offset + data_len < rsrc->rsrc_len ; k++) |
| 177 | { int slen ; |
| 178 | |
| 179 | - slen = read_char (rsrc->rsrc_data, str_offset) ; |
| 180 | - read_str (rsrc->rsrc_data, str_offset + 1, name, SF_MIN (SIGNED_SIZEOF (name), slen + 1)) ; |
| 181 | + slen = read_rsrc_char (rsrc, str_offset) ; |
| 182 | + read_rsrc_str (rsrc, str_offset + 1, name, SF_MIN (SIGNED_SIZEOF (name), slen + 1)) ; |
| 183 | str_offset += slen + 1 ; |
| 184 | |
| 185 | - rsrc_id = read_short (rsrc->rsrc_data, rsrc->item_offset + k * 12) ; |
| 186 | + rsrc_id = read_rsrc_short (rsrc, rsrc->item_offset + k * 12) ; |
| 187 | |
| 188 | - data_offset = rsrc->data_offset + read_int (rsrc->rsrc_data, rsrc->item_offset + k * 12 + 4) ; |
| 189 | + data_offset = rsrc->data_offset + read_rsrc_int (rsrc, rsrc->item_offset + k * 12 + 4) ; |
| 190 | if (data_offset < 0 || data_offset > rsrc->rsrc_len) |
| 191 | { psf_log_printf (psf, "Exiting parser on data offset of %d.\n", data_offset) ; |
| 192 | break ; |
| 193 | } ; |
| 194 | |
| 195 | - data_len = read_int (rsrc->rsrc_data, data_offset) ; |
| 196 | + data_len = read_rsrc_int (rsrc, data_offset) ; |
| 197 | if (data_len < 0 || data_len > rsrc->rsrc_len) |
| 198 | { psf_log_printf (psf, "Exiting parser on data length of %d.\n", data_len) ; |
| 199 | break ; |
| 200 | } ; |
| 201 | |
| 202 | - slen = read_char (rsrc->rsrc_data, data_offset + 4) ; |
| 203 | - read_str (rsrc->rsrc_data, data_offset + 5, value, SF_MIN (SIGNED_SIZEOF (value), slen + 1)) ; |
| 204 | + slen = read_rsrc_char (rsrc, data_offset + 4) ; |
| 205 | + read_rsrc_str (rsrc, data_offset + 5, value, SF_MIN (SIGNED_SIZEOF (value), slen + 1)) ; |
| 206 | |
| 207 | psf_log_printf (psf, " 0x%04x %4d %4d %3d '%s'\n", data_offset, rsrc_id, data_len, slen, value) ; |
| 208 | |
| 209 | -- |
| 210 | 1.7.9.5 |
| 211 | |