Bug Summary

File:build-analysis/../src/plugins/asf/libasf/parse.c
Warning:line 264, column 7
Potential leak of memory pointed to by 'current'

Annotated Source Code

1/* libasf - An Advanced Systems Format media file parser
2 * Copyright (C) 2006-2010 Juho Vähä-Herttua
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19#include <stdlib.h>
20#include <string.h>
21
22#include "asf.h"
23#include "asfint.h"
24#include "byteio.h"
25#include "header.h"
26#include "guid.h"
27#include "debug.h"
28#include "parse.h"
29
30/**
31 * Read next object from buffer pointed by data. Notice that
32 * no buffer overflow checks are done! This function always
33 * expects to have 24 bytes available, which is the size of
34 * the object header (GUID + data size)
35 */
36static void
37asf_parse_read_object(asfint_object_t *obj, uint8_t *data)
38{
39 GetGUID(data, &obj->guid);
40 obj->type = asf_guid_get_type(&obj->guid);
41 obj->size = GetQWLE(data + 16);
42 obj->full_data = data;
43 obj->datalen = 0;
44 obj->data = NULL((void*)0);
45 obj->next = NULL((void*)0);
46
47 if (obj->type == GUID_UNKNOWN) {
48 debug_printf("unknown object: %x-%x-%x-%02x%02x%02x%02x%02x%02x%02x%02x, %ld bytes",
49 obj->guid.v1, obj->guid.v2, obj->guid.v3, obj->guid.v4[0],
50 obj->guid.v4[1], obj->guid.v4[2], obj->guid.v4[3], obj->guid.v4[4],
51 obj->guid.v4[5], obj->guid.v4[6], obj->guid.v4[7], (long) obj->size);
52 }
53}
54
55/**
56 * Parse header extension object. Takes a pointer to a newly allocated
57 * header extension structure, a pointer to the data buffer and the
58 * length of the data buffer as its parameters. Subobject contents are
59 * not parsed, but they are added as a linked list to the header object.
60 */
61static int
62asf_parse_headerext(asf_object_headerext_t *header, uint8_t *buf)
63{
64 uint64_t datalen;
65 uint8_t *data;
66
67 if (header->size < 46) {
68 /* invalide size for headerext */
69 return ASF_ERROR_INVALID_OBJECT_SIZE;
70 }
71
72 /* Read reserved and datalen fields from the buffer */
73 GetGUID(buf + 24, &header->reserved1);
74 header->reserved2 = GetWLE(buf + 40);
75 header->datalen = GetDWLE(buf + 42);
76
77 if (header->datalen != header->size - 46) {
78 /* invalid header extension data length value */
79 return ASF_ERROR_INVALID_LENGTH;
80 }
81 header->data = buf + 46;
82
83 debug_printf("parsing header extension subobjects");
84
85 datalen = header->datalen;
86 data = header->data;
87 while (datalen > 0) {
88 asfint_object_t *current;
89
90 if (datalen < 24) {
91 /* not enough data for reading a new object */
92 break;
93 }
94
95 /* Allocate a new subobject */
96 current = malloc(sizeof(asfint_object_t));
97 if (!current) {
98 return ASF_ERROR_OUTOFMEM;
99 }
100
101 asf_parse_read_object(current, data);
102 if (current->size > datalen || current->size < 24) {
103 /* invalid object size */
104 break;
105 }
106 current->datalen = current->size - 24;
107 current->data = data + 24;
108
109 /* add to the list of subobjects */
110 if (!header->first) {
111 header->first = current;
112 header->last = current;
113 } else {
114 header->last->next = current;
115 header->last = current;
116 }
117
118 data += current->size;
119 datalen -= current->size;
120 }
121
122 if (datalen != 0) {
123 /* not enough data for reading the whole object */
124 return ASF_ERROR_INVALID_LENGTH;
125 }
126
127 debug_printf("header extension subobjects parsed successfully");
128
129 return header->size;
130}
131
132/**
133 * Takes an initialized asf_file_t structure file as a parameter. Allocates
134 * a new asf_object_header_t in file->header and uses the file->iostream to
135 * read all fields and subobjects into it. Finally calls the
136 * asf_parse_header_validate function to validate the values and parse the
137 * commonly used values into the asf_file_t struct itself.
138 */
139int
140asf_parse_header(asf_file_t *file)
141{
142 asf_object_header_t *header;
143 asf_iostream_t *iostream;
144 uint8_t hdata[30];
145 int tmp;
146
147 file->header = NULL((void*)0);
148 iostream = &file->iostream;
149
150 /* object minimum is 24 bytes and header needs to have
151 * the subobject count field and two reserved fields */
152 tmp = asf_byteio_read(iostream, hdata, 30);
153 if (tmp < 0) {
1
Assuming 'tmp' is >= 0
2
Taking false branch
154 /* not enough data to read the header object */
155 return tmp;
156 }
157
158 file->header = malloc(sizeof(asf_object_header_t));
159 header = file->header;
160 if (!header) {
3
Assuming 'header' is non-null
4
Taking false branch
161 return ASF_ERROR_OUTOFMEM;
162 }
163
164 /* read the object and check its size value */
165 asf_parse_read_object((asfint_object_t *) header, hdata);
166 if (header->size < 30) {
5
Assuming the condition is false
6
Taking false branch
167 /* invalid size for header object */
168 return ASF_ERROR_INVALID_OBJECT_SIZE;
169 }
170
171 /* read header object specific compulsory fields */
172 header->subobjects = GetDWLE(hdata + 24);
173 header->reserved1 = hdata[28];
174 header->reserved2 = hdata[29];
175
176 /* clear header extension object and subobject list */
177 header->ext = NULL((void*)0);
178 header->first = NULL((void*)0);
179 header->last = NULL((void*)0);
180
181 /* the header data needs to be allocated for reading */
182 header->datalen = header->size - 30;
183 header->data = malloc(header->datalen * sizeof(uint8_t));
184 if (!header->data) {
7
Assuming the condition is false
8
Taking false branch
185 return ASF_ERROR_OUTOFMEM;
186 }
187
188 tmp = asf_byteio_read(iostream, header->data, header->datalen);
189 if (tmp < 0) {
9
Assuming 'tmp' is >= 0
10
Taking false branch
190 return tmp;
191 }
192
193 if (header->subobjects > 0) {
11
Assuming the condition is true
12
Taking true branch
194 uint64_t datalen;
195 uint8_t *data;
196 int i;
197
198 debug_printf("starting to read subobjects");
199
200 /* use temporary variables for use during the read */
201 datalen = header->datalen;
202 data = header->data;
203 for (i=0; i<header->subobjects; i++) {
13
Loop condition is true. Entering loop body
204 asfint_object_t *current;
205
206 if (datalen < 24) {
14
Assuming 'datalen' is >= 24
15
Taking false branch
207 /* not enough data for reading object */
208 break;
209 }
210
211 current = malloc(sizeof(asfint_object_t));
16
Memory is allocated
212 if (!current) {
17
Assuming 'current' is non-null
18
Taking false branch
213 return ASF_ERROR_OUTOFMEM;
214 }
215
216 asf_parse_read_object(current, data);
217 if (current->size > datalen || current->size < 24) {
218 /* invalid object size */
219 break;
19
Execution continues on line 264
220 }
221
222 /* Check if the current subobject is a header extension
223 * object or just a normal subobject */
224 if (current->type == GUID_HEADER_EXTENSION && !header->ext) {
225 int ret;
226 asf_object_headerext_t *headerext;
227
228 /* we handle header extension separately because it has
229 * some subobjects as well */
230 current = realloc(current, sizeof(asf_object_headerext_t));
231 headerext = (asf_object_headerext_t *) current;
232 headerext->first = NULL((void*)0);
233 headerext->last = NULL((void*)0);
234 ret = asf_parse_headerext(headerext, data);
235
236 if (ret < 0) {
237 /* error parsing header extension */
238 return ret;
239 }
240
241 header->ext = headerext;
242 } else {
243 if (current->type == GUID_HEADER_EXTENSION) {
244 debug_printf("WARNING! Second header extension object found, ignoring it!");
245 }
246
247 current->datalen = current->size - 24;
248 current->data = data + 24;
249
250 /* add to list of subobjects */
251 if (!header->first) {
252 header->first = current;
253 header->last = current;
254 } else {
255 header->last->next = current;
256 header->last = current;
257 }
258 }
259
260 data += current->size;
261 datalen -= current->size;
262 }
263
264 if (i != header->subobjects || datalen != 0) {
20
Potential leak of memory pointed to by 'current'
265 /* header data size doesn't match given subobject count */
266 return ASF_ERROR_INVALID_VALUE;
267 }
268
269 debug_printf("%d subobjects read successfully", i);
270 }
271
272 tmp = asf_parse_header_validate(file, file->header);
273 if (tmp < 0) {
274 /* header read ok but doesn't validate correctly */
275 return tmp;
276 }
277
278 debug_printf("header validated correctly");
279
280 return header->size;
281}
282
283/**
284 * Takes an initialized asf_file_t structure file as a parameter. Allocates
285 * a new asf_object_data_t in file->data and uses the file->iostream to
286 * read all its compulsory fields into it. Notice that the actual data is
287 * not read in any way, because we need to be able to work with non-seekable
288 * streams as well.
289 */
290int
291asf_parse_data(asf_file_t *file)
292{
293 asf_object_data_t *data;
294 asf_iostream_t *iostream;
295 uint8_t ddata[50];
296 int tmp;
297
298 file->data = NULL((void*)0);
299 iostream = &file->iostream;
300
301 /* object minimum is 24 bytes and data object needs to have
302 * 26 additional bytes for its internal fields */
303 tmp = asf_byteio_read(iostream, ddata, 50);
304 if (tmp < 0) {
305 return tmp;
306 }
307
308 file->data = malloc(sizeof(asf_object_data_t));
309 data = file->data;
310 if (!data) {
311 return ASF_ERROR_OUTOFMEM;
312 }
313
314 /* read the object and check its size value */
315 asf_parse_read_object((asfint_object_t *) data, ddata);
316 if (data->size < 50) {
317 /* invalid size for data object */
318 return ASF_ERROR_INVALID_OBJECT_SIZE;
319 }
320
321 /* read data object specific compulsory fields */
322 GetGUID(ddata + 24, &data->file_id);
323 data->total_data_packets = GetQWLE(ddata + 40);
324 data->reserved = GetWLE(ddata + 48);
325 data->packets_position = file->position + 50;
326
327 /* If the file_id GUID in data object doesn't match the
328 * file_id GUID in headers, the file is corrupted */
329 if (!asf_guid_equals(&data->file_id, &file->file_id)) {
330 return ASF_ERROR_INVALID_VALUE;
331 }
332
333 /* if data->total_data_packets is non-zero (not a stream) and
334 the data packets count doesn't match, return error */
335 if (data->total_data_packets &&
336 data->total_data_packets != file->data_packets_count) {
337 return ASF_ERROR_INVALID_VALUE;
338 }
339
340 return 50;
341}
342
343/**
344 * Takes an initialized asf_file_t structure file as a parameter. Allocates
345 * a new asf_object_index_t in file->index and uses the file->iostream to
346 * read all its compulsory fields into it. Notice that the actual data is
347 * not read in any way, because we need to be able to work with non-seekable
348 * streams as well.
349 */
350int
351asf_parse_index(asf_file_t *file)
352{
353 asf_object_index_t *index;
354 asf_iostream_t *iostream;
355 uint8_t idata[56];
356 uint64_t entry_data_size;
357 uint8_t *entry_data = NULL((void*)0);
358 uint32_t i;
359 int tmp;
360
361 file->index = NULL((void*)0);
362 iostream = &file->iostream;
363
364 /* read the raw data of an index header */
365 tmp = asf_byteio_read(iostream, idata, 56);
366 if (tmp < 0) {
367 return tmp;
368 }
369
370 /* allocate the index object */
371 index = malloc(sizeof(asf_object_index_t));
372 if (!index) {
373 return ASF_ERROR_OUTOFMEM;
374 }
375
376 asf_parse_read_object((asfint_object_t *) index, idata);
377 if (index->type != GUID_INDEX) {
378 tmp = index->size;
379 free(index);
380
381 /* The guid type was wrong, just return the bytes to skip */
382 return tmp;
383 }
384
385 if (index->size < 56) {
386 /* invalid size for index object */
387 free(index);
388 return ASF_ERROR_INVALID_OBJECT_SIZE;
389 }
390
391 GetGUID(idata + 24, &index->file_id);
392 index->entry_time_interval = GetQWLE(idata + 40);
393 index->max_packet_count = GetDWLE(idata + 48);
394 index->entry_count = GetDWLE(idata + 52);
395
396 if (index->entry_count * 6 + 56 > index->size) {
397 free(index);
398 return ASF_ERROR_INVALID_LENGTH;
399 }
400
401 entry_data_size = index->entry_count * 6;
402 entry_data = malloc(entry_data_size * sizeof(uint8_t));
403 if (!entry_data) {
404 free(index);
405 return ASF_ERROR_OUTOFMEM;
406 }
407 tmp = asf_byteio_read(iostream, entry_data, entry_data_size);
408 if (tmp < 0) {
409 free(index);
410 free(entry_data);
411 return tmp;
412 }
413
414 index->entries = malloc(index->entry_count * sizeof(asf_index_entry_t));
415 if (!index->entries) {
416 free(index);
417 free(entry_data);
418 return ASF_ERROR_OUTOFMEM;
419 }
420
421 for (i=0; i<index->entry_count; i++) {
422 index->entries[i].packet_index = GetDWLE(entry_data + i*6);
423 index->entries[i].packet_count = GetWLE(entry_data + i*6 + 4);
424 }
425
426 free(entry_data);
427 file->index = index;
428
429 return index->size;
430}