blob: cd48710fb7a507cc551fbc4426c5ad622c6da100 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001From 9341e9c6e70cd3ad76c901c3cf052d4cb52fd827 Mon Sep 17 00:00:00 2001
2From: Erik de Castro Lopo <erikd@mega-nerd.com>
3Date: Thu, 27 Jun 2013 18:04:03 +1000
4Subject: [PATCH] src/sd2.c : Fix segfault in SD2 RSRC parser.
5
6(Upstream commit 9341e9c6e70cd3ad76c901c3cf052d4cb52fd827)
7
8A specially crafted resource fork for an SD2 file can cause
9the SD2 RSRC parser to read data from outside a dynamically
10defined buffer. The data that is read is converted into a
11short or int and used during further processing.
12
13Since no write occurs, this is unlikely to be exploitable.
14
15Bug reported by The Mayhem Team from Cylab, Carnegie Mellon
16Univeristy. Paper is:
17http://users.ece.cmu.edu/~arebert/papers/mayhem-oakland-12.pdf
18
19Upstream-Status: Backport
20
21Signed-off-by: Yue Tao <yue.tao@windriver.com>
22---
23 src/sd2.c | 93 ++++++++++++++++++++++++++++++++++++-------------------------
24 1 file changed, 55 insertions(+), 38 deletions(-)
25
26diff --git a/src/sd2.c b/src/sd2.c
27index 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--
2101.7.9.5
211