Home | History | Annotate | Download | only in cgptlib
      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 
     15 const static int SECTOR_SIZE = 512;
     16 
     17 size_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 
     23 int 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 
     53 uint32_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 
     66 int 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 
    153 int 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 
    159 int 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 
    211 int 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 
    237 int 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 
    315 void 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 
    365 int GetEntrySuccessful(const GptEntry *e)
    366 {
    367 	return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_SUCCESSFUL_MASK) >>
    368 		CGPT_ATTRIBUTE_SUCCESSFUL_OFFSET;
    369 }
    370 
    371 int GetEntryPriority(const GptEntry *e)
    372 {
    373 	return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_PRIORITY_MASK) >>
    374 		CGPT_ATTRIBUTE_PRIORITY_OFFSET;
    375 }
    376 
    377 int GetEntryTries(const GptEntry *e)
    378 {
    379 	return (e->attrs.fields.gpt_att & CGPT_ATTRIBUTE_TRIES_MASK) >>
    380 		CGPT_ATTRIBUTE_TRIES_OFFSET;
    381 }
    382 
    383 void 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 
    391 void 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 
    399 void 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 
    406 void 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 
    413 void 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 
    434 const 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