1/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 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 "sysincludes.h" 7 8#include "cgptlib.h" 9#include "cgptlib_internal.h" 10#include "crc32.h" 11#include "gpt.h" 12#include "gpt_misc.h" 13#include "utility.h" 14 15const static int SECTOR_SIZE = 512; 16 17size_t CalculateEntriesSectors(GptHeader* h) { 18 size_t bytes = h->number_of_entries * h->size_of_entry; 19 size_t ret = (bytes + SECTOR_SIZE - 1) / SECTOR_SIZE; 20 return ret; 21} 22 23int CheckParameters(GptData *gpt) 24{ 25 /* Currently, we only support 512-byte sectors. */ 26 if (gpt->sector_bytes != SECTOR_SIZE) 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_EXTERNAL) && 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_ENTRIES / 47 (SECTOR_SIZE / 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{ 70 if (!h) 71 return 1; 72 73 /* 74 * Make sure we're looking at a header of reasonable size before 75 * attempting to calculate CRC. 76 */ 77 if (Memcmp(h->signature, GPT_HEADER_SIGNATURE, 78 GPT_HEADER_SIGNATURE_SIZE) && 79 Memcmp(h->signature, GPT_HEADER_SIGNATURE2, 80 GPT_HEADER_SIGNATURE_SIZE)) 81 return 1; 82 if (h->revision != GPT_HEADER_REVISION) 83 return 1; 84 if (h->size < MIN_SIZE_OF_HEADER || h->size > MAX_SIZE_OF_HEADER) 85 return 1; 86 87 /* Check CRC before looking at remaining fields */ 88 if (HeaderCrc(h) != h->header_crc32) 89 return 1; 90 91 /* Reserved fields must be zero. */ 92 if (h->reserved_zero) 93 return 1; 94 95 /* Could check that padding is zero, but that doesn't matter to us. */ 96 97 /* 98 * If entry size is different than our struct, we won't be able to 99 * parse it. Technically, any size 2^N where N>=7 is valid. 100 */ 101 if (h->size_of_entry != sizeof(GptEntry)) 102 return 1; 103 if ((h->number_of_entries < MIN_NUMBER_OF_ENTRIES) || 104 (h->number_of_entries > MAX_NUMBER_OF_ENTRIES) || 105 (!(flags & GPT_FLAG_EXTERNAL) && 106 h->number_of_entries != MAX_NUMBER_OF_ENTRIES)) 107 return 1; 108 109 /* 110 * Check locations for the header and its entries. The primary 111 * immediately follows the PMBR, and is followed by its entries. The 112 * secondary is at the end of the drive, preceded by its entries. 113 */ 114 if (is_secondary) { 115 if (h->my_lba != gpt_drive_sectors - GPT_HEADER_SECTORS) 116 return 1; 117 if (h->entries_lba != h->my_lba - CalculateEntriesSectors(h)) 118 return 1; 119 } else { 120 if (h->my_lba != GPT_PMBR_SECTORS) 121 return 1; 122 if (h->entries_lba < h->my_lba + 1) 123 return 1; 124 } 125 126 /* FirstUsableLBA <= LastUsableLBA. */ 127 if (h->first_usable_lba > h->last_usable_lba) 128 return 1; 129 130 if (flags & GPT_FLAG_EXTERNAL) { 131 if (h->last_usable_lba >= streaming_drive_sectors) { 132 return 1; 133 } 134 return 0; 135 } 136 137 /* 138 * FirstUsableLBA must be after the end of the primary GPT table array. 139 * LastUsableLBA must be before the start of the secondary GPT table 140 * array. 141 */ 142 /* TODO(namnguyen): Also check for padding between header & entries. */ 143 if (h->first_usable_lba < 2 + CalculateEntriesSectors(h)) 144 return 1; 145 if (h->last_usable_lba >= 146 streaming_drive_sectors - 1 - CalculateEntriesSectors(h)) 147 return 1; 148 149 /* Success */ 150 return 0; 151} 152 153int IsKernelEntry(const GptEntry *e) 154{ 155 static Guid chromeos_kernel = GPT_ENT_TYPE_CHROMEOS_KERNEL; 156 return !Memcmp(&e->type, &chromeos_kernel, sizeof(Guid)); 157} 158 159int CheckEntries(GptEntry *entries, GptHeader *h) 160{ 161 if (!entries) 162 return GPT_ERROR_INVALID_ENTRIES; 163 GptEntry *entry; 164 uint32_t crc32; 165 uint32_t i; 166 167 /* Check CRC before examining entries. */ 168 crc32 = Crc32((const uint8_t *)entries, 169 h->size_of_entry * h->number_of_entries); 170 if (crc32 != h->entries_crc32) 171 return GPT_ERROR_CRC_CORRUPTED; 172 173 /* Check all entries. */ 174 for (i = 0, entry = entries; i < h->number_of_entries; i++, entry++) { 175 GptEntry *e2; 176 uint32_t i2; 177 178 if (IsUnusedEntry(entry)) 179 continue; 180 181 /* Entry must be in valid region. */ 182 if ((entry->starting_lba < h->first_usable_lba) || 183 (entry->ending_lba > h->last_usable_lba) || 184 (entry->ending_lba < entry->starting_lba)) 185 return GPT_ERROR_OUT_OF_REGION; 186 187 /* Entry must not overlap other entries. */ 188 for (i2 = 0, e2 = entries; i2 < h->number_of_entries; 189 i2++, e2++) { 190 if (i2 == i || IsUnusedEntry(e2)) 191 continue; 192 193 if ((entry->starting_lba >= e2->starting_lba) && 194 (entry->starting_lba <= e2->ending_lba)) 195 return GPT_ERROR_START_LBA_OVERLAP; 196 if ((entry->ending_lba >= e2->starting_lba) && 197 (entry->ending_lba <= e2->ending_lba)) 198 return GPT_ERROR_END_LBA_OVERLAP; 199 200 /* UniqueGuid field must be unique. */ 201 if (0 == Memcmp(&entry->unique, &e2->unique, 202 sizeof(Guid))) 203 return GPT_ERROR_DUP_GUID; 204 } 205 } 206 207 /* Success */ 208 return 0; 209} 210 211int HeaderFieldsSame(GptHeader *h1, GptHeader *h2) 212{ 213 if (Memcmp(h1->signature, h2->signature, sizeof(h1->signature))) 214 return 1; 215 if (h1->revision != h2->revision) 216 return 1; 217 if (h1->size != h2->size) 218 return 1; 219 if (h1->reserved_zero != h2->reserved_zero) 220 return 1; 221 if (h1->first_usable_lba != h2->first_usable_lba) 222 return 1; 223 if (h1->last_usable_lba != h2->last_usable_lba) 224 return 1; 225 if (Memcmp(&h1->disk_uuid, &h2->disk_uuid, sizeof(Guid))) 226 return 1; 227 if (h1->number_of_entries != h2->number_of_entries) 228 return 1; 229 if (h1->size_of_entry != h2->size_of_entry) 230 return 1; 231 if (h1->entries_crc32 != h2->entries_crc32) 232 return 1; 233 234 return 0; 235} 236 237int GptSanityCheck(GptData *gpt) 238{ 239 int retval; 240 GptHeader *header1 = (GptHeader *)(gpt->primary_header); 241 GptHeader *header2 = (GptHeader *)(gpt->secondary_header); 242 GptEntry *entries1 = (GptEntry *)(gpt->primary_entries); 243 GptEntry *entries2 = (GptEntry *)(gpt->secondary_entries); 244 GptHeader *goodhdr = NULL; 245 246 gpt->valid_headers = 0; 247 gpt->valid_entries = 0; 248 249 retval = CheckParameters(gpt); 250 if (retval != GPT_SUCCESS) 251 return retval; 252 253 /* Check both headers; we need at least one valid header. */ 254 if (0 == CheckHeader(header1, 0, gpt->streaming_drive_sectors, 255 gpt->gpt_drive_sectors, gpt->flags)) { 256 gpt->valid_headers |= MASK_PRIMARY; 257 goodhdr = header1; 258 } 259 if (0 == CheckHeader(header2, 1, gpt->streaming_drive_sectors, 260 gpt->gpt_drive_sectors, gpt->flags)) { 261 gpt->valid_headers |= MASK_SECONDARY; 262 if (!goodhdr) 263 goodhdr = header2; 264 } 265 266 if (!gpt->valid_headers) 267 return GPT_ERROR_INVALID_HEADERS; 268 269 /* 270 * Check if entries are valid. 271 * 272 * Note that we use the same header in both checks. This way we'll 273 * catch the case where (header1,entries1) and (header2,entries2) are 274 * both valid, but (entries1 != entries2). 275 */ 276 if (0 == CheckEntries(entries1, goodhdr)) 277 gpt->valid_entries |= MASK_PRIMARY; 278 if (0 == CheckEntries(entries2, goodhdr)) 279 gpt->valid_entries |= MASK_SECONDARY; 280 281 /* 282 * If both headers are good but neither entries were good, check the 283 * entries with the secondary header. 284 */ 285 if (MASK_BOTH == gpt->valid_headers && !gpt->valid_entries) { 286 if (0 == CheckEntries(entries1, header2)) 287 gpt->valid_entries |= MASK_PRIMARY; 288 if (0 == CheckEntries(entries2, header2)) 289 gpt->valid_entries |= MASK_SECONDARY; 290 if (gpt->valid_entries) { 291 /* 292 * Sure enough, header2 had a good CRC for one of the 293 * entries. Mark header1 invalid, so we'll update its 294 * entries CRC. 295 */ 296 gpt->valid_headers &= ~MASK_PRIMARY; 297 goodhdr = header2; 298 } 299 } 300 301 if (!gpt->valid_entries) 302 return GPT_ERROR_INVALID_ENTRIES; 303 304 /* 305 * Now that we've determined which header contains a good CRC for 306 * the entries, make sure the headers are otherwise identical. 307 */ 308 if (MASK_BOTH == gpt->valid_headers && 309 0 != HeaderFieldsSame(header1, header2)) 310 gpt->valid_headers &= ~MASK_SECONDARY; 311 312 return GPT_SUCCESS; 313} 314 315void GptRepair(GptData *gpt) 316{ 317 GptHeader *header1 = (GptHeader *)(gpt->primary_header); 318 GptHeader *header2 = (GptHeader *)(gpt->secondary_header); 319 GptEntry *entries1 = (GptEntry *)(gpt->primary_entries); 320 GptEntry *entries2 = (GptEntry *)(gpt->secondary_entries); 321 int entries_size; 322 323 /* Need at least one good header and one good set of entries. */ 324 if (MASK_NONE == gpt->valid_headers || MASK_NONE == gpt->valid_entries) 325 return; 326 327 /* Repair headers if necessary */ 328 if (MASK_PRIMARY == gpt->valid_headers) { 329 /* Primary is good, secondary is bad */ 330 Memcpy(header2, header1, sizeof(GptHeader)); 331 header2->my_lba = gpt->gpt_drive_sectors - GPT_HEADER_SECTORS; 332 header2->alternate_lba = GPT_PMBR_SECTORS; /* Second sector. */ 333 header2->entries_lba = header2->my_lba - CalculateEntriesSectors(header1); 334 header2->header_crc32 = HeaderCrc(header2); 335 gpt->modified |= GPT_MODIFIED_HEADER2; 336 } 337 else if (MASK_SECONDARY == gpt->valid_headers) { 338 /* Secondary is good, primary is bad */ 339 Memcpy(header1, header2, sizeof(GptHeader)); 340 header1->my_lba = GPT_PMBR_SECTORS; /* Second sector. */ 341 header1->alternate_lba = 342 gpt->streaming_drive_sectors - GPT_HEADER_SECTORS; 343 /* TODO (namnguyen): Preserve (header, entries) padding. */ 344 header1->entries_lba = header1->my_lba + 1; 345 header1->header_crc32 = HeaderCrc(header1); 346 gpt->modified |= GPT_MODIFIED_HEADER1; 347 } 348 gpt->valid_headers = MASK_BOTH; 349 350 /* Repair entries if necessary */ 351 entries_size = header1->size_of_entry * header1->number_of_entries; 352 if (MASK_PRIMARY == gpt->valid_entries) { 353 /* Primary is good, secondary is bad */ 354 Memcpy(entries2, entries1, entries_size); 355 gpt->modified |= GPT_MODIFIED_ENTRIES2; 356 } 357 else if (MASK_SECONDARY == gpt->valid_entries) { 358 /* Secondary is good, primary is bad */ 359 Memcpy(entries1, entries2, entries_size); 360 gpt->modified |= GPT_MODIFIED_ENTRIES1; 361 } 362 gpt->valid_entries = MASK_BOTH; 363} 364 365int GetEntrySuccessful(const GptEntry *e) 366{ 367 return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >> 368 CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET; 369} 370 371int GetEntryPriority(const GptEntry *e) 372{ 373 return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_PRIORITY_MASK) >> 374 CGPT_ATTRIBUTE_PRIORITY_OFFSET; 375} 376 377int GetEntryTries(const GptEntry *e) 378{ 379 return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_TRIES_MASK) >> 380 CGPT_ATTRIBUTE_TRIES_OFFSET; 381} 382 383void SetEntrySuccessful(GptEntry *e, int successful) 384{ 385 if (successful) 386 e->attrs.fields.gpt_att |= CGPT_ATTRIBUTE_SUCCESSFUL_MASK; 387 else 388 e->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_SUCCESSFUL_MASK; 389} 390 391void SetEntryPriority(GptEntry *e, int priority) 392{ 393 e->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_PRIORITY_MASK; 394 e->attrs.fields.gpt_att |= 395 (priority << CGPT_ATTRIBUTE_PRIORITY_OFFSET) & 396 CGPT_ATTRIBUTE_PRIORITY_MASK; 397} 398 399void SetEntryTries(GptEntry *e, int tries) 400{ 401 e->attrs.fields.gpt_att &= ~CGPT_ATTRIBUTE_TRIES_MASK; 402 e->attrs.fields.gpt_att |= (tries << CGPT_ATTRIBUTE_TRIES_OFFSET) & 403 CGPT_ATTRIBUTE_TRIES_MASK; 404} 405 406void GetCurrentKernelUniqueGuid(GptData *gpt, void *dest) 407{ 408 GptEntry *entries = (GptEntry *)gpt->primary_entries; 409 GptEntry *e = entries + gpt->current_kernel; 410 Memcpy(dest, &e->unique, sizeof(Guid)); 411} 412 413void GptModified(GptData *gpt) { 414 GptHeader *header = (GptHeader *)gpt->primary_header; 415 416 /* Update the CRCs */ 417 header->entries_crc32 = Crc32(gpt->primary_entries, 418 header->size_of_entry * 419 header->number_of_entries); 420 header->header_crc32 = HeaderCrc(header); 421 gpt->modified |= GPT_MODIFIED_HEADER1 | GPT_MODIFIED_ENTRIES1; 422 423 /* 424 * Use the repair function to update the other copy of the GPT. This 425 * is a tad inefficient, but is much faster than the disk I/O to update 426 * the GPT on disk so it doesn't matter. 427 */ 428 gpt->valid_headers = MASK_PRIMARY; 429 gpt->valid_entries = MASK_PRIMARY; 430 GptRepair(gpt); 431} 432 433 434const char *GptErrorText(int error_code) 435{ 436 switch(error_code) { 437 case GPT_SUCCESS: 438 return "none"; 439 440 case GPT_ERROR_NO_VALID_KERNEL: 441 return "Invalid kernel"; 442 443 case GPT_ERROR_INVALID_HEADERS: 444 return "Invalid headers"; 445 446 case GPT_ERROR_INVALID_ENTRIES: 447 return "Invalid entries"; 448 449 case GPT_ERROR_INVALID_SECTOR_SIZE: 450 return "Invalid sector size"; 451 452 case GPT_ERROR_INVALID_SECTOR_NUMBER: 453 return "Invalid sector number"; 454 455 case GPT_ERROR_INVALID_UPDATE_TYPE: 456 return "Invalid update type"; 457 458 case GPT_ERROR_CRC_CORRUPTED: 459 return "Entries' crc corrupted"; 460 461 case GPT_ERROR_OUT_OF_REGION: 462 return "Entry outside of valid region"; 463 464 case GPT_ERROR_START_LBA_OVERLAP: 465 return "Starting LBA overlaps"; 466 467 case GPT_ERROR_END_LBA_OVERLAP: 468 return "Ending LBA overlaps"; 469 470 case GPT_ERROR_DUP_GUID: 471 return "Duplicated GUID"; 472 473 case GPT_ERROR_INVALID_FLASH_GEOMETRY: 474 return "Invalid flash geometry"; 475 476 case GPT_ERROR_NO_SUCH_ENTRY: 477 return "No entry found"; 478 479 default: 480 break; 481 }; 482 return "Unknown"; 483} 484