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 "2common.h"
7 #include "2sysincludes.h"
8 #include "cgptlib.h"
9 #include "cgptlib_internal.h"
10 #include "crc32.h"
11 #include "gpt.h"
12 #include "vboot_api.h"
13
14 /**
15 * Allocate and read GPT data from the drive.
16 *
17 * The sector_bytes and gpt_drive_sectors fields should be filled on input. The
18 * primary and secondary header and entries are filled on output.
19 *
20 * Returns 0 if successful, 1 if error.
21 */
AllocAndReadGptData(vb2ex_disk_handle_t disk_handle,GptData * gptdata)22 int AllocAndReadGptData(vb2ex_disk_handle_t disk_handle, GptData *gptdata)
23 {
24 int primary_valid = 0, secondary_valid = 0;
25
26 /* No data to be written yet */
27 gptdata->modified = 0;
28 /* This should get overwritten by GptInit() */
29 gptdata->ignored = 0;
30
31 /* Allocate all buffers */
32 gptdata->primary_header = (uint8_t *)malloc(gptdata->sector_bytes);
33 gptdata->secondary_header =
34 (uint8_t *)malloc(gptdata->sector_bytes);
35 gptdata->primary_entries = (uint8_t *)malloc(GPT_ENTRIES_ALLOC_SIZE);
36 gptdata->secondary_entries = (uint8_t *)malloc(GPT_ENTRIES_ALLOC_SIZE);
37
38 /* In some cases we try to validate header1 with entries2 or vice versa,
39 so make sure the entries buffers always got fully initialized. */
40 memset(gptdata->primary_entries, 0, GPT_ENTRIES_ALLOC_SIZE);
41 memset(gptdata->secondary_entries, 0, GPT_ENTRIES_ALLOC_SIZE);
42
43 if (gptdata->primary_header == NULL ||
44 gptdata->secondary_header == NULL ||
45 gptdata->primary_entries == NULL ||
46 gptdata->secondary_entries == NULL)
47 return 1;
48
49 /* Read primary header from the drive, skipping the protective MBR */
50 if (0 != VbExDiskRead(disk_handle, 1, 1, gptdata->primary_header)) {
51 VB2_DEBUG("Read error in primary GPT header\n");
52 memset(gptdata->primary_header, 0, gptdata->sector_bytes);
53 }
54
55 /* Only read primary GPT if the primary header is valid */
56 GptHeader* primary_header = (GptHeader*)gptdata->primary_header;
57 if (0 == CheckHeader(primary_header, 0,
58 gptdata->streaming_drive_sectors,
59 gptdata->gpt_drive_sectors,
60 gptdata->flags,
61 gptdata->sector_bytes)) {
62 primary_valid = 1;
63 uint64_t entries_bytes =
64 (uint64_t)primary_header->number_of_entries
65 * primary_header->size_of_entry;
66 uint64_t entries_sectors =
67 (entries_bytes + gptdata->sector_bytes - 1)
68 / gptdata->sector_bytes;
69 if (0 != VbExDiskRead(disk_handle,
70 primary_header->entries_lba,
71 entries_sectors,
72 gptdata->primary_entries)) {
73 VB2_DEBUG("Read error in primary GPT entries\n");
74 primary_valid = 0;
75 }
76 } else {
77 VB2_DEBUG("Primary GPT header is %s\n",
78 memcmp(primary_header->signature,
79 GPT_HEADER_SIGNATURE_IGNORED,
80 GPT_HEADER_SIGNATURE_SIZE)
81 ? "invalid" : "being ignored");
82 }
83
84 /* Read secondary header from the end of the drive */
85 if (0 != VbExDiskRead(disk_handle, gptdata->gpt_drive_sectors - 1, 1,
86 gptdata->secondary_header)) {
87 VB2_DEBUG("Read error in secondary GPT header\n");
88 memset(gptdata->secondary_header, 0, gptdata->sector_bytes);
89 }
90
91 /* Only read secondary GPT if the secondary header is valid */
92 GptHeader* secondary_header = (GptHeader*)gptdata->secondary_header;
93 if (0 == CheckHeader(secondary_header, 1,
94 gptdata->streaming_drive_sectors,
95 gptdata->gpt_drive_sectors,
96 gptdata->flags,
97 gptdata->sector_bytes)) {
98 secondary_valid = 1;
99 uint64_t entries_bytes =
100 (uint64_t)secondary_header->number_of_entries
101 * secondary_header->size_of_entry;
102 uint64_t entries_sectors =
103 (entries_bytes + gptdata->sector_bytes - 1)
104 / gptdata->sector_bytes;
105 if (0 != VbExDiskRead(disk_handle,
106 secondary_header->entries_lba,
107 entries_sectors,
108 gptdata->secondary_entries)) {
109 VB2_DEBUG("Read error in secondary GPT entries\n");
110 secondary_valid = 0;
111 }
112 } else {
113 VB2_DEBUG("Secondary GPT header is %s\n",
114 memcmp(secondary_header->signature,
115 GPT_HEADER_SIGNATURE_IGNORED,
116 GPT_HEADER_SIGNATURE_SIZE)
117 ? "invalid" : "being ignored");
118 }
119
120 /* Return 0 if least one GPT header was valid */
121 return (primary_valid || secondary_valid) ? 0 : 1;
122 }
123
124 /**
125 * Write any changes for the GPT data back to the drive, then free the buffers.
126 *
127 * Returns 0 if successful, 1 if error.
128 */
WriteAndFreeGptData(vb2ex_disk_handle_t disk_handle,GptData * gptdata)129 int WriteAndFreeGptData(vb2ex_disk_handle_t disk_handle, GptData *gptdata)
130 {
131 int skip_primary = 0;
132 GptHeader *header;
133 uint64_t entries_bytes, entries_sectors;
134 int ret = 1;
135
136 header = (GptHeader *)gptdata->primary_header;
137 if (!header)
138 header = (GptHeader *)gptdata->secondary_header;
139 if (!header)
140 return 1; /* No headers at all, so nothing to write */
141
142 entries_bytes = (uint64_t)header->number_of_entries
143 * header->size_of_entry;
144 entries_sectors = entries_bytes / gptdata->sector_bytes;
145
146 /*
147 * TODO(namnguyen): Preserve padding between primary GPT header and
148 * its entries.
149 */
150 uint64_t entries_lba = GPT_PMBR_SECTORS + GPT_HEADER_SECTORS;
151 if (gptdata->primary_header) {
152 GptHeader *h = (GptHeader *)(gptdata->primary_header);
153 entries_lba = h->entries_lba;
154
155 if (gptdata->ignored & MASK_PRIMARY) {
156 VB2_DEBUG("Not updating primary GPT: "
157 "marked to be ignored.\n");
158 skip_primary = 1;
159 } else if (gptdata->modified & GPT_MODIFIED_HEADER1) {
160 if (!memcmp(h->signature, GPT_HEADER_SIGNATURE2,
161 GPT_HEADER_SIGNATURE_SIZE)) {
162 VB2_DEBUG("Not updating primary GPT: "
163 "legacy mode is enabled.\n");
164 skip_primary = 1;
165 } else {
166 VB2_DEBUG("Updating GPT header 1\n");
167 if (0 != VbExDiskWrite(disk_handle, 1, 1,
168 gptdata->primary_header))
169 goto fail;
170 }
171 }
172 }
173
174 if (gptdata->primary_entries && !skip_primary) {
175 if (gptdata->modified & GPT_MODIFIED_ENTRIES1) {
176 VB2_DEBUG("Updating GPT entries 1\n");
177 if (0 != VbExDiskWrite(disk_handle, entries_lba,
178 entries_sectors,
179 gptdata->primary_entries))
180 goto fail;
181 }
182 }
183
184 entries_lba = (gptdata->gpt_drive_sectors - entries_sectors -
185 GPT_HEADER_SECTORS);
186 if (gptdata->secondary_header && !(gptdata->ignored & MASK_SECONDARY)) {
187 GptHeader *h = (GptHeader *)(gptdata->secondary_header);
188 entries_lba = h->entries_lba;
189 if (gptdata->modified & GPT_MODIFIED_HEADER2) {
190 VB2_DEBUG("Updating GPT header 2\n");
191 if (0 != VbExDiskWrite(disk_handle,
192 gptdata->gpt_drive_sectors - 1, 1,
193 gptdata->secondary_header))
194 goto fail;
195 }
196 }
197
198 if (gptdata->secondary_entries && !(gptdata->ignored & MASK_SECONDARY)){
199 if (gptdata->modified & GPT_MODIFIED_ENTRIES2) {
200 VB2_DEBUG("Updating GPT entries 2\n");
201 if (0 != VbExDiskWrite(disk_handle,
202 entries_lba, entries_sectors,
203 gptdata->secondary_entries))
204 goto fail;
205 }
206 }
207
208 ret = 0;
209
210 fail:
211 /* Avoid leaking memory on disk write failure */
212 if (gptdata->primary_header)
213 free(gptdata->primary_header);
214 if (gptdata->primary_entries)
215 free(gptdata->primary_entries);
216 if (gptdata->secondary_entries)
217 free(gptdata->secondary_entries);
218 if (gptdata->secondary_header)
219 free(gptdata->secondary_header);
220
221 /* Success */
222 return ret;
223 }
224
IsUnusedEntry(const GptEntry * e)225 int IsUnusedEntry(const GptEntry *e)
226 {
227 static Guid zero = {{{0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0}}}};
228 return !memcmp(&zero, (const uint8_t*)(&e->type), sizeof(zero));
229 }
230
231 /*
232 * Func: GptGetEntrySize
233 * Desc: This function returns size(in lba) of a partition represented by
234 * given GPT entry.
235 */
GptGetEntrySizeLba(const GptEntry * e)236 uint64_t GptGetEntrySizeLba(const GptEntry *e)
237 {
238 return (e->ending_lba - e->starting_lba + 1);
239 }
240
241 /*
242 * Func: GptGetEntrySize
243 * Desc: This function returns size(in bytes) of a partition represented by
244 * given GPT entry.
245 */
GptGetEntrySizeBytes(const GptData * gpt,const GptEntry * e)246 uint64_t GptGetEntrySizeBytes(const GptData *gpt, const GptEntry *e)
247 {
248 return GptGetEntrySizeLba(e) * gpt->sector_bytes;
249 }
250