Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/modules/libmar/src/mar_read.c
Warning:line 682, column 30
Access to field 'offset' results in a dereference of a null pointer (loaded from variable 'item')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mar_read.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/modules/libmar/src -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/modules/libmar/src -resource-dir /usr/lib/llvm-18/lib/clang/18 -D XP_UNIX -D DEBUG=1 -I /var/lib/jenkins/workspace/firefox-scan-build/modules/libmar/src -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/modules/libmar/src -I /var/lib/jenkins/workspace/firefox-scan-build/other-licenses/nsis/Contrib/CityHash/cityhash -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -std=gnu11 -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-05-16-034744-15991-1 -x c /var/lib/jenkins/workspace/firefox-scan-build/modules/libmar/src/mar_read.c
1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim:set ts=2 sw=2 sts=2 et cindent: */
3/* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7#include <sys/types.h>
8#include <fcntl.h>
9#include <stdlib.h>
10#include <string.h>
11#include "city.h"
12#include "mar_private.h"
13#include "mar.h"
14#ifdef XP_WIN
15# define strdup _strdup
16#endif
17
18/* This block must be at most 104 bytes.
19 MAR channel name < 64 bytes, and product version < 32 bytes + 3 NULL
20 terminator bytes. We only check for 96 though because we remove 8
21 bytes above from the additionalBlockSize: We subtract
22 sizeof(additionalBlockSize) and sizeof(additionalBlockID) */
23#define MAXADDITIONALBLOCKSIZE96 96
24
25static uint32_t mar_hash_name(const char* name) {
26 return CityHash64(name, strlen(name)) % TABLESIZE256;
27}
28
29static int mar_insert_item(MarFile* mar, const char* name, uint32_t namelen,
30 uint32_t offset, uint32_t length, uint32_t flags) {
31 MarItem *item, *root;
32 uint32_t hash;
33
34 item = (MarItem*)malloc(sizeof(MarItem) + namelen);
35 if (!item) {
36 return -1;
37 }
38 item->next = NULL((void*)0);
39 item->offset = offset;
40 item->length = length;
41 item->flags = flags;
42 memcpy(item->name, name, namelen + 1);
43
44 hash = mar_hash_name(name);
45
46 root = mar->item_table[hash];
47 if (!root) {
48 mar->item_table[hash] = item;
49 } else {
50 /* append item */
51 while (root->next) root = root->next;
52 root->next = item;
53 }
54 return 0;
55}
56
57static int mar_consume_index(MarFile* mar, char** buf, const char* buf_end) {
58 /*
59 * Each item has the following structure:
60 * uint32_t offset (network byte order)
61 * uint32_t length (network byte order)
62 * uint32_t flags (network byte order)
63 * char name[N] (where N >= 1)
64 * char null_byte;
65 */
66 uint32_t offset;
67 uint32_t length;
68 uint32_t flags;
69 const char* name;
70 int namelen;
71
72 if ((buf_end - *buf) < (int)(3 * sizeof(uint32_t) + 2)) {
73 return -1;
74 }
75
76 memcpy(&offset, *buf, sizeof(offset));
77 *buf += sizeof(offset);
78
79 memcpy(&length, *buf, sizeof(length));
80 *buf += sizeof(length);
81
82 memcpy(&flags, *buf, sizeof(flags));
83 *buf += sizeof(flags);
84
85 offset = ntohl(offset)__bswap_32 (offset);
86 length = ntohl(length)__bswap_32 (length);
87 flags = ntohl(flags)__bswap_32 (flags);
88
89 name = *buf;
90 /* find namelen; must take care not to read beyond buf_end */
91 while (**buf) {
92 /* buf_end points one byte past the end of buf's allocation */
93 if (*buf == (buf_end - 1)) {
94 return -1;
95 }
96 ++(*buf);
97 }
98 namelen = (*buf - name);
99 /* must ensure that namelen is valid */
100 if (namelen < 0) {
101 return -1;
102 }
103 /* consume null byte */
104 if (*buf == buf_end) {
105 return -1;
106 }
107 ++(*buf);
108
109 return mar_insert_item(mar, name, namelen, offset, length, flags);
110}
111
112static int mar_read_index(MarFile* mar) {
113 char id[MAR_ID_SIZE4], *buf, *bufptr, *bufend;
114 uint32_t offset_to_index, size_of_index;
115 size_t mar_position = 0;
116
117 /* verify MAR ID */
118 if (mar_read_buffer(mar, id, &mar_position, MAR_ID_SIZE4) != 0) {
119 return -1;
120 }
121 if (memcmp(id, MAR_ID"MAR1", MAR_ID_SIZE4) != 0) {
122 return -1;
123 }
124
125 if (mar_read_buffer(mar, &offset_to_index, &mar_position, sizeof(uint32_t)) !=
126 0) {
127 return -1;
128 }
129 offset_to_index = ntohl(offset_to_index)__bswap_32 (offset_to_index);
130
131 mar_position = 0;
132 if (mar_buffer_seek(mar, &mar_position, offset_to_index) != 0) {
133 return -1;
134 }
135 if (mar_read_buffer(mar, &size_of_index, &mar_position, sizeof(uint32_t)) !=
136 0) {
137 return -1;
138 }
139 size_of_index = ntohl(size_of_index)__bswap_32 (size_of_index);
140
141 buf = (char*)malloc(size_of_index);
142 if (!buf) {
143 return -1;
144 }
145 if (mar_read_buffer(mar, buf, &mar_position, size_of_index) != 0) {
146 free(buf);
147 return -1;
148 }
149
150 bufptr = buf;
151 bufend = buf + size_of_index;
152 while (bufptr < bufend && mar_consume_index(mar, &bufptr, bufend) == 0)
153 ;
154
155 free(buf);
156 return (bufptr == bufend) ? 0 : -1;
157}
158
159/**
160 * Adds an offset and length to the MarFile's index_list
161 * @param mar The MarFile that owns this offset length pair
162 * @param offset The byte offset in the archive to be marked as processed
163 * @param length The length corresponding to this byte offset
164 * @return int 1 on success, 0 if offset has been previously processed
165 * -1 if unable to allocate space for the SeenIndexes
166 */
167static int mar_insert_offset(MarFile* mar, uint32_t offset, uint32_t length) {
168 /* Ignore files with no length */
169 if (length == 0) {
170 return 1;
171 }
172
173 SeenIndex* index = (SeenIndex*)malloc(sizeof(SeenIndex));
174 if (!index) {
175 return -1;
176 }
177 index->next = NULL((void*)0);
178 index->offset = offset;
179 index->length = length;
180 uint32_t index_end = index->offset + index->length - 1;
181
182 /* If this is our first index store it at the front */
183 if (mar->index_list == NULL((void*)0)) {
184 mar->index_list = index;
185 return 1;
186 }
187
188 /* Search for matching indexes in the list of those previously visited */
189 SeenIndex* previous;
190 SeenIndex* current = mar->index_list;
191 while (current != NULL((void*)0)) {
192 uint32_t current_end = current->offset + current->length - 1;
193
194 /* If index has collided with the front or end of current or if current has
195 collided with the front or end of index return false */
196 if ((index->offset >= current->offset && index->offset <= current_end) ||
197 (index_end >= current->offset && index_end <= current_end) ||
198 (current->offset >= index->offset && current->offset <= index_end) ||
199 (current_end >= index->offset && current_end <= index_end)) {
200 free(index);
201 return 0;
202 }
203
204 /* else move to the next in the list */
205 previous = current;
206 current = current->next;
207 }
208
209 /* These indexes are valid, track them */
210 previous->next = index;
211 return 1;
212}
213
214/**
215 * Internal shared code for mar_open and mar_wopen.
216 * Reads the entire MAR into memory. Fails if it is bigger than
217 * MAX_SIZE_OF_MAR_FILE bytes.
218 */
219static MarReadResult mar_fpopen(FILE* fp, MarFile** out_mar) {
220 *out_mar = NULL((void*)0);
221 MarFile* mar;
222
223 mar = (MarFile*)malloc(sizeof(*mar));
224 if (!mar) {
225 return MAR_MEM_ERROR;
226 }
227
228 off_t buffer_size = -1;
229 if (fseeko(fp, 0, SEEK_END2) == 0) {
230 buffer_size = ftello(fp);
231 }
232 rewind(fp);
233 if (buffer_size < 0) {
234 fprintf(stderrstderr, "Warning: MAR size could not be determined\n");
235 buffer_size = MAX_SIZE_OF_MAR_FILE((int64_t)524288000);
236 }
237 if (buffer_size > MAX_SIZE_OF_MAR_FILE((int64_t)524288000)) {
238 fprintf(stderrstderr, "ERROR: MAR exceeds maximum size (%lli)\n",
239 (long long int)buffer_size);
240 free(mar);
241 return MAR_FILE_TOO_BIG_ERROR;
242 }
243
244 mar->buffer = malloc(buffer_size);
245 if (!mar->buffer) {
246 fprintf(stderrstderr, "ERROR: MAR buffer could not be allocated\n");
247 free(mar);
248 return MAR_MEM_ERROR;
249 }
250 mar->data_len = fread(mar->buffer, 1, buffer_size, fp);
251 if (fgetc(fp) != EOF(-1)) {
252 fprintf(stderrstderr, "ERROR: File is larger than buffer (%lli)\n",
253 (long long int)buffer_size);
254 free(mar->buffer);
255 free(mar);
256 return MAR_IO_ERROR;
257 }
258 if (ferror(fp)) {
259 fprintf(stderrstderr, "ERROR: Failed to read MAR\n");
260 free(mar->buffer);
261 free(mar);
262 return MAR_IO_ERROR;
263 }
264
265 mar->item_table_is_valid = 0;
266 memset(mar->item_table, 0, sizeof(mar->item_table));
267 mar->index_list = NULL((void*)0);
268
269 *out_mar = mar;
270 return MAR_READ_SUCCESS;
271}
272
273MarReadResult mar_open(const char* path, MarFile** out_mar) {
274 *out_mar = NULL((void*)0);
275
276 FILE* fp;
277
278 fp = fopen(path, "rb");
279 if (!fp) {
280 fprintf(stderrstderr, "ERROR: could not open file in mar_open()\n");
281 perror(path);
282 return MAR_IO_ERROR;
283 }
284
285 MarReadResult result = mar_fpopen(fp, out_mar);
286 fclose(fp);
287 return result;
288}
289
290#ifdef XP_WIN
291MarReadResult mar_wopen(const wchar_t* path, MarFile** out_mar) {
292 *out_mar = NULL((void*)0);
293
294 FILE* fp;
295
296 _wfopen_s(&fp, path, L"rb");
297 if (!fp) {
298 fprintf(stderrstderr, "ERROR: could not open file in mar_wopen()\n");
299 _wperror(path);
300 return MAR_IO_ERROR;
301 }
302
303 MarReadResult result = mar_fpopen(fp, out_mar);
304 fclose(fp);
305 return result;
306}
307#endif
308
309void mar_close(MarFile* mar) {
310 MarItem* item;
311 SeenIndex* index;
312 int i;
313
314 free(mar->buffer);
315
316 for (i = 0; i < TABLESIZE256; ++i) {
317 item = mar->item_table[i];
318 while (item) {
319 MarItem* temp = item;
320 item = item->next;
321 free(temp);
322 }
323 }
324
325 while (mar->index_list != NULL((void*)0)) {
326 index = mar->index_list;
327 mar->index_list = index->next;
328 free(index);
329 }
330
331 free(mar);
332}
333
334int mar_read_buffer(MarFile* mar, void* dest, size_t* position, size_t size) {
335 // size may be provided by the MAR, which we may not have finished validating
336 // the signature on yet. Make sure not to trust it in a way that could
337 // cause an overflow.
338 if (size > mar->data_len) {
339 return -1;
340 }
341 if (*position > mar->data_len - size) {
342 return -1;
343 }
344 memcpy(dest, mar->buffer + *position, size);
345 *position += size;
346 return 0;
347}
348
349int mar_read_buffer_max(MarFile* mar, void* dest, size_t* position,
350 size_t size) {
351 // size may be provided by the MAR, which we may not have finished validating
352 // the signature on yet. Make sure not to trust it in a way that could
353 // cause an overflow.
354 if (mar->data_len <= *position) {
355 return 0;
356 }
357 size_t read_count = mar->data_len - *position;
358 if (read_count > size) {
359 read_count = size;
360 }
361 memcpy(dest, mar->buffer + *position, read_count);
362 *position += read_count;
363 return read_count;
364}
365
366int mar_buffer_seek(MarFile* mar, size_t* position, size_t distance) {
367 // distance may be provided by the MAR, which we may not have finished
368 // validating the signature on yet. Make sure not to trust it in a way that
369 // could cause an overflow.
370 if (distance > mar->data_len) {
371 return -1;
372 }
373 if (*position > mar->data_len - distance) {
374 return -1;
375 }
376 *position += distance;
377 return 0;
378}
379
380/**
381 * Determines the MAR file information.
382 *
383 * @param mar An open MAR file.
384 * @param mar_position The current position in the MAR.
385 * Its value will be updated to the current
386 * position in the MAR after the function exits.
387 * Since its initial value will never actually be
388 * used, this is effectively an outparam.
389 * @param hasSignatureBlock Optional out parameter specifying if the MAR
390 * file has a signature block or not.
391 * @param numSignatures Optional out parameter for storing the number
392 * of signatures in the MAR file.
393 * @param hasAdditionalBlocks Optional out parameter specifying if the MAR
394 * file has additional blocks or not.
395 * @param offsetAdditionalBlocks Optional out parameter for the offset to the
396 * first additional block. Value is only valid if
397 * hasAdditionalBlocks is not equal to 0.
398 * @param numAdditionalBlocks Optional out parameter for the number of
399 * additional blocks. Value is only valid if
400 * hasAdditionalBlocks is not equal to 0.
401 * @return 0 on success and non-zero on failure.
402 */
403int get_open_mar_file_info(MarFile* mar, size_t* mar_position,
404 int* hasSignatureBlock, uint32_t* numSignatures,
405 int* hasAdditionalBlocks,
406 uint32_t* offsetAdditionalBlocks,
407 uint32_t* numAdditionalBlocks) {
408 uint32_t offsetToIndex, offsetToContent, signatureCount, signatureLen, i;
409
410 /* One of hasSignatureBlock or hasAdditionalBlocks must be non NULL */
411 if (!hasSignatureBlock && !hasAdditionalBlocks) {
412 return -1;
413 }
414
415 /* Skip to the start of the offset index */
416 *mar_position = 0;
417 if (mar_buffer_seek(mar, mar_position, MAR_ID_SIZE4) != 0) {
418 return -1;
419 }
420
421 /* Read the offset to the index. */
422 if (mar_read_buffer(mar, &offsetToIndex, mar_position,
423 sizeof(offsetToIndex)) != 0) {
424 return -1;
425 }
426 offsetToIndex = ntohl(offsetToIndex)__bswap_32 (offsetToIndex);
427
428 if (numSignatures) {
429 /* Skip past the MAR file size field */
430 if (mar_buffer_seek(mar, mar_position, sizeof(uint64_t)) != 0) {
431 return -1;
432 }
433
434 /* Read the number of signatures field */
435 if (mar_read_buffer(mar, numSignatures, mar_position,
436 sizeof(*numSignatures)) != 0) {
437 return -1;
438 }
439 *numSignatures = ntohl(*numSignatures)__bswap_32 (*numSignatures);
440 }
441
442 /* Skip to the first index entry past the index size field
443 We do it in 2 calls because offsetToIndex + sizeof(uint32_t)
444 could overflow in theory. */
445 *mar_position = 0;
446 if (mar_buffer_seek(mar, mar_position, offsetToIndex) != 0) {
447 return -1;
448 }
449
450 if (mar_buffer_seek(mar, mar_position, sizeof(uint32_t)) != 0) {
451 return -1;
452 }
453
454 /* Read the first offset to content field. */
455 if (mar_read_buffer(mar, &offsetToContent, mar_position,
456 sizeof(offsetToContent)) != 0) {
457 return -1;
458 }
459 offsetToContent = ntohl(offsetToContent)__bswap_32 (offsetToContent);
460
461 /* Check if we have a new or old MAR file */
462 if (hasSignatureBlock) {
463 if (offsetToContent == MAR_ID_SIZE4 + sizeof(uint32_t)) {
464 *hasSignatureBlock = 0;
465 } else {
466 *hasSignatureBlock = 1;
467 }
468 }
469
470 /* If the caller doesn't care about the product info block
471 value, then just return */
472 if (!hasAdditionalBlocks) {
473 return 0;
474 }
475
476 /* Skip to the start of the signature block */
477 *mar_position = 0;
478 if (mar_buffer_seek(mar, mar_position, SIGNATURE_BLOCK_OFFSET16) != 0) {
479 return -1;
480 }
481
482 /* Get the number of signatures */
483 if (mar_read_buffer(mar, &signatureCount, mar_position,
484 sizeof(signatureCount)) != 0) {
485 return -1;
486 }
487 signatureCount = ntohl(signatureCount)__bswap_32 (signatureCount);
488
489 /* Check that we have less than the max amount of signatures so we don't
490 waste too much of either updater's or signmar's time. */
491 if (signatureCount > MAX_SIGNATURES8) {
492 return -1;
493 }
494
495 /* Skip past the whole signature block */
496 for (i = 0; i < signatureCount; i++) {
497 /* Skip past the signature algorithm ID */
498 if (mar_buffer_seek(mar, mar_position, sizeof(uint32_t)) != 0) {
499 return -1;
500 }
501
502 /* Read the signature length and skip past the signature */
503 if (mar_read_buffer(mar, &signatureLen, mar_position, sizeof(uint32_t)) !=
504 0) {
505 return -1;
506 }
507 signatureLen = ntohl(signatureLen)__bswap_32 (signatureLen);
508 if (mar_buffer_seek(mar, mar_position, signatureLen) != 0) {
509 return -1;
510 }
511 }
512
513 if (*mar_position <= (size_t)INT64_MAX(9223372036854775807L) &&
514 (int64_t)mar_position == (int64_t)offsetToContent) {
515 *hasAdditionalBlocks = 0;
516 } else {
517 if (numAdditionalBlocks) {
518 /* We have an additional block, so read in the number of additional blocks
519 and set the offset. */
520 *hasAdditionalBlocks = 1;
521 if (mar_read_buffer(mar, numAdditionalBlocks, mar_position,
522 sizeof(uint32_t)) != 0) {
523 return -1;
524 }
525 *numAdditionalBlocks = ntohl(*numAdditionalBlocks)__bswap_32 (*numAdditionalBlocks);
526 if (offsetAdditionalBlocks) {
527 if (*mar_position > (size_t)UINT32_MAX(4294967295U)) {
528 return -1;
529 }
530 *offsetAdditionalBlocks = (uint32_t)*mar_position;
531 }
532 } else if (offsetAdditionalBlocks) {
533 /* numAdditionalBlocks is not specified but offsetAdditionalBlocks
534 is, so fill it! */
535 if (mar_buffer_seek(mar, mar_position, sizeof(uint32_t)) != 0) {
536 return -1;
537 }
538 if (*mar_position > (size_t)UINT32_MAX(4294967295U)) {
539 return -1;
540 }
541 *offsetAdditionalBlocks = (uint32_t)*mar_position;
542 }
543 }
544
545 return 0;
546}
547
548/**
549 * Reads the product info block from the MAR file's additional block section.
550 * The caller is responsible for freeing the fields in infoBlock
551 * if the return is successful.
552 *
553 * @param infoBlock Out parameter for where to store the result to
554 * @return 0 on success, -1 on failure
555 */
556int read_product_info_block(char* path,
557 struct ProductInformationBlock* infoBlock) {
558 int rv;
559 MarFile* mar;
560 MarReadResult result = mar_open(path, &mar);
561 if (result != MAR_READ_SUCCESS) {
562 fprintf(stderrstderr,
563 "ERROR: could not open file in read_product_info_block()\n");
564 return -1;
565 }
566 rv = mar_read_product_info_block(mar, infoBlock);
567 mar_close(mar);
568 return rv;
569}
570
571/**
572 * Reads the product info block from the MAR file's additional block section.
573 * The caller is responsible for freeing the fields in infoBlock
574 * if the return is successful.
575 *
576 * @param infoBlock Out parameter for where to store the result to
577 * @return 0 on success, -1 on failure
578 */
579int mar_read_product_info_block(MarFile* mar,
580 struct ProductInformationBlock* infoBlock) {
581 uint32_t offsetAdditionalBlocks, numAdditionalBlocks, additionalBlockSize,
582 additionalBlockID;
583 int hasAdditionalBlocks;
584 size_t mar_position = 0;
585
586 /* The buffer size is 97 bytes because the MAR channel name < 64 bytes, and
587 product version < 32 bytes + 3 NULL terminator bytes. */
588 char buf[MAXADDITIONALBLOCKSIZE96 + 1] = {'\0'};
589 if (get_open_mar_file_info(mar, &mar_position, NULL((void*)0), NULL((void*)0),
590 &hasAdditionalBlocks, &offsetAdditionalBlocks,
591 &numAdditionalBlocks) != 0) {
592 return -1;
593 }
594
595 /* We only have the one additional block type and only one is expected to be
596 in a MAR file so check if any exist and process the first found */
597 if (numAdditionalBlocks > 0) {
598 /* Read the additional block size */
599 if (mar_read_buffer(mar, &additionalBlockSize, &mar_position,
600 sizeof(additionalBlockSize)) != 0) {
601 return -1;
602 }
603 additionalBlockSize = ntohl(additionalBlockSize)__bswap_32 (additionalBlockSize) -
604 sizeof(additionalBlockSize) -
605 sizeof(additionalBlockID);
606
607 /* Additional Block sizes should only be 96 bytes long */
608 if (additionalBlockSize > MAXADDITIONALBLOCKSIZE96) {
609 return -1;
610 }
611
612 /* Read the additional block ID */
613 if (mar_read_buffer(mar, &additionalBlockID, &mar_position,
614 sizeof(additionalBlockID)) != 0) {
615 return -1;
616 }
617 additionalBlockID = ntohl(additionalBlockID)__bswap_32 (additionalBlockID);
618
619 if (PRODUCT_INFO_BLOCK_ID1 == additionalBlockID) {
620 const char* location;
621 int len;
622
623 if (mar_read_buffer(mar, buf, &mar_position, additionalBlockSize) != 0) {
624 return -1;
625 }
626
627 /* Extract the MAR channel name from the buffer. For now we
628 point to the stack allocated buffer but we strdup this
629 if we are within bounds of each field's max length. */
630 location = buf;
631 len = strlen(location);
632 infoBlock->MARChannelID = location;
633 location += len + 1;
634 if (len >= 64) {
635 infoBlock->MARChannelID = NULL((void*)0);
636 return -1;
637 }
638
639 /* Extract the version from the buffer */
640 len = strlen(location);
641 infoBlock->productVersion = location;
642 if (len >= 32) {
643 infoBlock->MARChannelID = NULL((void*)0);
644 infoBlock->productVersion = NULL((void*)0);
645 return -1;
646 }
647 infoBlock->MARChannelID = strdup(infoBlock->MARChannelID);
648 infoBlock->productVersion = strdup(infoBlock->productVersion);
649 return 0;
650 } else {
651 /* This is not the additional block you're looking for. Move along. */
652 if (mar_buffer_seek(mar, &mar_position, additionalBlockSize) != 0) {
653 return -1;
654 }
655 }
656 }
657
658 /* If we had a product info block we would have already returned */
659 return -1;
660}
661
662const MarItem* mar_find_item(MarFile* mar, const char* name) {
663 uint32_t hash;
664 const MarItem* item;
665
666 if (!mar->item_table_is_valid) {
1
Assuming field 'item_table_is_valid' is not equal to 0
2
Taking false branch
667 if (mar_read_index(mar)) {
668 return NULL((void*)0);
669 } else {
670 mar->item_table_is_valid = 1;
671 }
672 }
673
674 hash = mar_hash_name(name);
3
Value assigned to 'hash'
675
676 item = mar->item_table[hash];
4
Value assigned to 'item'
677 while (item && strcmp(item->name, name) != 0) {
5
Assuming 'item' is null
678 item = item->next;
679 }
680
681 /* If this is the first time seeing this item's indexes, return it */
682 if (mar_insert_offset(mar, item->offset, item->length) == 1) {
6
Access to field 'offset' results in a dereference of a null pointer (loaded from variable 'item')
683 return item;
684 } else {
685 fprintf(stderrstderr, "ERROR: file content collision in mar_find_item()\n");
686 return NULL((void*)0);
687 }
688}
689
690int mar_enum_items(MarFile* mar, MarItemCallback callback, void* closure) {
691 MarItem* item;
692 int i, rv;
693
694 if (!mar->item_table_is_valid) {
695 if (mar_read_index(mar)) {
696 return -1;
697 } else {
698 mar->item_table_is_valid = 1;
699 }
700 }
701
702 for (i = 0; i < TABLESIZE256; ++i) {
703 item = mar->item_table[i];
704 while (item) {
705 /* if this is the first time seeing this item's indexes, process it */
706 if (mar_insert_offset(mar, item->offset, item->length) == 1) {
707 rv = callback(mar, item, closure);
708 if (rv) {
709 return rv;
710 }
711 } else {
712 fprintf(stderrstderr, "ERROR: file content collision in mar_enum_items()\n");
713 return 1;
714 }
715 item = item->next;
716 }
717 }
718
719 return 0;
720}
721
722int mar_read(MarFile* mar, const MarItem* item, int offset, uint8_t* buf,
723 int bufsize) {
724 int nr;
725 size_t mar_position = 0;
726
727 if (offset == (int)item->length) {
728 return 0;
729 }
730 if (offset > (int)item->length) {
731 return -1;
732 }
733
734 nr = item->length - offset;
735 if (nr > bufsize) {
736 nr = bufsize;
737 }
738
739 // Avoid adding item->offset and offset directly, just in case of overflow.
740 if (mar_buffer_seek(mar, &mar_position, item->offset)) {
741 return -1;
742 }
743 if (mar_buffer_seek(mar, &mar_position, offset)) {
744 return -1;
745 }
746
747 return mar_read_buffer_max(mar, buf, &mar_position, nr);
748}
749
750/**
751 * Determines the MAR file information.
752 *
753 * @param path The path of the MAR file to check.
754 * @param hasSignatureBlock Optional out parameter specifying if the MAR
755 * file has a signature block or not.
756 * @param numSignatures Optional out parameter for storing the number
757 * of signatures in the MAR file.
758 * @param hasAdditionalBlocks Optional out parameter specifying if the MAR
759 * file has additional blocks or not.
760 * @param offsetAdditionalBlocks Optional out parameter for the offset to the
761 * first additional block. Value is only valid if
762 * hasAdditionalBlocks is not equal to 0.
763 * @param numAdditionalBlocks Optional out parameter for the number of
764 * additional blocks. Value is only valid if
765 * has_additional_blocks is not equal to 0.
766 * @return 0 on success and non-zero on failure.
767 */
768int get_mar_file_info(const char* path, int* hasSignatureBlock,
769 uint32_t* numSignatures, int* hasAdditionalBlocks,
770 uint32_t* offsetAdditionalBlocks,
771 uint32_t* numAdditionalBlocks) {
772 int rv;
773 MarFile* mar;
774 size_t mar_position = 0;
775 MarReadResult result = mar_open(path, &mar);
776 if (result != MAR_READ_SUCCESS) {
777 fprintf(stderrstderr, "ERROR: could not read file in get_mar_file_info()\n");
778 return -1;
779 }
780
781 rv = get_open_mar_file_info(mar, &mar_position, hasSignatureBlock,
782 numSignatures, hasAdditionalBlocks,
783 offsetAdditionalBlocks, numAdditionalBlocks);
784
785 mar_close(mar);
786 return rv;
787}