• 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 "utility.h"
13 #include "vboot_api.h"
14 
15 
16 /**
17  * Allocate and read GPT data from the drive.
18  *
19  * The sector_bytes and gpt_drive_sectors fields should be filled on input.  The
20  * primary and secondary header and entries are filled on output.
21  *
22  * Returns 0 if successful, 1 if error.
23  */
AllocAndReadGptData(VbExDiskHandle_t disk_handle,GptData * gptdata)24 int AllocAndReadGptData(VbExDiskHandle_t disk_handle, GptData *gptdata)
25 {
26 	uint64_t max_entries_bytes = MAX_NUMBER_OF_ENTRIES * sizeof(GptEntry);
27 	int primary_valid = 0, secondary_valid = 0;
28 
29 	/* No data to be written yet */
30 	gptdata->modified = 0;
31 
32 	/* Allocate all buffers */
33 	gptdata->primary_header = (uint8_t *)VbExMalloc(gptdata->sector_bytes);
34 	gptdata->secondary_header =
35 		(uint8_t *)VbExMalloc(gptdata->sector_bytes);
36 	gptdata->primary_entries = (uint8_t *)VbExMalloc(max_entries_bytes);
37 	gptdata->secondary_entries = (uint8_t *)VbExMalloc(max_entries_bytes);
38 
39 	if (gptdata->primary_header == NULL ||
40 	    gptdata->secondary_header == NULL ||
41 	    gptdata->primary_entries == NULL ||
42 	    gptdata->secondary_entries == NULL)
43 		return 1;
44 
45 	/* Read primary header from the drive, skipping the protective MBR */
46 	if (0 != VbExDiskRead(disk_handle, 1, 1, gptdata->primary_header))
47 		return 1;
48 
49 	/* Only read primary GPT if the primary header is valid */
50 	GptHeader* primary_header = (GptHeader*)gptdata->primary_header;
51 	if (0 == CheckHeader(primary_header, 0,
52 			gptdata->streaming_drive_sectors,
53 			gptdata->gpt_drive_sectors,
54 			gptdata->flags)) {
55 		primary_valid = 1;
56 		uint64_t entries_bytes = primary_header->number_of_entries
57 				* primary_header->size_of_entry;
58 		uint64_t entries_sectors = entries_bytes
59 					/ gptdata->sector_bytes;
60 		if (0 != VbExDiskRead(disk_handle,
61 				      primary_header->entries_lba,
62 				      entries_sectors,
63 				      gptdata->primary_entries))
64 			return 1;
65 	} else {
66 		VBDEBUG(("Primary GPT header invalid!\n"));
67 	}
68 
69 	/* Read secondary header from the end of the drive */
70 	if (0 != VbExDiskRead(disk_handle, gptdata->gpt_drive_sectors - 1, 1,
71 			      gptdata->secondary_header))
72 		return 1;
73 
74 	/* Only read secondary GPT if the secondary header is valid */
75 	GptHeader* secondary_header = (GptHeader*)gptdata->secondary_header;
76 	if (0 == CheckHeader(secondary_header, 1,
77 			gptdata->streaming_drive_sectors,
78 			gptdata->gpt_drive_sectors,
79 			gptdata->flags)) {
80 		secondary_valid = 1;
81 		uint64_t entries_bytes = secondary_header->number_of_entries
82 				* secondary_header->size_of_entry;
83 		uint64_t entries_sectors = entries_bytes
84 				/ gptdata->sector_bytes;
85 		if (0 != VbExDiskRead(disk_handle,
86 				      secondary_header->entries_lba,
87 				      entries_sectors,
88 				      gptdata->secondary_entries))
89 			return 1;
90 	} else {
91 		VBDEBUG(("Secondary GPT header invalid!\n"));
92 	}
93 
94 	/* Return 0 if least one GPT header was valid */
95 	return (primary_valid || secondary_valid) ? 0 : 1;
96 }
97 
98 /**
99  * Write any changes for the GPT data back to the drive, then free the buffers.
100  *
101  * Returns 0 if successful, 1 if error.
102  */
WriteAndFreeGptData(VbExDiskHandle_t disk_handle,GptData * gptdata)103 int WriteAndFreeGptData(VbExDiskHandle_t disk_handle, GptData *gptdata)
104 {
105 	int legacy = 0;
106 	GptHeader *header = (GptHeader *)gptdata->primary_header;
107 	uint64_t entries_bytes = header->number_of_entries
108 				* header->size_of_entry;
109 	uint64_t entries_sectors = entries_bytes / gptdata->sector_bytes;
110 	int ret = 1;
111 
112 	/*
113 	 * TODO(namnguyen): Preserve padding between primary GPT header and
114 	 * its entries.
115 	 */
116 	uint64_t entries_lba = GPT_PMBR_SECTORS + GPT_HEADER_SECTORS;
117 	if (gptdata->primary_header) {
118 		GptHeader *h = (GptHeader *)(gptdata->primary_header);
119 		entries_lba = h->entries_lba;
120 
121 		/*
122 		 * Avoid even looking at this data if we don't need to. We
123 		 * may in fact not have read it from disk if the read failed,
124 		 * and this avoids a valgrind complaint.
125 		 */
126 		if (gptdata->modified) {
127 			legacy = !Memcmp(h->signature, GPT_HEADER_SIGNATURE2,
128 					GPT_HEADER_SIGNATURE_SIZE);
129 		}
130 		if (gptdata->modified & GPT_MODIFIED_HEADER1) {
131 			if (legacy) {
132 				VBDEBUG(("Not updating GPT header 1: "
133 					 "legacy mode is enabled.\n"));
134 			} else {
135 				VBDEBUG(("Updating GPT header 1\n"));
136 				if (0 != VbExDiskWrite(disk_handle, 1, 1,
137 						       gptdata->primary_header))
138 					goto fail;
139 			}
140 		}
141 	}
142 
143 	if (gptdata->primary_entries) {
144 		if (gptdata->modified & GPT_MODIFIED_ENTRIES1) {
145 			if (legacy) {
146 				VBDEBUG(("Not updating GPT entries 1: "
147 					 "legacy mode is enabled.\n"));
148 			} else {
149 				VBDEBUG(("Updating GPT entries 1\n"));
150 				if (0 != VbExDiskWrite(disk_handle, entries_lba,
151 						entries_sectors,
152 						gptdata->primary_entries))
153 					goto fail;
154 			}
155 		}
156 	}
157 
158 	entries_lba = (gptdata->gpt_drive_sectors - entries_sectors -
159 		GPT_HEADER_SECTORS);
160 	if (gptdata->secondary_header) {
161 		GptHeader *h = (GptHeader *)(gptdata->secondary_header);
162 		entries_lba = h->entries_lba;
163 		if (gptdata->modified & GPT_MODIFIED_HEADER2) {
164 			VBDEBUG(("Updating GPT entries 2\n"));
165 			if (0 != VbExDiskWrite(disk_handle,
166 					       gptdata->gpt_drive_sectors - 1, 1,
167 					       gptdata->secondary_header))
168 				goto fail;
169 		}
170 	}
171 
172 	if (gptdata->secondary_entries) {
173 		if (gptdata->modified & GPT_MODIFIED_ENTRIES2) {
174 			VBDEBUG(("Updating GPT header 2\n"));
175 			if (0 != VbExDiskWrite(disk_handle,
176 				entries_lba, entries_sectors,
177 				gptdata->secondary_entries))
178 				goto fail;
179 		}
180 	}
181 
182 	ret = 0;
183 
184 fail:
185 	/* Avoid leaking memory on disk write failure */
186 	if (gptdata->primary_header)
187 		VbExFree(gptdata->primary_header);
188 	if (gptdata->primary_entries)
189 		VbExFree(gptdata->primary_entries);
190 	if (gptdata->secondary_entries)
191 		VbExFree(gptdata->secondary_entries);
192 	if (gptdata->secondary_header)
193 		VbExFree(gptdata->secondary_header);
194 
195 	/* Success */
196 	return ret;
197 }
198 
IsUnusedEntry(const GptEntry * e)199 int IsUnusedEntry(const GptEntry *e)
200 {
201 	static Guid zero = {{{0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0}}}};
202 	return !Memcmp(&zero, (const uint8_t*)(&e->type), sizeof(zero));
203 }
204 
205 /*
206  * Func: GptGetEntrySize
207  * Desc: This function returns size(in lba) of a partition represented by
208  * given GPT entry.
209  */
GptGetEntrySizeLba(const GptEntry * e)210 size_t GptGetEntrySizeLba(const GptEntry *e)
211 {
212 	return (e->ending_lba - e->starting_lba + 1);
213 }
214 
215 /*
216  * Func: GptGetEntrySize
217  * Desc: This function returns size(in bytes) of a partition represented by
218  * given GPT entry.
219  */
GptGetEntrySizeBytes(const GptData * gpt,const GptEntry * e)220 size_t GptGetEntrySizeBytes(const GptData *gpt, const GptEntry *e)
221 {
222 	return GptGetEntrySizeLba(e) * gpt->sector_bytes;
223 }
224