1 /* ----------------------------------------------------------------------- *
3 * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
4 * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
5 * Copyright 2010 Shao Miller
6 * Copyright 2010-2012 Michal Soltys
8 * Permission is hereby granted, free of charge, to any person
9 * obtaining a copy of this software and associated documentation
10 * files (the "Software"), to deal in the Software without
11 * restriction, including without limitation the rights to use,
12 * copy, modify, merge, publish, distribute, sublicense, and/or
13 * sell copies of the Software, and to permit persons to whom
14 * the Software is furnished to do so, subject to the following
17 * The above copyright notice and this permission notice shall
18 * be included in all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 * OTHER DEALINGS IN THE SOFTWARE.
29 * ----------------------------------------------------------------------- */
34 * Provides disk / partition iteration.
42 #include <syslinux/disk.h>
46 #define ost_is_ext(type) ((type) == 0x05 || (type) == 0x0F || (type) == 0x85)
47 #define ost_is_nondata(type) (ost_is_ext(type) || (type) == 0x00)
48 #define sane(s,l) ((s)+(l) > (s))
50 /* virtual forwards */
52 static void pi_dtor_(struct part_iter
*);
53 static int pi_next_(struct part_iter
*);
54 static int pi_dos_next(struct part_iter
*);
55 static int pi_gpt_next(struct part_iter
*);
59 static struct itertype types
[] = {
71 const struct itertype
* const typedos
= types
;
72 const struct itertype
* const typegpt
= types
+1;
73 const struct itertype
* const typeraw
= types
+2;
75 /* pi_dtor_() - common/raw iterator cleanup */
76 static void pi_dtor_(struct part_iter
*iter
)
78 /* syslinux's free is null resilient */
82 /* pi_ctor() - common/raw iterator initialization */
83 static int pi_ctor(struct part_iter
*iter
,
84 const struct disk_info
*di
, int flags
87 memcpy(&iter
->di
, di
, sizeof *di
);
90 iter
->length
= di
->lbacnt
;
96 /* pi_dos_ctor() - MBR/EBR iterator specific initialization */
97 static int pi_dos_ctor(struct part_iter
*iter
,
98 const struct disk_info
*di
, int flags
,
99 const struct disk_dos_mbr
*mbr
102 if (pi_ctor(iter
, di
, flags
))
105 if (!(iter
->data
= malloc(sizeof *mbr
))) {
110 memcpy(iter
->data
, mbr
, sizeof *mbr
);
112 iter
->dos
.bebr_index0
= -1;
113 iter
->dos
.disk_sig
= mbr
->disk_sig
;
115 iter
->type
= typedos
;
122 /* pi_gpt_ctor() - GPT iterator specific initialization */
123 static int pi_gpt_ctor(struct part_iter
*iter
,
124 const struct disk_info
*di
, int flags
,
125 const struct disk_gpt_header
*gpth
, const struct disk_gpt_part_entry
*gptl
130 if (pi_ctor(iter
, di
, flags
))
133 siz
= (uint64_t)gpth
->part_count
* gpth
->part_size
;
135 if (!(iter
->data
= malloc((size_t)siz
))) {
140 memcpy(iter
->data
, gptl
, (size_t)siz
);
142 iter
->gpt
.pe_count
= (int)gpth
->part_count
;
143 iter
->gpt
.pe_size
= (int)gpth
->part_size
;
144 iter
->gpt
.ufirst
= gpth
->lba_first_usable
;
145 iter
->gpt
.ulast
= gpth
->lba_last_usable
;
147 memcpy(&iter
->gpt
.disk_guid
, &gpth
->disk_guid
, sizeof gpth
->disk_guid
);
148 memcpy(&iter
->gpt
.part_guid
, &gpth
->disk_guid
, sizeof gpth
->disk_guid
);
150 iter
->type
= typegpt
;
157 /* Logical partition must be sane, meaning:
158 * - must be data or empty
159 * - must have non-0 start and length
160 * - values must not wrap around 32bit
161 * - must be inside current EBR frame
164 static int notsane_logical(const struct part_iter
*iter
)
166 const struct disk_dos_part_entry
*dp
;
169 dp
= ((struct disk_dos_mbr
*)iter
->data
)->table
;
174 if (ost_is_ext(dp
[0].ostype
)) {
175 error("The 1st EBR entry must be data or empty.");
179 if (iter
->flags
& PIF_RELAX
)
182 end_log
= dp
[0].start_lba
+ dp
[0].length
;
184 if (!dp
[0].start_lba
||
186 !sane(dp
[0].start_lba
, dp
[0].length
) ||
187 end_log
> iter
->dos
.nebr_siz
) {
189 error("Logical partition (in EBR) with invalid offset and/or length.");
196 /* Extended partition must be sane, meaning:
197 * - must be extended or empty
198 * - must have non-0 start and length
199 * - values must not wrap around 32bit
200 * - must be inside base EBR frame
203 static int notsane_extended(const struct part_iter
*iter
)
205 const struct disk_dos_part_entry
*dp
;
208 dp
= ((struct disk_dos_mbr
*)iter
->data
)->table
;
213 if (!ost_is_nondata(dp
[1].ostype
)) {
214 error("The 2nd EBR entry must be extended or empty.");
218 if (iter
->flags
& PIF_RELAX
)
221 end_ebr
= dp
[1].start_lba
+ dp
[1].length
;
223 if (!dp
[1].start_lba
||
225 !sane(dp
[1].start_lba
, dp
[1].length
) ||
226 end_ebr
> iter
->dos
.bebr_siz
) {
228 error("Extended partition (EBR) with invalid offset and/or length.");
235 /* Primary partition must be sane, meaning:
236 * - must have non-0 start and length
237 * - values must not wrap around 32bit
240 static int notsane_primary(const struct part_iter
*iter
)
242 const struct disk_dos_part_entry
*dp
;
243 dp
= ((struct disk_dos_mbr
*)iter
->data
)->table
+ iter
->index0
;
248 if (iter
->flags
& PIF_RELAX
)
251 if (!dp
->start_lba
||
253 !sane(dp
->start_lba
, dp
->length
) ||
254 dp
->start_lba
+ dp
->length
> iter
->di
.lbacnt
) {
255 error("Primary partition (in MBR) with invalid offset and/or length.");
262 static int notsane_gpt(const struct part_iter
*iter
)
264 const struct disk_gpt_part_entry
*gp
;
265 gp
= (const struct disk_gpt_part_entry
*)
266 (iter
->data
+ iter
->index0
* iter
->gpt
.pe_size
);
268 if (guid_is0(&gp
->type
))
271 if (iter
->flags
& PIF_RELAX
)
274 if (gp
->lba_first
< iter
->gpt
.ufirst
||
275 gp
->lba_last
> iter
->gpt
.ulast
) {
276 error("LBA sectors of GPT partition are beyond the range allowed in GPT header.");
283 static int dos_next_mbr(struct part_iter
*iter
, uint32_t *lba
,
284 struct disk_dos_part_entry
**_dp
)
286 struct disk_dos_part_entry
*dp
;
288 while (++iter
->index0
< 4) {
289 dp
= ((struct disk_dos_mbr
*)iter
->data
)->table
+ iter
->index0
;
291 if (notsane_primary(iter
)) {
292 iter
->status
= PI_INSANE
;
296 if (ost_is_ext(dp
->ostype
)) {
297 if (iter
->dos
.bebr_index0
>= 0) {
298 error("More than 1 extended partition.");
299 iter
->status
= PI_INSANE
;
302 /* record base EBR index */
303 iter
->dos
.bebr_index0
= iter
->index0
;
305 if (!ost_is_nondata(dp
->ostype
) || (iter
->flags
& PIF_STEPALL
)) {
306 *lba
= dp
->start_lba
;
315 static int prep_base_ebr(struct part_iter
*iter
)
317 struct disk_dos_part_entry
*dp
;
319 if (iter
->dos
.bebr_index0
< 0) /* if we don't have base extended partition at all */
321 else if (!iter
->dos
.bebr_lba
) { /* if not initialized yet */
322 dp
= ((struct disk_dos_mbr
*)iter
->data
)->table
+ iter
->dos
.bebr_index0
;
324 iter
->dos
.bebr_lba
= dp
->start_lba
;
325 iter
->dos
.bebr_siz
= dp
->length
;
327 iter
->dos
.nebr_lba
= dp
->start_lba
;
328 iter
->dos
.nebr_siz
= dp
->length
;
335 static int dos_next_ebr(struct part_iter
*iter
, uint32_t *lba
,
336 struct disk_dos_part_entry
**_dp
)
338 struct disk_dos_part_entry
*dp
;
340 if (prep_base_ebr(iter
) < 0) {
341 iter
->status
= PI_DONE
;
345 while (++iter
->index0
< 1024 && iter
->dos
.nebr_lba
) {
348 disk_read_sectors(&iter
->di
, iter
->dos
.nebr_lba
, 1))) {
349 error("Couldn't load EBR.");
350 iter
->status
= PI_ERRLOAD
;
354 /* check sanity of loaded data */
355 if (notsane_logical(iter
) || notsane_extended(iter
)) {
356 iter
->status
= PI_INSANE
;
360 dp
= ((struct disk_dos_mbr
*)iter
->data
)->table
;
362 iter
->dos
.cebr_lba
= iter
->dos
.nebr_lba
;
363 iter
->dos
.cebr_siz
= iter
->dos
.nebr_siz
;
365 /* setup next frame values */
367 iter
->dos
.nebr_lba
= iter
->dos
.bebr_lba
+ dp
[1].start_lba
;
368 iter
->dos
.nebr_siz
= dp
[1].length
;
370 iter
->dos
.nebr_lba
= 0;
371 iter
->dos
.nebr_siz
= 0;
375 iter
->dos
.logskipcnt
++;
377 if (dp
[0].ostype
|| (iter
->flags
& PIF_STEPALL
)) {
378 *lba
= dp
[0].start_lba
? iter
->dos
.cebr_lba
+ dp
[0].start_lba
: 0;
383 * This way it's possible to continue, if some crazy soft left a "hole"
384 * - EBR with a valid extended partition without a logical one. In
385 * such case, linux will not reserve a number for such hole - so we
386 * don't increase index0. If PIF_STEPALL flag is set, we will never
390 iter
->status
= PI_DONE
;
394 static void gpt_conv_label(struct part_iter
*iter
)
396 const struct disk_gpt_part_entry
*gp
;
397 const int16_t *orig_lab
;
399 gp
= (const struct disk_gpt_part_entry
*)
400 (iter
->data
+ iter
->index0
* iter
->gpt
.pe_size
);
401 orig_lab
= (const int16_t *)gp
->name
;
403 /* caveat: this is very crude conversion */
404 for (int i
= 0; i
< PI_GPTLABSIZE
/2; i
++) {
405 iter
->gpt
.part_label
[i
] = (char)orig_lab
[i
];
407 iter
->gpt
.part_label
[PI_GPTLABSIZE
/2] = 0;
410 static inline int valid_crc(uint32_t crc
, const uint8_t *buf
, unsigned int siz
)
412 return crc
== crc32(crc32(0, NULL
, 0), buf
, siz
);
415 static int gpt_check_hdr_crc(const struct disk_info
* const diskinfo
, struct disk_gpt_header
**_gh
)
417 struct disk_gpt_header
*gh
= *_gh
;
421 hold_crc32
= gh
->chksum
;
423 if (!valid_crc(hold_crc32
, (const uint8_t *)gh
, gh
->hdr_size
)) {
424 warn("Primary GPT header checksum invalid.");
425 /* retry with backup */
426 lba_alt
= gh
->lba_alt
;
428 if (!(gh
= *_gh
= disk_read_sectors(diskinfo
, lba_alt
, 1))) {
429 error("Couldn't read backup GPT header.");
432 hold_crc32
= gh
->chksum
;
434 if (!valid_crc(hold_crc32
, (const uint8_t *)gh
, gh
->hdr_size
)) {
435 error("Secondary GPT header checksum invalid.");
439 /* restore old checksum */
440 gh
->chksum
= hold_crc32
;
445 static int pi_next_(struct part_iter
*iter
)
447 iter
->status
= PI_DONE
;
451 static int pi_dos_next(struct part_iter
*iter
)
453 uint32_t abs_lba
= 0;
454 struct disk_dos_part_entry
*dos_part
= NULL
;
459 /* look for primary partitions */
460 if (iter
->index0
< 4 &&
461 dos_next_mbr(iter
, &abs_lba
, &dos_part
) < 0)
464 /* look for logical partitions */
465 if (iter
->index0
>= 4 &&
466 dos_next_ebr(iter
, &abs_lba
, &dos_part
) < 0)
470 * note special index handling:
471 * in case PIF_STEPALL is set - this makes the index consistent with
472 * non-PIF_STEPALL iterators
475 if (!dos_part
->ostype
)
478 iter
->index
= iter
->index0
+ 1 - iter
->dos
.logskipcnt
;
479 iter
->abs_lba
= abs_lba
;
480 iter
->length
= dos_part
->length
;
481 iter
->record
= (char *)dos_part
;
484 disk_dos_part_dump(dos_part
);
490 static int pi_gpt_next(struct part_iter
*iter
)
492 const struct disk_gpt_part_entry
*gpt_part
= NULL
;
497 while (++iter
->index0
< iter
->gpt
.pe_count
) {
498 gpt_part
= (const struct disk_gpt_part_entry
*)
499 (iter
->data
+ iter
->index0
* iter
->gpt
.pe_size
);
501 if (notsane_gpt(iter
)) {
502 iter
->status
= PI_INSANE
;
506 if (!guid_is0(&gpt_part
->type
) || (iter
->flags
& PIF_STEPALL
))
509 /* no more partitions ? */
510 if (iter
->index0
== iter
->gpt
.pe_count
) {
511 iter
->status
= PI_DONE
;
514 /* gpt_part is guaranteed to be valid here */
515 iter
->index
= iter
->index0
+ 1;
516 iter
->abs_lba
= gpt_part
->lba_first
;
517 iter
->length
= gpt_part
->lba_last
- gpt_part
->lba_first
+ 1;
518 iter
->record
= (char *)gpt_part
;
519 memcpy(&iter
->gpt
.part_guid
, &gpt_part
->uid
, sizeof(struct guid
));
520 gpt_conv_label(iter
);
523 disk_gpt_part_dump(gpt_part
);
529 static struct part_iter
*pi_alloc(void)
531 struct part_iter
*iter
;
532 if (!(iter
= malloc(sizeof *iter
)))
535 memset(iter
, 0, sizeof *iter
);
539 /* pi_del() - delete iterator */
540 void pi_del(struct part_iter
**_iter
)
542 if(!_iter
|| !*_iter
)
549 /* pi_begin() - validate and and get proper iterator for a disk described by di */
550 struct part_iter
*pi_begin(const struct disk_info
*di
, int flags
)
552 int gptprot
, ret
= -1;
553 struct part_iter
*iter
;
554 struct disk_dos_mbr
*mbr
= NULL
;
555 struct disk_gpt_header
*gpth
= NULL
;
556 struct disk_gpt_part_entry
*gptl
= NULL
;
558 /* Preallocate iterator */
559 if (!(iter
= pi_alloc()))
563 if (!(mbr
= disk_read_sectors(di
, 0, 1))) {
564 error("Couldn't read the first disk sector.");
568 /* Check for MBR magic */
569 if (mbr
->sig
!= disk_mbr_sig_magic
) {
570 warn("No MBR magic, treating disk as raw.");
572 ret
= pi_ctor(iter
, di
, flags
);
576 /* Check for GPT protective MBR */
578 for (size_t i
= 0; i
< 4; i
++)
579 gptprot
|= (mbr
->table
[i
].ostype
== 0xEE);
580 if (gptprot
&& !(flags
& PIF_PREFMBR
)) {
581 if (!(gpth
= disk_read_sectors(di
, 1, 1))) {
582 error("Couldn't read potential GPT header.");
587 if (gpth
&& gpth
->rev
.uint32
== 0x00010000 &&
588 !memcmp(gpth
->sig
, disk_gpt_sig_magic
, sizeof gpth
->sig
)) {
589 /* looks like GPT v1.0 */
590 uint64_t gpt_loff
; /* offset to GPT partition list in sectors */
591 uint64_t gpt_lsiz
; /* size of GPT partition list in bytes */
592 uint64_t gpt_lcnt
; /* size of GPT partition in sectors */
594 dprintf("Looks like a GPT v1.0 disk.\n");
595 disk_gpt_header_dump(gpth
);
597 /* Verify checksum, fallback to backup, then bail if invalid */
598 if (gpt_check_hdr_crc(di
, &gpth
))
601 gpt_loff
= gpth
->lba_table
;
602 gpt_lsiz
= (uint64_t)gpth
->part_size
* gpth
->part_count
;
603 gpt_lcnt
= (gpt_lsiz
+ di
->bps
- 1) / di
->bps
;
606 * disk_read_sectors allows reading of max 255 sectors, so we use
607 * it as a sanity check base. EFI doesn't specify max (AFAIK).
608 * Apart from that, some extensive sanity checks.
610 if (!(flags
& PIF_RELAX
) && (
611 !gpt_loff
|| !gpt_lsiz
|| gpt_lcnt
> 255u ||
612 gpth
->lba_first_usable
> gpth
->lba_last_usable
||
613 !sane(gpt_loff
, gpt_lcnt
) ||
614 gpt_loff
+ gpt_lcnt
> gpth
->lba_first_usable
||
615 !sane(gpth
->lba_last_usable
, gpt_lcnt
) ||
616 gpth
->lba_last_usable
+ gpt_lcnt
>= gpth
->lba_alt
||
617 gpth
->lba_alt
>= di
->lbacnt
||
618 gpth
->part_size
< sizeof *gptl
)) {
619 error("Invalid GPT header's values.");
622 if (!(gptl
= disk_read_sectors(di
, gpt_loff
, gpt_lcnt
))) {
623 error("Couldn't read GPT partition list.");
626 /* Check array checksum(s). */
627 if (!valid_crc(gpth
->table_chksum
, (const uint8_t *)gptl
, (unsigned int)gpt_lsiz
)) {
628 warn("Checksum of the main GPT partition list is invalid, trying backup.");
630 /* secondary array directly precedes secondary header */
631 if (!(gptl
= disk_read_sectors(di
, gpth
->lba_alt
- gpt_lcnt
, gpt_lcnt
))) {
632 error("Couldn't read backup GPT partition list.");
635 if (!valid_crc(gpth
->table_chksum
, (const uint8_t *)gptl
, gpt_lsiz
)) {
636 error("Checksum of the backup GPT partition list is invalid, giving up.");
641 ret
= pi_gpt_ctor(iter
, di
, flags
, gpth
, gptl
);
644 ret
= pi_dos_ctor(iter
, di
, flags
, mbr
);
656 /* vim: set ts=8 sts=4 sw=4 noet: */