Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/modules/libmar/src/mar_read.c
Warning:line 681, 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/14/../../../../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-07-27-022226-2793976-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 free(buf);
155 return (bufptr == bufend) ? 0 : -1;
156}
157
158/**
159 * Adds an offset and length to the MarFile's index_list
160 * @param mar The MarFile that owns this offset length pair
161 * @param offset The byte offset in the archive to be marked as processed
162 * @param length The length corresponding to this byte offset
163 * @return int 1 on success, 0 if offset has been previously processed
164 * -1 if unable to allocate space for the SeenIndexes
165 */
166static int mar_insert_offset(MarFile* mar, uint32_t offset, uint32_t length) {
167 /* Ignore files with no length */
168 if (length == 0) {
169 return 1;
170 }
171
172 SeenIndex* index = (SeenIndex*)malloc(sizeof(SeenIndex));
173 if (!index) {
174 return -1;
175 }
176 index->next = NULL((void*)0);
177 index->offset = offset;
178 index->length = length;
179 uint32_t index_end = index->offset + index->length - 1;
180
181 /* If this is our first index store it at the front */
182 if (mar->index_list == NULL((void*)0)) {
183 mar->index_list = index;
184 return 1;
185 }
186
187 /* Search for matching indexes in the list of those previously visited */
188 SeenIndex* previous;
189 SeenIndex* current = mar->index_list;
190 while (current != NULL((void*)0)) {
191 uint32_t current_end = current->offset + current->length - 1;
192
193 /* If index has collided with the front or end of current or if current has
194 collided with the front or end of index return false */
195 if ((index->offset >= current->offset && index->offset <= current_end) ||
196 (index_end >= current->offset && index_end <= current_end) ||
197 (current->offset >= index->offset && current->offset <= index_end) ||
198 (current_end >= index->offset && current_end <= index_end)) {
199 free(index);
200 return 0;
201 }
202
203 /* else move to the next in the list */
204 previous = current;
205 current = current->next;
206 }
207
208 /* These indexes are valid, track them */
209 previous->next = index;
210 return 1;
211}
212
213/**
214 * Internal shared code for mar_open and mar_wopen.
215 * Reads the entire MAR into memory. Fails if it is bigger than
216 * MAX_SIZE_OF_MAR_FILE bytes.
217 */
218static MarReadResult mar_fpopen(FILE* fp, MarFile** out_mar) {
219 *out_mar = NULL((void*)0);
220 MarFile* mar;
221
222 mar = (MarFile*)malloc(sizeof(*mar));
223 if (!mar) {
224 return MAR_MEM_ERROR;
225 }
226
227 off_t buffer_size = -1;
228 if (fseeko(fp, 0, SEEK_END2) == 0) {
229 buffer_size = ftello(fp);
230 }
231 rewind(fp);
232 if (buffer_size < 0) {
233 fprintf(stderrstderr, "Warning: MAR size could not be determined\n");
234 buffer_size = MAX_SIZE_OF_MAR_FILE((int64_t)524288000);
235 }
236 if (buffer_size > MAX_SIZE_OF_MAR_FILE((int64_t)524288000)) {
237 fprintf(stderrstderr, "ERROR: MAR exceeds maximum size (%lli)\n",
238 (long long int)buffer_size);
239 free(mar);
240 return MAR_FILE_TOO_BIG_ERROR;
241 }
242
243 mar->buffer = malloc(buffer_size);
244 if (!mar->buffer) {
245 fprintf(stderrstderr, "ERROR: MAR buffer could not be allocated\n");
246 free(mar);
247 return MAR_MEM_ERROR;
248 }
249 mar->data_len = fread(mar->buffer, 1, buffer_size, fp);
250 if (fgetc(fp) != EOF(-1)) {
251 fprintf(stderrstderr, "ERROR: File is larger than buffer (%lli)\n",
252 (long long int)buffer_size);
253 free(mar->buffer);
254 free(mar);
255 return MAR_IO_ERROR;
256 }
257 if (ferror(fp)) {
258 fprintf(stderrstderr, "ERROR: Failed to read MAR\n");
259 free(mar->buffer);
260 free(mar);
261 return MAR_IO_ERROR;
262 }
263
264 mar->item_table_is_valid = 0;
265 memset(mar->item_table, 0, sizeof(mar->item_table));
266 mar->index_list = NULL((void*)0);
267
268 *out_mar = mar;
269 return MAR_READ_SUCCESS;
270}
271
272MarReadResult mar_open(const char* path, MarFile** out_mar) {
273 *out_mar = NULL((void*)0);
274
275 FILE* fp;
276
277 fp = fopen(path, "rb");
278 if (!fp) {
279 fprintf(stderrstderr, "ERROR: could not open file in mar_open()\n");
280 perror(path);
281 return MAR_IO_ERROR;
282 }
283
284 MarReadResult result = mar_fpopen(fp, out_mar);
285 fclose(fp);
286 return result;
287}
288
289#ifdef XP_WIN
290MarReadResult mar_wopen(const wchar_t* path, MarFile** out_mar) {
291 *out_mar = NULL((void*)0);
292
293 FILE* fp;
294
295 _wfopen_s(&fp, path, L"rb");
296 if (!fp) {
297 fprintf(stderrstderr, "ERROR: could not open file in mar_wopen()\n");
298 _wperror(path);
299 return MAR_IO_ERROR;
300 }
301
302 MarReadResult result = mar_fpopen(fp, out_mar);
303 fclose(fp);
304 return result;
305}
306#endif
307
308void mar_close(MarFile* mar) {
309 MarItem* item;
310 SeenIndex* index;
311 int i;
312
313 free(mar->buffer);
314
315 for (i = 0; i < TABLESIZE256; ++i) {
316 item = mar->item_table[i];
317 while (item) {
318 MarItem* temp = item;
319 item = item->next;
320 free(temp);
321 }
322 }
323
324 while (mar->index_list != NULL((void*)0)) {
325 index = mar->index_list;
326 mar->index_list = index->next;
327 free(index);
328 }
329
330 free(mar);
331}
332
333int mar_read_buffer(MarFile* mar, void* dest, size_t* position, size_t size) {
334 // size may be provided by the MAR, which we may not have finished validating
335 // the signature on yet. Make sure not to trust it in a way that could
336 // cause an overflow.
337 if (size > mar->data_len) {
338 return -1;
339 }
340 if (*position > mar->data_len - size) {
341 return -1;
342 }
343 memcpy(dest, mar->buffer + *position, size);
344 *position += size;
345 return 0;
346}
347
348int mar_read_buffer_max(MarFile* mar, void* dest, size_t* position,
349 size_t size) {
350 // size may be provided by the MAR, which we may not have finished validating
351 // the signature on yet. Make sure not to trust it in a way that could
352 // cause an overflow.
353 if (mar->data_len <= *position) {
354 return 0;
355 }
356 size_t read_count = mar->data_len - *position;
357 if (read_count > size) {
358 read_count = size;
359 }
360 memcpy(dest, mar->buffer + *position, read_count);
361 *position += read_count;
362 return read_count;
363}
364
365int mar_buffer_seek(MarFile* mar, size_t* position, size_t distance) {
366 // distance may be provided by the MAR, which we may not have finished
367 // validating the signature on yet. Make sure not to trust it in a way that
368 // could cause an overflow.
369 if (distance > mar->data_len) {
370 return -1;
371 }
372 if (*position > mar->data_len - distance) {
373 return -1;
374 }
375 *position += distance;
376 return 0;
377}
378
379/**
380 * Determines the MAR file information.
381 *
382 * @param mar An open MAR file.
383 * @param mar_position The current position in the MAR.
384 * Its value will be updated to the current
385 * position in the MAR after the function exits.
386 * Since its initial value will never actually be
387 * used, this is effectively an outparam.
388 * @param hasSignatureBlock Optional out parameter specifying if the MAR
389 * file has a signature block or not.
390 * @param numSignatures Optional out parameter for storing the number
391 * of signatures in the MAR file.
392 * @param hasAdditionalBlocks Optional out parameter specifying if the MAR
393 * file has additional blocks or not.
394 * @param offsetAdditionalBlocks Optional out parameter for the offset to the
395 * first additional block. Value is only valid if
396 * hasAdditionalBlocks is not equal to 0.
397 * @param numAdditionalBlocks Optional out parameter for the number of
398 * additional blocks. Value is only valid if
399 * hasAdditionalBlocks is not equal to 0.
400 * @return 0 on success and non-zero on failure.
401 */
402int get_open_mar_file_info(MarFile* mar, size_t* mar_position,
403 int* hasSignatureBlock, uint32_t* numSignatures,
404 int* hasAdditionalBlocks,
405 uint32_t* offsetAdditionalBlocks,
406 uint32_t* numAdditionalBlocks) {
407 uint32_t offsetToIndex, offsetToContent, signatureCount, signatureLen, i;
408
409 /* One of hasSignatureBlock or hasAdditionalBlocks must be non NULL */
410 if (!hasSignatureBlock && !hasAdditionalBlocks) {
411 return -1;
412 }
413
414 /* Skip to the start of the offset index */
415 *mar_position = 0;
416 if (mar_buffer_seek(mar, mar_position, MAR_ID_SIZE4) != 0) {
417 return -1;
418 }
419
420 /* Read the offset to the index. */
421 if (mar_read_buffer(mar, &offsetToIndex, mar_position,
422 sizeof(offsetToIndex)) != 0) {
423 return -1;
424 }
425 offsetToIndex = ntohl(offsetToIndex)__bswap_32 (offsetToIndex);
426
427 if (numSignatures) {
428 /* Skip past the MAR file size field */
429 if (mar_buffer_seek(mar, mar_position, sizeof(uint64_t)) != 0) {
430 return -1;
431 }
432
433 /* Read the number of signatures field */
434 if (mar_read_buffer(mar, numSignatures, mar_position,
435 sizeof(*numSignatures)) != 0) {
436 return -1;
437 }
438 *numSignatures = ntohl(*numSignatures)__bswap_32 (*numSignatures);
439 }
440
441 /* Skip to the first index entry past the index size field
442 We do it in 2 calls because offsetToIndex + sizeof(uint32_t)
443 could overflow in theory. */
444 *mar_position = 0;
445 if (mar_buffer_seek(mar, mar_position, offsetToIndex) != 0) {
446 return -1;
447 }
448
449 if (mar_buffer_seek(mar, mar_position, sizeof(uint32_t)) != 0) {
450 return -1;
451 }
452
453 /* Read the first offset to content field. */
454 if (mar_read_buffer(mar, &offsetToContent, mar_position,
455 sizeof(offsetToContent)) != 0) {
456 return -1;
457 }
458 offsetToContent = ntohl(offsetToContent)__bswap_32 (offsetToContent);
459
460 /* Check if we have a new or old MAR file */
461 if (hasSignatureBlock) {
462 if (offsetToContent == MAR_ID_SIZE4 + sizeof(uint32_t)) {
463 *hasSignatureBlock = 0;
464 } else {
465 *hasSignatureBlock = 1;
466 }
467 }
468
469 /* If the caller doesn't care about the product info block
470 value, then just return */
471 if (!hasAdditionalBlocks) {
472 return 0;
473 }
474
475 /* Skip to the start of the signature block */
476 *mar_position = 0;
477 if (mar_buffer_seek(mar, mar_position, SIGNATURE_BLOCK_OFFSET16) != 0) {
478 return -1;
479 }
480
481 /* Get the number of signatures */
482 if (mar_read_buffer(mar, &signatureCount, mar_position,
483 sizeof(signatureCount)) != 0) {
484 return -1;
485 }
486 signatureCount = ntohl(signatureCount)__bswap_32 (signatureCount);
487
488 /* Check that we have less than the max amount of signatures so we don't
489 waste too much of either updater's or signmar's time. */
490 if (signatureCount > MAX_SIGNATURES8) {
491 return -1;
492 }
493
494 /* Skip past the whole signature block */
495 for (i = 0; i < signatureCount; i++) {
496 /* Skip past the signature algorithm ID */
497 if (mar_buffer_seek(mar, mar_position, sizeof(uint32_t)) != 0) {
498 return -1;
499 }
500
501 /* Read the signature length and skip past the signature */
502 if (mar_read_buffer(mar, &signatureLen, mar_position, sizeof(uint32_t)) !=
503 0) {
504 return -1;
505 }
506 signatureLen = ntohl(signatureLen)__bswap_32 (signatureLen);
507 if (mar_buffer_seek(mar, mar_position, signatureLen) != 0) {
508 return -1;
509 }
510 }
511
512 if (*mar_position <= (size_t)INT64_MAX(9223372036854775807L) &&
513 (int64_t)mar_position == (int64_t)offsetToContent) {
514 *hasAdditionalBlocks = 0;
515 } else {
516 if (numAdditionalBlocks) {
517 /* We have an additional block, so read in the number of additional blocks
518 and set the offset. */
519 *hasAdditionalBlocks = 1;
520 if (mar_read_buffer(mar, numAdditionalBlocks, mar_position,
521 sizeof(uint32_t)) != 0) {
522 return -1;
523 }
524 *numAdditionalBlocks = ntohl(*numAdditionalBlocks)__bswap_32 (*numAdditionalBlocks);
525 if (offsetAdditionalBlocks) {
526 if (*mar_position > (size_t)UINT32_MAX(4294967295U)) {
527 return -1;
528 }
529 *offsetAdditionalBlocks = (uint32_t)*mar_position;
530 }
531 } else if (offsetAdditionalBlocks) {
532 /* numAdditionalBlocks is not specified but offsetAdditionalBlocks
533 is, so fill it! */
534 if (mar_buffer_seek(mar, mar_position, sizeof(uint32_t)) != 0) {
535 return -1;
536 }
537 if (*mar_position > (size_t)UINT32_MAX(4294967295U)) {
538 return -1;
539 }
540 *offsetAdditionalBlocks = (uint32_t)*mar_position;
541 }
542 }
543
544 return 0;
545}
546
547/**
548 * Reads the product info block from the MAR file's additional block section.
549 * The caller is responsible for freeing the fields in infoBlock
550 * if the return is successful.
551 *
552 * @param infoBlock Out parameter for where to store the result to
553 * @return 0 on success, -1 on failure
554 */
555int read_product_info_block(char* path,
556 struct ProductInformationBlock* infoBlock) {
557 int rv;
558 MarFile* mar;
559 MarReadResult result = mar_open(path, &mar);
560 if (result != MAR_READ_SUCCESS) {
561 fprintf(stderrstderr,
562 "ERROR: could not open file in read_product_info_block()\n");
563 return -1;
564 }
565 rv = mar_read_product_info_block(mar, infoBlock);
566 mar_close(mar);
567 return rv;
568}
569
570/**
571 * Reads the product info block from the MAR file's additional block section.
572 * The caller is responsible for freeing the fields in infoBlock
573 * if the return is successful.
574 *
575 * @param infoBlock Out parameter for where to store the result to
576 * @return 0 on success, -1 on failure
577 */
578int mar_read_product_info_block(MarFile* mar,
579 struct ProductInformationBlock* infoBlock) {
580 uint32_t offsetAdditionalBlocks, numAdditionalBlocks, additionalBlockSize,
581 additionalBlockID;
582 int hasAdditionalBlocks;
583 size_t mar_position = 0;
584
585 /* The buffer size is 97 bytes because the MAR channel name < 64 bytes, and
586 product version < 32 bytes + 3 NULL terminator bytes. */
587 char buf[MAXADDITIONALBLOCKSIZE96 + 1] = {'\0'};
588 if (get_open_mar_file_info(mar, &mar_position, NULL((void*)0), NULL((void*)0),
589 &hasAdditionalBlocks, &offsetAdditionalBlocks,
590 &numAdditionalBlocks) != 0) {
591 return -1;
592 }
593
594 /* We only have the one additional block type and only one is expected to be
595 in a MAR file so check if any exist and process the first found */
596 if (numAdditionalBlocks > 0) {
597 /* Read the additional block size */
598 if (mar_read_buffer(mar, &additionalBlockSize, &mar_position,
599 sizeof(additionalBlockSize)) != 0) {
600 return -1;
601 }
602 additionalBlockSize = ntohl(additionalBlockSize)__bswap_32 (additionalBlockSize) -
603 sizeof(additionalBlockSize) -
604 sizeof(additionalBlockID);
605
606 /* Additional Block sizes should only be 96 bytes long */
607 if (additionalBlockSize > MAXADDITIONALBLOCKSIZE96) {
608 return -1;
609 }
610
611 /* Read the additional block ID */
612 if (mar_read_buffer(mar, &additionalBlockID, &mar_position,
613 sizeof(additionalBlockID)) != 0) {
614 return -1;
615 }
616 additionalBlockID = ntohl(additionalBlockID)__bswap_32 (additionalBlockID);
617
618 if (PRODUCT_INFO_BLOCK_ID1 == additionalBlockID) {
619 const char* location;
620 int len;
621
622 if (mar_read_buffer(mar, buf, &mar_position, additionalBlockSize) != 0) {
623 return -1;
624 }
625
626 /* Extract the MAR channel name from the buffer. For now we
627 point to the stack allocated buffer but we strdup this
628 if we are within bounds of each field's max length. */
629 location = buf;
630 len = strlen(location);
631 infoBlock->MARChannelID = location;
632 location += len + 1;
633 if (len >= 64) {
634 infoBlock->MARChannelID = NULL((void*)0);
635 return -1;
636 }
637
638 /* Extract the version from the buffer */
639 len = strlen(location);
640 infoBlock->productVersion = location;
641 if (len >= 32) {
642 infoBlock->MARChannelID = NULL((void*)0);
643 infoBlock->productVersion = NULL((void*)0);
644 return -1;
645 }
646 infoBlock->MARChannelID = strdup(infoBlock->MARChannelID);
647 infoBlock->productVersion = strdup(infoBlock->productVersion);
648 return 0;
649 } else {
650 /* This is not the additional block you're looking for. Move along. */
651 if (mar_buffer_seek(mar, &mar_position, additionalBlockSize) != 0) {
652 return -1;
653 }
654 }
655 }
656
657 /* If we had a product info block we would have already returned */
658 return -1;
659}
660
661const MarItem* mar_find_item(MarFile* mar, const char* name) {
662 uint32_t hash;
663 const MarItem* item;
664
665 if (!mar->item_table_is_valid) {
1
Assuming field 'item_table_is_valid' is not equal to 0
2
Taking false branch
666 if (mar_read_index(mar)) {
667 return NULL((void*)0);
668 } else {
669 mar->item_table_is_valid = 1;
670 }
671 }
672
673 hash = mar_hash_name(name);
3
Value assigned to 'hash'
674
675 item = mar->item_table[hash];
4
Value assigned to 'item'
676 while (item && strcmp(item->name, name) != 0) {
5
Assuming 'item' is null
677 item = item->next;
678 }
679
680 /* If this is the first time seeing this item's indexes, return it */
681 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')
682 return item;
683 } else {
684 fprintf(stderrstderr, "ERROR: file content collision in mar_find_item()\n");
685 return NULL((void*)0);
686 }
687}
688
689int mar_enum_items(MarFile* mar, MarItemCallback callback, void* closure) {
690 MarItem* item;
691 int i, rv;
692
693 if (!mar->item_table_is_valid) {
694 if (mar_read_index(mar)) {
695 return -1;
696 } else {
697 mar->item_table_is_valid = 1;
698 }
699 }
700
701 for (i = 0; i < TABLESIZE256; ++i) {
702 item = mar->item_table[i];
703 while (item) {
704 /* if this is the first time seeing this item's indexes, process it */
705 if (mar_insert_offset(mar, item->offset, item->length) == 1) {
706 rv = callback(mar, item, closure);
707 if (rv) {
708 return rv;
709 }
710 } else {
711 fprintf(stderrstderr, "ERROR: file content collision in mar_enum_items()\n");
712 return 1;
713 }
714 item = item->next;
715 }
716 }
717
718 return 0;
719}
720
721int mar_read(MarFile* mar, const MarItem* item, int offset, uint8_t* buf,
722 int bufsize) {
723 int nr;
724 size_t mar_position = 0;
725
726 if (offset == (int)item->length) {
727 return 0;
728 }
729 if (offset > (int)item->length) {
730 return -1;
731 }
732
733 nr = item->length - offset;
734 if (nr > bufsize) {
735 nr = bufsize;
736 }
737
738 // Avoid adding item->offset and offset directly, just in case of overflow.
739 if (mar_buffer_seek(mar, &mar_position, item->offset)) {
740 return -1;
741 }
742 if (mar_buffer_seek(mar, &mar_position, offset)) {
743 return -1;
744 }
745
746 return mar_read_buffer_max(mar, buf, &mar_position, nr);
747}
748
749/**
750 * Determines the MAR file information.
751 *
752 * @param path The path of the MAR file to check.
753 * @param hasSignatureBlock Optional out parameter specifying if the MAR
754 * file has a signature block or not.
755 * @param numSignatures Optional out parameter for storing the number
756 * of signatures in the MAR file.
757 * @param hasAdditionalBlocks Optional out parameter specifying if the MAR
758 * file has additional blocks or not.
759 * @param offsetAdditionalBlocks Optional out parameter for the offset to the
760 * first additional block. Value is only valid if
761 * hasAdditionalBlocks is not equal to 0.
762 * @param numAdditionalBlocks Optional out parameter for the number of
763 * additional blocks. Value is only valid if
764 * has_additional_blocks is not equal to 0.
765 * @return 0 on success and non-zero on failure.
766 */
767int get_mar_file_info(const char* path, int* hasSignatureBlock,
768 uint32_t* numSignatures, int* hasAdditionalBlocks,
769 uint32_t* offsetAdditionalBlocks,
770 uint32_t* numAdditionalBlocks) {
771 int rv;
772 MarFile* mar;
773 size_t mar_position = 0;
774 MarReadResult result = mar_open(path, &mar);
775 if (result != MAR_READ_SUCCESS) {
776 fprintf(stderrstderr, "ERROR: could not read file in get_mar_file_info()\n");
777 return -1;
778 }
779
780 rv = get_open_mar_file_info(mar, &mar_position, hasSignatureBlock,
781 numSignatures, hasAdditionalBlocks,
782 offsetAdditionalBlocks, numAdditionalBlocks);
783
784 mar_close(mar);
785 return rv;
786}