Bug Summary

File:3rdparty/vboot/firmware/lib/cgptlib/cgptlib_internal.c
Warning:line 302, column 4
Value stored to 'goodhdr' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name cgptlib_internal.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 -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -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 -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/home/coreboot/node-root/workspace/coreboot_scanbuild/3rdparty/vboot -resource-dir /opt/xgcc/lib/clang/17 -D CHROMEOS_ENVIRONMENT -D EC_EFS=0 -D EXTERNAL_TPM_CLEAR_REQUEST=0 -D _GNU_SOURCE -D _FILE_OFFSET_BITS=64 -D HAVE_EXECINFO_H -D HAVE_CROSID -D HAVE_NSS -I firmware/include -I firmware/lib/include -I firmware/lib/cgptlib/include -I firmware/lib/tpm_lite/include -I firmware/2lib/include -I host/include -I host/lib/include -I host/lib21/include -internal-isystem /opt/xgcc/lib/clang/17/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 -source-date-epoch 1714465709 -Os -Wno-trigraphs -Wwrite-strings -Wno-format-security -Wno-address-of-packed-member -Wno-unknown-warning -std=gnu11 -fconst-strings -fdebug-compilation-dir=/home/coreboot/node-root/workspace/coreboot_scanbuild/3rdparty/vboot -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-opt-analyze-headers -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /cb-build/coreboot_scanbuild.0/sharedutils-scanbuildtmp/2024-05-02-073004-2299942-1 -x c firmware/lib/cgptlib/cgptlib_internal.c
1/* Copyright 2013 The ChromiumOS Authors
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
6#include "2sysincludes.h"
7#include "cgptlib.h"
8#include "cgptlib_internal.h"
9#include "crc32.h"
10#include "gpt.h"
11#include "gpt_misc.h"
12
13static const int MIN_SECTOR_SIZE = 512;
14
15size_t CalculateEntriesSectors(GptHeader* h, uint32_t sector_bytes)
16{
17 size_t bytes = h->number_of_entries * h->size_of_entry;
18 size_t ret = (bytes + sector_bytes - 1) / sector_bytes;
19 return ret;
20}
21
22int CheckParameters(GptData *gpt)
23{
24 /* Only support 512-byte or larger sectors that are a power of 2 */
25 if (gpt->sector_bytes < MIN_SECTOR_SIZE ||
26 (gpt->sector_bytes & (gpt->sector_bytes - 1)) != 0)
27 return GPT_ERROR_INVALID_SECTOR_SIZE;
28
29 /*
30 * gpt_drive_sectors should be reasonable. It cannot be unset, and it
31 * cannot differ from streaming_drive_sectors if the GPT structs are
32 * stored on same device.
33 */
34 if (gpt->gpt_drive_sectors == 0 ||
35 (!(gpt->flags & GPT_FLAG_EXTERNAL0x1) &&
36 gpt->gpt_drive_sectors != gpt->streaming_drive_sectors)) {
37 return GPT_ERROR_INVALID_SECTOR_NUMBER;
38 }
39
40 /*
41 * Sector count of a drive should be reasonable. If the given value is
42 * too small to contain basic GPT structure (PMBR + Headers + Entries),
43 * the value is wrong.
44 */
45 if (gpt->gpt_drive_sectors <
46 (1 + 2 * (1 + MIN_NUMBER_OF_ENTRIES16 /
47 (gpt->sector_bytes / sizeof(GptEntry)))))
48 return GPT_ERROR_INVALID_SECTOR_NUMBER;
49
50 return GPT_SUCCESS;
51}
52
53uint32_t HeaderCrc(GptHeader *h)
54{
55 uint32_t crc32, original_crc32;
56
57 /* Original CRC is calculated with the CRC field 0. */
58 original_crc32 = h->header_crc32;
59 h->header_crc32 = 0;
60 crc32 = Crc32((const uint8_t *)h, h->size);
61 h->header_crc32 = original_crc32;
62
63 return crc32;
64}
65
66int CheckHeader(GptHeader *h, int is_secondary,
67 uint64_t streaming_drive_sectors,
68 uint64_t gpt_drive_sectors, uint32_t flags,
69 uint32_t sector_bytes)
70{
71 if (!h)
72 return 1;
73
74 /*
75 * Make sure we're looking at a header of reasonable size before
76 * attempting to calculate CRC.
77 */
78 if (memcmp(h->signature, GPT_HEADER_SIGNATURE"EFI PART",
79 GPT_HEADER_SIGNATURE_SIZE8) &&
80 memcmp(h->signature, GPT_HEADER_SIGNATURE2"CHROMEOS",
81 GPT_HEADER_SIGNATURE_SIZE8))
82 return 1;
83 if (h->revision != GPT_HEADER_REVISION0x00010000)
84 return 1;
85 if (h->size < MIN_SIZE_OF_HEADER92 || h->size > MAX_SIZE_OF_HEADER512)
86 return 1;
87
88 /* Check CRC before looking at remaining fields */
89 if (HeaderCrc(h) != h->header_crc32)
90 return 1;
91
92 /* Reserved fields must be zero. */
93 if (h->reserved_zero)
94 return 1;
95
96 /* Could check that padding is zero, but that doesn't matter to us. */
97
98 /*
99 * If entry size is different than our struct, we won't be able to
100 * parse it. Technically, any size 2^N where N>=7 is valid.
101 */
102 if (h->size_of_entry != sizeof(GptEntry))
103 return 1;
104 if ((h->number_of_entries < MIN_NUMBER_OF_ENTRIES16) ||
105 (h->number_of_entries > MAX_NUMBER_OF_ENTRIES128) ||
106 (!(flags & GPT_FLAG_EXTERNAL0x1) &&
107 h->number_of_entries != MAX_NUMBER_OF_ENTRIES128))
108 return 1;
109
110 /*
111 * Check locations for the header and its entries. The primary
112 * immediately follows the PMBR, and is followed by its entries. The
113 * secondary is at the end of the drive, preceded by its entries.
114 */
115 if (is_secondary) {
116 if (h->my_lba != gpt_drive_sectors - GPT_HEADER_SECTORS1)
117 return 1;
118 if (h->entries_lba != h->my_lba - CalculateEntriesSectors(h,
119 sector_bytes))
120 return 1;
121 } else {
122 if (h->my_lba != GPT_PMBR_SECTORS1)
123 return 1;
124 if (h->entries_lba < h->my_lba + 1)
125 return 1;
126 }
127
128 /* FirstUsableLBA <= LastUsableLBA. */
129 if (h->first_usable_lba > h->last_usable_lba)
130 return 1;
131
132 if (flags & GPT_FLAG_EXTERNAL0x1) {
133 if (h->last_usable_lba >= streaming_drive_sectors) {
134 return 1;
135 }
136 return 0;
137 }
138
139 /*
140 * FirstUsableLBA must be after the end of the primary GPT table array.
141 * LastUsableLBA must be before the start of the secondary GPT table
142 * array.
143 */
144 /* TODO(namnguyen): Also check for padding between header & entries. */
145 if (h->first_usable_lba < 2 + CalculateEntriesSectors(h, sector_bytes))
146 return 1;
147 if (h->last_usable_lba >=
148 streaming_drive_sectors - 1 - CalculateEntriesSectors(h,
149 sector_bytes))
150 return 1;
151
152 /* Success */
153 return 0;
154}
155
156int IsKernelEntry(const GptEntry *e)
157{
158 static Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL{{{0xfe3a2a5d,0x4f32,0x41a7,0xb7,0x25,{0xac,0xcc,0x32,0x85,0xa3
,0x09}}}}
;
159 return !memcmp(&e->type, &chromeos_kernel, sizeof(Guid));
160}
161
162int CheckEntries(GptEntry *entries, GptHeader *h)
163{
164 if (!entries)
165 return GPT_ERROR_INVALID_ENTRIES;
166 GptEntry *entry;
167 uint32_t crc32;
168 uint32_t i;
169
170 /* Check CRC before examining entries. */
171 crc32 = Crc32((const uint8_t *)entries,
172 h->size_of_entry * h->number_of_entries);
173 if (crc32 != h->entries_crc32)
174 return GPT_ERROR_CRC_CORRUPTED;
175
176 /* Check all entries. */
177 for (i = 0, entry = entries; i < h->number_of_entries; i++, entry++) {
178 GptEntry *e2;
179 uint32_t i2;
180
181 if (IsUnusedEntry(entry))
182 continue;
183
184 /* Entry must be in valid region. */
185 if ((entry->starting_lba < h->first_usable_lba) ||
186 (entry->ending_lba > h->last_usable_lba) ||
187 (entry->ending_lba < entry->starting_lba))
188 return GPT_ERROR_OUT_OF_REGION;
189
190 /* Entry must not overlap other entries. */
191 for (i2 = 0, e2 = entries; i2 < h->number_of_entries;
192 i2++, e2++) {
193 if (i2 == i || IsUnusedEntry(e2))
194 continue;
195
196 if ((entry->starting_lba >= e2->starting_lba) &&
197 (entry->starting_lba <= e2->ending_lba))
198 return GPT_ERROR_START_LBA_OVERLAP;
199 if ((entry->ending_lba >= e2->starting_lba) &&
200 (entry->ending_lba <= e2->ending_lba))
201 return GPT_ERROR_END_LBA_OVERLAP;
202
203 /* UniqueGuid field must be unique. */
204 if (0 == memcmp(&entry->unique, &e2->unique,
205 sizeof(Guid)))
206 return GPT_ERROR_DUP_GUID;
207 }
208 }
209
210 /* Success */
211 return 0;
212}
213
214int HeaderFieldsSame(GptHeader *h1, GptHeader *h2)
215{
216 if (memcmp(h1->signature, h2->signature, sizeof(h1->signature)))
217 return 1;
218 if (h1->revision != h2->revision)
219 return 1;
220 if (h1->size != h2->size)
221 return 1;
222 if (h1->reserved_zero != h2->reserved_zero)
223 return 1;
224 if (h1->first_usable_lba != h2->first_usable_lba)
225 return 1;
226 if (h1->last_usable_lba != h2->last_usable_lba)
227 return 1;
228 if (memcmp(&h1->disk_uuid, &h2->disk_uuid, sizeof(Guid)))
229 return 1;
230 if (h1->number_of_entries != h2->number_of_entries)
231 return 1;
232 if (h1->size_of_entry != h2->size_of_entry)
233 return 1;
234 if (h1->entries_crc32 != h2->entries_crc32)
235 return 1;
236
237 return 0;
238}
239
240int GptValidityCheck(GptData *gpt)
241{
242 int retval;
243 GptHeader *header1 = (GptHeader *)(gpt->primary_header);
244 GptHeader *header2 = (GptHeader *)(gpt->secondary_header);
245 GptEntry *entries1 = (GptEntry *)(gpt->primary_entries);
246 GptEntry *entries2 = (GptEntry *)(gpt->secondary_entries);
247 GptHeader *goodhdr = NULL((void*)0);
248
249 gpt->valid_headers = 0;
250 gpt->valid_entries = 0;
251 gpt->ignored = 0;
252
253 retval = CheckParameters(gpt);
254 if (retval != GPT_SUCCESS)
255 return retval;
256
257 /* Check both headers; we need at least one valid header. */
258 if (0 == CheckHeader(header1, 0, gpt->streaming_drive_sectors,
259 gpt->gpt_drive_sectors, gpt->flags,
260 gpt->sector_bytes)) {
261 gpt->valid_headers |= MASK_PRIMARY;
262 goodhdr = header1;
263 if (0 == CheckEntries(entries1, goodhdr))
264 gpt->valid_entries |= MASK_PRIMARY;
265 } else if (header1 && !memcmp(header1->signature,
266 GPT_HEADER_SIGNATURE_IGNORED"IGNOREME", GPT_HEADER_SIGNATURE_SIZE8)) {
267 gpt->ignored |= MASK_PRIMARY;
268 }
269 if (0 == CheckHeader(header2, 1, gpt->streaming_drive_sectors,
270 gpt->gpt_drive_sectors, gpt->flags,
271 gpt->sector_bytes)) {
272 gpt->valid_headers |= MASK_SECONDARY;
273 if (!goodhdr)
274 goodhdr = header2;
275 /* Check header1+entries2 if it was good, to catch mismatch. */
276 if (0 == CheckEntries(entries2, goodhdr))
277 gpt->valid_entries |= MASK_SECONDARY;
278 } else if (header2 && !memcmp(header2->signature,
279 GPT_HEADER_SIGNATURE_IGNORED"IGNOREME", GPT_HEADER_SIGNATURE_SIZE8)) {
280 gpt->ignored |= MASK_SECONDARY;
281 }
282
283 if (!gpt->valid_headers)
284 return GPT_ERROR_INVALID_HEADERS;
285
286 /*
287 * If both headers are good but neither entries were good, check the
288 * entries with the secondary header.
289 */
290 if (MASK_BOTH == gpt->valid_headers && !gpt->valid_entries) {
291 if (0 == CheckEntries(entries1, header2))
292 gpt->valid_entries |= MASK_PRIMARY;
293 if (0 == CheckEntries(entries2, header2))
294 gpt->valid_entries |= MASK_SECONDARY;
295 if (gpt->valid_entries) {
296 /*
297 * Sure enough, header2 had a good CRC for one of the
298 * entries. Mark header1 invalid, so we'll update its
299 * entries CRC.
300 */
301 gpt->valid_headers &= ~MASK_PRIMARY;
302 goodhdr = header2;
Value stored to 'goodhdr' is never read
303 }
304 }
305
306 if (!gpt->valid_entries)
307 return GPT_ERROR_INVALID_ENTRIES;
308
309 /*
310 * Now that we've determined which header contains a good CRC for
311 * the entries, make sure the headers are otherwise identical.
312 */
313 if (MASK_BOTH == gpt->valid_headers &&
314 0 != HeaderFieldsSame(header1, header2))
315 gpt->valid_headers &= ~MASK_SECONDARY;
316
317 /*
318 * When we're ignoring a GPT, make it look in memory like the other one
319 * and pretend that everything is fine (until we try to save).
320 */
321 if (MASK_NONE != gpt->ignored) {
322 GptRepair(gpt);
323 gpt->modified = 0;
324 }
325
326 return GPT_SUCCESS;
327}
328
329void GptRepair(GptData *gpt)
330{
331 GptHeader *header1 = (GptHeader *)(gpt->primary_header);
332 GptHeader *header2 = (GptHeader *)(gpt->secondary_header);
333 GptEntry *entries1 = (GptEntry *)(gpt->primary_entries);
334 GptEntry *entries2 = (GptEntry *)(gpt->secondary_entries);
335 int entries_size;
336
337 /* Need at least one good header and one good set of entries. */
338 if (MASK_NONE == gpt->valid_headers || MASK_NONE == gpt->valid_entries)
339 return;
340
341 /* Repair headers if necessary */
342 if (MASK_PRIMARY == gpt->valid_headers) {
343 /* Primary is good, secondary is bad */
344 memcpy(header2, header1, sizeof(GptHeader));
345 header2->my_lba = gpt->gpt_drive_sectors - GPT_HEADER_SECTORS1;
346 header2->alternate_lba = GPT_PMBR_SECTORS1; /* Second sector. */
347 header2->entries_lba = header2->my_lba -
348 CalculateEntriesSectors(header1, gpt->sector_bytes);
349 header2->header_crc32 = HeaderCrc(header2);
350 gpt->modified |= GPT_MODIFIED_HEADER20x02;
351 }
352 else if (MASK_SECONDARY == gpt->valid_headers) {
353 /* Secondary is good, primary is bad */
354 memcpy(header1, header2, sizeof(GptHeader));
355 header1->my_lba = GPT_PMBR_SECTORS1; /* Second sector. */
356 header1->alternate_lba =
357 gpt->streaming_drive_sectors - GPT_HEADER_SECTORS1;
358 /* TODO (namnguyen): Preserve (header, entries) padding. */
359 header1->entries_lba = header1->my_lba + 1;
360 header1->header_crc32 = HeaderCrc(header1);
361 gpt->modified |= GPT_MODIFIED_HEADER10x01;
362 }
363 gpt->valid_headers = MASK_BOTH;
364
365 /* Repair entries if necessary */
366 entries_size = header1->size_of_entry * header1->number_of_entries;
367 if (MASK_PRIMARY == gpt->valid_entries) {
368 /* Primary is good, secondary is bad */
369 memcpy(entries2, entries1, entries_size);
370 gpt->modified |= GPT_MODIFIED_ENTRIES20x08;
371 }
372 else if (MASK_SECONDARY == gpt->valid_entries) {
373 /* Secondary is good, primary is bad */
374 memcpy(entries1, entries2, entries_size);
375 gpt->modified |= GPT_MODIFIED_ENTRIES10x04;
376 }
377 gpt->valid_entries = MASK_BOTH;
378}
379
380int GetEntryRequired(const GptEntry *e)
381{
382 return e->attrs.fields.required;
383}
384
385int GetEntryLegacyBoot(const GptEntry *e)
386{
387 return e->attrs.fields.legacy_boot;
388}
389
390int GetEntrySuccessful(const GptEntry *e)
391{
392 return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_SUCCESSFUL_MASK((1ULL) << (56 - 48))) >>
393 CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET(56 - 48);
394}
395
396int GetEntryPriority(const GptEntry *e)
397{
398 return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_PRIORITY_MASK((15ULL) << (48 - 48))) >>
399 CGPT_ATTRIBUTE_PRIORITY_OFFSET(48 - 48);
400}
401
402int GetEntryTries(const GptEntry *e)
403{
404 return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_TRIES_MASK((15ULL) << (52 - 48))) >>
405 CGPT_ATTRIBUTE_TRIES_OFFSET(52 - 48);
406}
407
408int GetEntryErrorCounter(const GptEntry *e)
409{
410 return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_ERROR_COUNTER_MASK((1ULL) << (57 - 48))) >>
411 CGPT_ATTRIBUTE_ERROR_COUNTER_OFFSET(57 - 48);
412}
413
414void SetEntryRequired(GptEntry *e, int required)
415{
416 e->attrs.fields.required = required;
417}
418
419void SetEntryLegacyBoot(GptEntry *e, int legacy_boot)
420{
421 e->attrs.fields.legacy_boot = legacy_boot;
422}
423
424void SetEntrySuccessful(GptEntry *e, int successful)
425{
426 if (successful)
427 e->attrs.fields.gpt_att |= CGPT_ATTRIBUTE_SUCCESSFUL_MASK((1ULL) << (56 - 48));
428 else
429 e->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_SUCCESSFUL_MASK((1ULL) << (56 - 48));
430}
431
432void SetEntryPriority(GptEntry *e, int priority)
433{
434 e->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_PRIORITY_MASK((15ULL) << (48 - 48));
435 e->attrs.fields.gpt_att |=
436 (priority << CGPT_ATTRIBUTE_PRIORITY_OFFSET(48 - 48)) &
437 CGPT_ATTRIBUTE_PRIORITY_MASK((15ULL) << (48 - 48));
438}
439
440void SetEntryTries(GptEntry *e, int tries)
441{
442 e->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_TRIES_MASK((15ULL) << (52 - 48));
443 e->attrs.fields.gpt_att |= (tries << CGPT_ATTRIBUTE_TRIES_OFFSET(52 - 48)) &
444 CGPT_ATTRIBUTE_TRIES_MASK((15ULL) << (52 - 48));
445}
446
447void SetEntryErrorCounter(GptEntry *e, int error_counter)
448{
449 e->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_ERROR_COUNTER_MASK((1ULL) << (57 - 48));
450 e->attrs.fields.gpt_att |=
451 (error_counter << CGPT_ATTRIBUTE_ERROR_COUNTER_OFFSET(57 - 48)) &
452 CGPT_ATTRIBUTE_ERROR_COUNTER_MASK((1ULL) << (57 - 48));
453}
454
455void GetCurrentKernelUniqueGuid(GptData *gpt, void *dest)
456{
457 GptEntry *entries = (GptEntry *)gpt->primary_entries;
458 GptEntry *e = entries + gpt->current_kernel;
459 memcpy(dest, &e->unique, sizeof(Guid));
460}
461
462void GptModified(GptData *gpt) {
463 GptHeader *header = (GptHeader *)gpt->primary_header;
464
465 /* Update the CRCs */
466 header->entries_crc32 = Crc32(gpt->primary_entries,
467 header->size_of_entry *
468 header->number_of_entries);
469 header->header_crc32 = HeaderCrc(header);
470 gpt->modified |= GPT_MODIFIED_HEADER10x01 | GPT_MODIFIED_ENTRIES10x04;
471
472 /*
473 * Use the repair function to update the other copy of the GPT. This
474 * is a tad inefficient, but is much faster than the disk I/O to update
475 * the GPT on disk so it doesn't matter.
476 */
477 gpt->valid_headers = MASK_PRIMARY;
478 gpt->valid_entries = MASK_PRIMARY;
479 GptRepair(gpt);
480}
481
482
483const char *GptErrorText(int error_code)
484{
485 switch(error_code) {
486 case GPT_SUCCESS:
487 return "none";
488
489 case GPT_ERROR_NO_VALID_KERNEL:
490 return "Invalid kernel";
491
492 case GPT_ERROR_INVALID_HEADERS:
493 return "Invalid headers";
494
495 case GPT_ERROR_INVALID_ENTRIES:
496 return "Invalid entries";
497
498 case GPT_ERROR_INVALID_SECTOR_SIZE:
499 return "Invalid sector size";
500
501 case GPT_ERROR_INVALID_SECTOR_NUMBER:
502 return "Invalid sector number";
503
504 case GPT_ERROR_INVALID_UPDATE_TYPE:
505 return "Invalid update type";
506
507 case GPT_ERROR_CRC_CORRUPTED:
508 return "Entries' crc corrupted";
509
510 case GPT_ERROR_OUT_OF_REGION:
511 return "Entry outside of valid region";
512
513 case GPT_ERROR_START_LBA_OVERLAP:
514 return "Starting LBA overlaps";
515
516 case GPT_ERROR_END_LBA_OVERLAP:
517 return "Ending LBA overlaps";
518
519 case GPT_ERROR_DUP_GUID:
520 return "Duplicated GUID";
521
522 case GPT_ERROR_INVALID_FLASH_GEOMETRY:
523 return "Invalid flash geometry";
524
525 case GPT_ERROR_NO_SUCH_ENTRY:
526 return "No entry found";
527
528 default:
529 break;
530 };
531 return "Unknown";
532}