• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CalculateEntriesSectors(GptHeader * h)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 
CheckParameters(GptData * gpt)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 
HeaderCrc(GptHeader * h)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 
CheckHeader(GptHeader * h,int is_secondary,uint64_t streaming_drive_sectors,uint64_t gpt_drive_sectors,uint32_t flags)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 
IsKernelEntry(const GptEntry * e)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 
CheckEntries(GptEntry * entries,GptHeader * h)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 
HeaderFieldsSame(GptHeader * h1,GptHeader * h2)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 
GptSanityCheck(GptData * gpt)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 
GptRepair(GptData * gpt)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 
GetEntrySuccessful(const GptEntry * e)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 
GetEntryPriority(const GptEntry * e)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 
GetEntryTries(const GptEntry * e)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 
SetEntrySuccessful(GptEntry * e,int successful)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 
SetEntryPriority(GptEntry * e,int priority)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 
SetEntryTries(GptEntry * e,int tries)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 
GetCurrentKernelUniqueGuid(GptData * gpt,void * dest)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 
GptModified(GptData * gpt)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 
GptErrorText(int error_code)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