From 26e78ed6574a439d4ec35dcffcbb12dac6e7abcb Mon Sep 17 00:00:00 2001 From: miod Date: Sun, 13 Jul 2014 15:32:28 +0000 Subject: [PATCH] Initial support to read GPT partition tables in the kernel, if option GPT. Contributed by Markus Mueller; code based upon Bitrig's GPT support, with stricter GPT structures validation and support for alternate header places. ok deraadt@ jsing@ krw@ --- sys/arch/amd64/amd64/disksubr.c | 8 +- sys/arch/amd64/conf/GENERIC | 3 +- sys/arch/i386/conf/GENERIC | 3 +- sys/arch/i386/i386/disksubr.c | 8 +- sys/conf/files | 5 +- sys/kern/kern_uuid.c | 151 +++++++++++++++ sys/kern/subr_disk.c | 324 +++++++++++++++++++++++++++++++- sys/sys/disklabel.h | 98 +++++++++- sys/sys/uuid.h | 75 ++++++++ 9 files changed, 667 insertions(+), 8 deletions(-) create mode 100644 sys/kern/kern_uuid.c create mode 100644 sys/sys/uuid.h diff --git a/sys/arch/amd64/amd64/disksubr.c b/sys/arch/amd64/amd64/disksubr.c index e2f1c1a5e61..ae83a2c6611 100644 --- a/sys/arch/amd64/amd64/disksubr.c +++ b/sys/arch/amd64/amd64/disksubr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: disksubr.c,v 1.66 2014/06/15 11:43:24 sf Exp $ */ +/* $OpenBSD: disksubr.c,v 1.67 2014/07/13 15:32:28 miod Exp $ */ /* $NetBSD: disksubr.c,v 1.21 1996/05/03 19:42:03 christos Exp $ */ /* @@ -91,6 +91,12 @@ readdisklabel(dev_t dev, void (*strat)(struct buf *), bp = geteblk((int)lp->d_secsize); bp->b_dev = dev; +#if defined(GPT) + error = readgptlabel(bp, strat, lp, NULL, spoofonly); + if (error == 0) + goto done; +#endif + error = readdoslabel(bp, strat, lp, NULL, spoofonly); if (error == 0) goto done; diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC index bff331e8e3c..901af9ebcbc 100644 --- a/sys/arch/amd64/conf/GENERIC +++ b/sys/arch/amd64/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.371 2014/07/12 21:56:56 tedu Exp $ +# $OpenBSD: GENERIC,v 1.372 2014/07/13 15:32:28 miod Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -22,6 +22,7 @@ option MTRR # CPU memory range attributes control #option KGDB # Remote debugger support; exclusive of DDB #option "KGDB_DEVNAME=\"com\"",KGDBADDR=0x2f8,KGDBRATE=9600 +option GPT # GPT partition table support option NTFS # NTFS support option HIBERNATE # Hibernate support diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC index 87300279bb4..76556799dfb 100644 --- a/sys/arch/i386/conf/GENERIC +++ b/sys/arch/i386/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.780 2014/07/12 21:56:56 tedu Exp $ +# $OpenBSD: GENERIC,v 1.781 2014/07/13 15:32:28 miod Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -27,6 +27,7 @@ option MTRR # CPU memory range attributes control option COMPAT_LINUX # binary compatibility with Linux #option PROCFS # /proc, currently broken +option GPT # GPT partition table support option NTFS # NTFS support option HIBERNATE # Hibernate support diff --git a/sys/arch/i386/i386/disksubr.c b/sys/arch/i386/i386/disksubr.c index 6da9f77a7bd..a8bf13d7bb0 100644 --- a/sys/arch/i386/i386/disksubr.c +++ b/sys/arch/i386/i386/disksubr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: disksubr.c,v 1.106 2014/06/15 11:43:24 sf Exp $ */ +/* $OpenBSD: disksubr.c,v 1.107 2014/07/13 15:32:28 miod Exp $ */ /* $NetBSD: disksubr.c,v 1.21 1996/05/03 19:42:03 christos Exp $ */ /* @@ -93,6 +93,12 @@ readdisklabel(dev_t dev, void (*strat)(struct buf *), bp = geteblk((int)lp->d_secsize); bp->b_dev = dev; +#if defined(GPT) + error = readgptlabel(bp, strat, lp, NULL, spoofonly); + if (error == 0) + goto done; +#endif + error = readdoslabel(bp, strat, lp, NULL, spoofonly); if (error == 0) goto done; diff --git a/sys/conf/files b/sys/conf/files index 2ba37e05d54..3941639281a 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $OpenBSD: files,v 1.574 2014/07/13 13:28:26 pelikan Exp $ +# $OpenBSD: files,v 1.575 2014/07/13 15:32:28 miod Exp $ # $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -693,6 +693,7 @@ file kern/kern_synch.c file kern/kern_tc.c file kern/kern_time.c file kern/kern_timeout.c +file kern/kern_uuid.c gpt file kern/kern_watchdog.c !small_kernel file kern/kern_workq.c file kern/kern_task.c @@ -1042,7 +1043,7 @@ file lib/libkern/arch/${MACHINE_ARCH}/htons.S | lib/libkern/htons.c file lib/libkern/arch/${MACHINE_ARCH}/strncasecmp.S | lib/libkern/strncasecmp.c file lib/libz/adler32.c ppp_deflate | ipsec | crypto | bios -file lib/libz/crc32.c ppp_deflate | ipsec | crypto +file lib/libz/crc32.c ppp_deflate | ipsec | crypto | gpt file lib/libz/infback.c ppp_deflate | ipsec | crypto file lib/libz/inffast.c ppp_deflate | ipsec | crypto file lib/libz/inflate.c ppp_deflate | ipsec | crypto diff --git a/sys/kern/kern_uuid.c b/sys/kern/kern_uuid.c new file mode 100644 index 00000000000..7505bf42834 --- /dev/null +++ b/sys/kern/kern_uuid.c @@ -0,0 +1,151 @@ +/* $OpenBSD: kern_uuid.c,v 1.1 2014/07/13 15:32:28 miod Exp $ */ +/* $NetBSD: kern_uuid.c,v 1.18 2011/11/19 22:51:25 tls Exp $ */ + +/* + * Copyright (c) 2002 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: /repoman/r/ncvs/src/sys/kern/kern_uuid.c,v 1.7 2004/01/12 +13:34:11 rse Exp $ + */ + +#include +#include +#include +#include + +/* + * For a description of UUIDs see RFC 4122. + */ + +struct uuid_private { + struct { + uint32_t low; + uint16_t mid; + uint16_t hi; + } time; + uint16_t seq; + uint16_t node[UUID_NODE_LEN>>1]; +}; + +#ifdef DEBUG +int +uuid_snprintf(char *buf, size_t sz, const struct uuid *uuid) +{ + const struct uuid_private *id; + int cnt; + + id = (const struct uuid_private *)uuid; + cnt = snprintf(buf, sz, "%08x-%04x-%04x-%04x-%04x%04x%04x", + id->time.low, id->time.mid, id->time.hi, betoh16(id->seq), + betoh16(id->node[0]), betoh16(id->node[1]), betoh16(id->node[2])); + return (cnt); +} + +int +uuid_printf(const struct uuid *uuid) +{ + char buf[_UUID_BUF_LEN]; + + (void) uuid_snprintf(buf, sizeof(buf), uuid); + printf("%s", buf); + return (0); +} +#endif + +/* + * Encode/Decode UUID into octet-stream. + * + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | time_low | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | time_mid | time_hi_and_version | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |clk_seq_hi_res | clk_seq_low | node (0-1) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | node (2-5) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + +void +uuid_enc_le(void *buf, const struct uuid *uuid) +{ + uint8_t *p = buf; + int i; + + p[0] = htole32(uuid->time_low); + p[4] = htole16(uuid->time_mid); + p[6] = htole16(uuid->time_hi_and_version); + p[8] = uuid->clock_seq_hi_and_reserved; + p[9] = uuid->clock_seq_low; + for (i = 0; i < UUID_NODE_LEN; i++) + p[10 + i] = uuid->node[i]; +} + +void +uuid_dec_le(void const *buf, struct uuid *uuid) +{ + const uint8_t *p = buf; + int i; + + uuid->time_low = letoh32(*(uint32_t*)p); + uuid->time_mid = letoh16(*(uint16_t*)(p + 4)); + uuid->time_hi_and_version = letoh16(*(uint16_t*)(p + 6)); + uuid->clock_seq_hi_and_reserved = p[8]; + uuid->clock_seq_low = p[9]; + for (i = 0; i < UUID_NODE_LEN; i++) + uuid->node[i] = p[10 + i]; +} + +void +uuid_enc_be(void *buf, const struct uuid *uuid) +{ + uint8_t *p = buf; + int i; + + p[0] = htobe32(uuid->time_low); + p[4] = htobe16(uuid->time_mid); + p[6] = htobe16(uuid->time_hi_and_version); + p[8] = uuid->clock_seq_hi_and_reserved; + p[9] = uuid->clock_seq_low; + for (i = 0; i < UUID_NODE_LEN; i++) + p[10 + i] = uuid->node[i]; +} + +void +uuid_dec_be(void const *buf, struct uuid *uuid) +{ + const uint8_t *p = buf; + int i; + + uuid->time_low = betoh32(*(uint32_t*)p); + uuid->time_mid = betoh16(*(uint16_t*)(p + 4)); + uuid->time_hi_and_version = betoh16(*(uint16_t*)(p + 6)); + uuid->clock_seq_hi_and_reserved = p[8]; + uuid->clock_seq_low = p[9]; + for (i = 0; i < UUID_NODE_LEN; i++) + uuid->node[i] = p[10 + i]; +} diff --git a/sys/kern/subr_disk.c b/sys/kern/subr_disk.c index 95fc03e0e91..3262da52107 100644 --- a/sys/kern/subr_disk.c +++ b/sys/kern/subr_disk.c @@ -1,4 +1,4 @@ -/* $OpenBSD: subr_disk.c,v 1.167 2014/07/12 18:43:32 tedu Exp $ */ +/* $OpenBSD: subr_disk.c,v 1.168 2014/07/13 15:32:28 miod Exp $ */ /* $NetBSD: subr_disk.c,v 1.17 1996/03/16 23:17:08 christos Exp $ */ /* @@ -66,8 +66,16 @@ #include #include +#include + #include "softraid.h" +#ifdef DEBUG +#define DPRINTF(x...) printf(x) +#else +#define DPRINTF(x...) +#endif + /* * A global list of all disks attached to the system. May grow or * shrink over time. @@ -530,6 +538,320 @@ notfat: return (error); } +#ifdef GPT + +int gpt_chk_hdr(struct gpt_header *); +int gpt_chk_parts(struct gpt_header *, struct gpt_partition *); +int get_fstype(struct uuid *); + +int +gpt_chk_hdr(struct gpt_header *gh) +{ + u_int32_t orig_gh_csum = gh->gh_csum; + gh->gh_csum = 0; + gh->gh_csum = crc32(0, (unsigned char *)gh, gh->gh_size); + + if (orig_gh_csum != gh->gh_csum) + return (EINVAL); + + return 0; +} + +int +gpt_chk_parts(struct gpt_header *gh, struct gpt_partition *gp) +{ + u_int32_t checksum; + checksum = crc32(0, (unsigned char *)gp, + gh->gh_part_num * gh->gh_part_size); + + if (checksum != gh->gh_part_csum) + return (EINVAL); + + return 0; +} + +int +get_fstype(struct uuid *uuid_part) +{ + static int init = 0; + static struct uuid uuid_openbsd, uuid_msdos, uuid_chromefs, + uuid_linux, uuid_hfs, uuid_unused; + static const uint8_t gpt_uuid_openbsd[] = GPT_UUID_OPENBSD; + static const uint8_t gpt_uuid_msdos[] = GPT_UUID_MSDOS; + static const uint8_t gpt_uuid_chromerootfs[] = GPT_UUID_CHROMEROOTFS; + static const uint8_t gpt_uuid_linux[] = GPT_UUID_LINUX; + static const uint8_t gpt_uuid_hfs[] = GPT_UUID_APPLE_HFS; + static const uint8_t gpt_uuid_unused[] = GPT_UUID_UNUSED; + + if (init == 0) { + uuid_dec_be(gpt_uuid_openbsd, &uuid_openbsd); + uuid_dec_be(gpt_uuid_msdos, &uuid_msdos); + uuid_dec_be(gpt_uuid_chromerootfs, &uuid_chromefs); + uuid_dec_be(gpt_uuid_linux, &uuid_linux); + uuid_dec_be(gpt_uuid_hfs, &uuid_hfs); + uuid_dec_be(gpt_uuid_unused, &uuid_unused); + init = 1; + } + + if (!memcmp(uuid_part, &uuid_unused, sizeof(struct uuid))) + return FS_UNUSED; + else if (!memcmp(uuid_part, &uuid_openbsd, sizeof(struct uuid))) + return FS_BSDFFS; + else if (!memcmp(uuid_part, &uuid_msdos, sizeof(struct uuid))) + return FS_MSDOS; + else if (!memcmp(uuid_part, &uuid_chromefs, sizeof(struct uuid))) + return FS_EXT2FS; + else if (!memcmp(uuid_part, &uuid_linux, sizeof(struct uuid))) + return FS_EXT2FS; + else if (!memcmp(uuid_part, &uuid_hfs, sizeof(struct uuid))) + return FS_HFS; + else + return FS_OTHER; +} + +/* + * If gpt partition table requested, attempt to load it and + * find disklabel inside a GPT partition. Return buffer + * for use in signalling errors if requested. + * + * XXX: readgptlabel() is based on readdoslabel(), so they should be merged + */ +int +readgptlabel(struct buf *bp, void (*strat)(struct buf *), + struct disklabel *lp, daddr_t *partoffp, int spoofonly) +{ + struct gpt_header gh; + struct gpt_partition *gp, *gp_tmp; + size_t gpsz; + struct uuid uuid_part, uuid_openbsd; + struct partition *pp; + + daddr_t part_blkno; + u_int64_t gptpartoff = 0, gptpartend = DL_GETBEND(lp); + int i, altheader = 0, error, n=0, ourpart = -1, offset; + + static const u_int8_t gpt_uuid_openbsd[] = GPT_UUID_OPENBSD; + u_int8_t fstype; + + uuid_dec_be(gpt_uuid_openbsd, &uuid_openbsd); + + if (lp->d_secpercyl == 0) + return (EINVAL); /* invalid label */ + if (lp->d_secsize == 0) + return (ENOSPC); /* disk too small */ + + /* + * XXX: We should not trust the primary header and instead + * use the last LBA of the disk, as defined in the standard. + */ + for (part_blkno = GPTSECTOR; ; part_blkno = gh.gh_lba_alt, + altheader = 1) { + /* read header record */ + bp->b_blkno = DL_BLKTOSEC(lp, part_blkno) * DL_BLKSPERSEC(lp); + offset = DL_BLKOFFSET(lp, part_blkno); + bp->b_bcount = lp->d_secsize; + bp->b_error = 0; /* B_ERROR and b_error may have stale data. */ + CLR(bp->b_flags, B_READ | B_WRITE | B_DONE | B_ERROR); + SET(bp->b_flags, B_BUSY | B_READ | B_RAW); + (*strat)(bp); + error = biowait(bp); + + if (error) { + DPRINTF("error reading from disk\n"); + /*wrong*/ if (partoffp) + /*wrong*/ *partoffp = -1; + return (error); + } + + bcopy(bp->b_data + offset, &gh, sizeof(gh)); + + if (letoh64(gh.gh_sig) != GPTSIGNATURE) + return (EINVAL); + + /* we only support version 1.0 */ + if (letoh32(gh.gh_rev) != GPTREVISION) + return (EINVAL); + + if (gpt_chk_hdr(&gh)) { + /* header broken, using alternate header */ + if (altheader) { + DPRINTF("alternate header also broken\n"); + return (EINVAL); + } + + if (gh.gh_lba_alt >= DL_GETDSIZE(lp)) { + DPRINTF("alternate header's position is " + "bogous\n"); + return (EINVAL); + } + + continue; + } + + /* + * Header size must be greater than or equal to 92 and less + * than or equal to the logical block size. + */ + if (letoh32(gh.gh_size) < GPTMINHDRSIZE + && letoh32(gh.gh_size) > DEV_BSIZE) + return (EINVAL); + + if (letoh64(gh.gh_lba_start) >= DL_GETDSIZE(lp) || + letoh64(gh.gh_lba_end) >= DL_GETDSIZE(lp) || + letoh64(gh.gh_part_lba) >= DL_GETDSIZE(lp)) + return (EINVAL); + + /* + * Size per partition entry shall be 128*(2**n) with n >= 0. + * We don't support partition entries larger than block size. + */ + if (letoh32(gh.gh_part_size) % GPTMINPARTSIZE + || letoh32(gh.gh_part_size) > DEV_BSIZE + || GPT_PARTSPERSEC(&gh) == 0) { + DPRINTF("invalid partition size\n"); + return (EINVAL); + } + + /* XXX: we don't support multiples of GPTMINPARTSIZE yet */ + if (letoh32(gh.gh_part_size) != GPTMINPARTSIZE) { + DPRINTF("partition sizes larger than %d bytes are not " + "supported", GPTMINPARTSIZE); + return (EINVAL); + } + + /* read GPT partition entry array */ + gpsz = letoh32(gh.gh_part_num) * sizeof(struct gpt_partition); + gp = malloc(gpsz, M_DEVBUF, M_NOWAIT|M_ZERO); + if (gp == NULL) + return (ENOMEM); + + /* + * XXX: Fails if # of partition entries is no multiple of + * GPT_PARTSPERSEC(&gh) + */ + for (i = 0; i < letoh32(gh.gh_part_num) / GPT_PARTSPERSEC(&gh); + i++) { + part_blkno = letoh64(gh.gh_part_lba) + i; + /* read partition record */ + bp->b_blkno = DL_BLKTOSEC(lp, part_blkno) * + DL_BLKSPERSEC(lp); + offset = DL_BLKOFFSET(lp, part_blkno); + bp->b_bcount = lp->d_secsize; + /* B_ERROR and b_error may have stale data. */ + bp->b_error = 0; + CLR(bp->b_flags, B_READ | B_WRITE | B_DONE | B_ERROR); + SET(bp->b_flags, B_BUSY | B_READ | B_RAW); + (*strat)(bp); + error = biowait(bp); + if (error) { + /*wrong*/ if (partoffp) + /*wrong*/ *partoffp = -1; + free(gp, M_DEVBUF, gpsz); + return (error); + } + + bcopy(bp->b_data + offset, gp + + i * GPT_PARTSPERSEC(&gh), GPT_PARTSPERSEC(&gh) * + sizeof(struct gpt_partition)); + } + + if (gpt_chk_parts(&gh, gp)) { + DPRINTF("partition entries broken, using alternate " + "header\n"); + free(gp, M_DEVBUF, gpsz); + + if (altheader) { + DPRINTF("alternate partition entries are also " + "broken\n"); + return (EINVAL); + } + + continue; + } + break; + } + + /* find OpenBSD partition */ + for (gp_tmp = gp, i = 0; i < letoh32(gh.gh_part_num) && ourpart == -1; + gp_tmp++, i++) { + if (letoh64(gp_tmp->gp_lba_start) > letoh64(gp_tmp->gp_lba_end) + || letoh64(gp_tmp->gp_lba_start) < letoh64(gh.gh_lba_start) + || letoh64(gp_tmp->gp_lba_end) > letoh64(gh.gh_lba_end)) + continue; /* entry invalid */ + + uuid_dec_le(&gp_tmp->gp_type, &uuid_part); + if (!memcmp(&uuid_part, &uuid_openbsd, sizeof(struct uuid))) { + ourpart = i; /* found it */ + } + + /* + * In case the disklabel read below fails, we want to + * provide a fake label in i-p. + */ + fstype = get_fstype(&uuid_part); + + /* + * Don't set fstype/offset/size when just looking for + * the offset of the OpenBSD partition. It would + * invalidate the disklabel checksum! + * + * Don't try to spoof more than 8 partitions, i.e. + * 'i' -'p'. + */ + if (partoffp || n >= 8) + continue; + + pp = &lp->d_partitions[8+n]; + n++; + pp->p_fstype = fstype; + DL_SETPOFFSET(pp, letoh64(gp_tmp->gp_lba_start)); + DL_SETPSIZE(pp, letoh64(gp_tmp->gp_lba_end) + - letoh64(gp_tmp->gp_lba_start) + 1); + } + + if (ourpart != -1) { + /* found our OpenBSD partition, so use it */ + gp_tmp = &gp[ourpart]; + gptpartoff = letoh64(gp_tmp->gp_lba_start); + gptpartend = letoh64(gp_tmp->gp_lba_end) + 1; + } else + spoofonly = 1; /* No disklabel to read from disk. */ + + if (!partoffp) + /* Must not modify *lp when partoffp is set. */ + lp->d_npartitions = MAXPARTITIONS; + + free(gp, M_DEVBUF, gpsz); + + /* record the OpenBSD partition's placement for the caller */ + if (partoffp) + *partoffp = gptpartoff; + else { + DL_SETBSTART(lp, gptpartoff); + DL_SETBEND(lp, (gptpartend < DL_GETDSIZE(lp)) ? gptpartend : + DL_GETDSIZE(lp)); + } + + /* don't read the on-disk label if we are in spoofed-only mode */ + if (spoofonly) + return (0); + + bp->b_blkno = DL_BLKTOSEC(lp, gptpartoff + DOS_LABELSECTOR) * + DL_BLKSPERSEC(lp); + offset = DL_BLKOFFSET(lp, gptpartoff + DOS_LABELSECTOR); + bp->b_bcount = lp->d_secsize; + CLR(bp->b_flags, B_READ | B_WRITE | B_DONE); + SET(bp->b_flags, B_BUSY | B_READ | B_RAW); + (*strat)(bp); + if (biowait(bp)) + return (bp->b_error); + + /* sub-GPT disklabels are always at a LABELOFFSET of 0 */ + return checkdisklabel(bp->b_data + offset, lp, gptpartoff, gptpartend); +} + +#endif + /* * Check new disk label for sensibility before setting it. */ diff --git a/sys/sys/disklabel.h b/sys/sys/disklabel.h index 98cc01ebad8..00c5c90e040 100644 --- a/sys/sys/disklabel.h +++ b/sys/sys/disklabel.h @@ -1,4 +1,4 @@ -/* $OpenBSD: disklabel.h,v 1.61 2014/07/01 05:22:09 dlg Exp $ */ +/* $OpenBSD: disklabel.h,v 1.62 2014/07/13 15:32:28 miod Exp $ */ /* $NetBSD: disklabel.h,v 1.41 1996/05/10 23:07:37 mark Exp $ */ /* @@ -47,6 +47,8 @@ */ #include +#include + /* * The absolute maximum number of disk partitions allowed. * This is the maximum value of MAXPARTITIONS for which 'struct disklabel' @@ -380,6 +382,96 @@ struct partinfo { struct partition *part; }; +/* GUID partition table -- located at sector 1 of some disks. */ +#define GPTSECTOR 1 /* DOS boot block relative sector # */ +#define GPTSIGNATURE 0x5452415020494645 + /* ASCII string "EFI PART" encoded as 64-bit */ +#define GPTREVISION 0x10000 /* GPT header version 1.0 */ +#define NGPTPARTITIONS 128 +#define GPTDOSACTIVE 0x2 +#define GPTMINHDRSIZE 92 +#define GPTMINPARTSIZE 128 + +/* all values in the GPT need to be little endian as per UEFI specification */ +struct gpt_header { + u_int64_t gh_sig; /* "EFI PART" */ + u_int32_t gh_rev; /* GPT Version 1.0: 0x00000100 */ + u_int32_t gh_size; /* Little-Endian */ + u_int32_t gh_csum; /* CRC32: with this field as 0 */ + u_int32_t gh_rsvd; /* always zero */ + u_int64_t gh_lba_self; /* LBA of this header */ + u_int64_t gh_lba_alt; /* LBA of alternate header */ + u_int64_t gh_lba_start; /* first usable LBA */ + u_int64_t gh_lba_end; /* last usable LBA */ + struct uuid gh_guid; /* disk GUID used to identify the disk */ + u_int64_t gh_part_lba; /* starting LBA of GPT partition entries */ + u_int32_t gh_part_num; /* # of partition entries */ + u_int32_t gh_part_size; /* size per entry, shall be 128*(2**n) + with n >= 0 */ + u_int32_t gh_part_csum; /* CRC32 checksum of all partition entries: + * starts at gh_part_lba and is computed over + * a byte length of gh_part_num*gh_part_size */ + /* the rest of the block is reserved by UEFI and must be zero */ +}; + +struct gpt_partition { + struct uuid gp_type; /* partition type GUID */ + struct uuid gp_guid; /* unique partition GUID */ + u_int64_t gp_lba_start; /* starting LBA of this partition */ + u_int64_t gp_lba_end; /* ending LBA of this partition, inclusive, + usually odd */ + u_int64_t gp_attrs; /* attribute flags */ + u_int16_t gp_name[36]; /* partition name, utf-16le */ + /* the rest of the GPT partition entry, if any, is reserved by UEFI + and must be zero */ +}; + +#define GPT_PARTSPERSEC(gh) (DEV_BSIZE / letoh32((gh)->gh_part_size)) +#define GPT_SECOFFSET(gh, n) ((gh)->gh_part_size * n) + +#define GPT_UUID_UNUSED \ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define GPT_UUID_MSDOS \ + { 0xeb, 0xd0, 0xa0, 0xa2, 0xb9, 0xe5, 0x44, 0x33, \ + 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 } +#define GPT_UUID_EFI_SYSTEM \ + { 0xc1, 0x2a, 0x73, 0x28, 0xf8, 0x1f, 0x11, 0xd2, \ + 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } +#define GPT_UUID_LEGACY_MBR \ + { 0x02, 0x4d, 0xee, 0x41, 0x33, 0x37, 0x11, 0xd3, \ + 0x9d, 0x69, 0x00, 0x08, 0xc7, 0x81, 0xf3, 0x9f } +#define GPT_UUID_OPENBSD \ + { 0x82, 0x4c, 0xc7, 0xa0, 0x36, 0xa8, 0x11, 0xe3, \ + 0x89, 0x0a, 0x95, 0x25, 0x19, 0xad, 0x3f, 0x61 } +#define GPT_UUID_CHROMEROOTFS \ + { 0x3c, 0xb8, 0xe2, 0x02, 0x3b, 0x7e, 0x47, 0xdd, \ + 0x8a, 0x3c, 0x7f, 0xf2, 0xa1, 0x3c, 0xfc, 0xec } +#define GPT_UUID_LINUX \ + { 0x0f, 0xc6, 0x3d, 0xaf, 0x84, 0x83, 0x47, 0x72, \ + 0x8e, 0x79, 0x3d, 0x69, 0xd8, 0x47, 0x7d, 0xe4 } +#define GPT_UUID_LINUX_HOME \ + { 0x93, 0x3a, 0xc7, 0xe1, 0x2e, 0xb4, 0x4f, 0x13, \ + 0xb8, 0x44, 0x0e, 0x14, 0xe2, 0xae, 0xf9, 0x15 } +#define GPT_UUID_LINUX_SRV \ + { 0x3b, 0x8f, 0x84, 0x25, 0x20, 0xe0, 0x4f, 0x3b, \ + 0x90, 0x7f, 0x1a, 0x25, 0xa7, 0x6f, 0x98, 0xe8 } +#define GPT_UUID_FBSD_DATA \ + { 0x51, 0x6e, 0x7c, 0xb4, 0x6e, 0xcf, 0x11, 0xd6, \ + 0x8f, 0xf8, 0x00, 0x02, 0x2d, 0x09, 0x71, 0x2b } +#define GPT_UUID_FBSD_UFS \ + { 0x51, 0x6e, 0x7c, 0xb6, 0x6e, 0xcf, 0x11, 0xd6, \ + 0x8f, 0xf8, 0x00, 0x02, 0x2d, 0x09, 0x71, 0x2b } +#define GPT_UUID_NBSD_UFS \ + { 0x49, 0xf4, 0x8d, 0x5a, 0xb1, 0x0e, 0x11, 0xdc, \ + 0xb9, 0x9b, 0x00, 0x19, 0xd1, 0x87, 0x96, 0x48 } +#define GPT_UUID_APPLE_HFS \ + { 0x48, 0x46, 0x53, 0x00, 0x00, 0x00, 0x11, 0xaa, \ + 0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac } +#define GPT_UUID_APPLE_UFS \ + { 0x55, 0x46, 0x53, 0x00, 0x00, 0x00, 0x11, 0xaa, \ + 0xaa, 0x11, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac } + /* DOS partition table -- located at start of some disks. */ #define DOS_LABELSECTOR 1 #define DOSBBSECTOR 0 /* DOS boot block relative sector # */ @@ -445,6 +537,10 @@ int writedisklabel(dev_t, void (*)(struct buf *), struct disklabel *); int bounds_check_with_label(struct buf *, struct disklabel *); int readdoslabel(struct buf *, void (*)(struct buf *), struct disklabel *, daddr_t *, int); +#ifdef GPT +int readgptlabel(struct buf *, void (*)(struct buf *), + struct disklabel *, daddr_t *, int); +#endif #ifdef CD9660 int iso_disklabelspoof(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp); diff --git a/sys/sys/uuid.h b/sys/sys/uuid.h new file mode 100644 index 00000000000..4e4b3da077a --- /dev/null +++ b/sys/sys/uuid.h @@ -0,0 +1,75 @@ +/* $OpenBSD: uuid.h,v 1.1 2014/07/13 15:32:28 miod Exp $ */ +/* $NetBSD: uuid.h,v 1.5 2008/11/18 14:01:03 joerg Exp $ */ + +/* + * Copyright (c) 2002 Marcel Moolenaar + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: /repoman/r/ncvs/src/sys/sys/uuid.h,v 1.3 2003/05/31 16:47:07 phk Exp $ + */ + +#ifndef _SYS_UUID_H_ +#define _SYS_UUID_H_ + +/* Length of a node address (an IEEE 802 address). */ +#define _UUID_NODE_LEN 6 + +/* Length of a printed UUID. */ +#define _UUID_BUF_LEN 38 + +/* + * See also: + * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt + * http://www.opengroup.org/onlinepubs/009629399/apdxa.htm + * + * A DCE 1.1 compatible source representation of UUIDs. + */ +struct uuid { + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint8_t clock_seq_hi_and_reserved; + uint8_t clock_seq_low; + uint8_t node[_UUID_NODE_LEN]; +}; + +#ifdef _KERNEL + +#define UUID_NODE_LEN _UUID_NODE_LEN +#define UUID_BUF_LEN _UUID_BUF_LEN + +int uuid_snprintf(char *, size_t, const struct uuid *); +int uuid_printf(const struct uuid *); +void uuid_dec_be(const void *, struct uuid *); +void uuid_dec_le(const void *, struct uuid *); +void uuid_enc_be(void *, const struct uuid *); +void uuid_enc_le(void *, const struct uuid *); + +#else /* _KERNEL */ + +typedef struct uuid uuid_t; + +#endif /* _KERNEL */ + +#endif /* _SYS_UUID_H_ */ -- 2.20.1