bigbiff bigbiff | e60683a | 2013-02-22 20:55:50 -0500 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 1999 by Andries Brouwer |
| 3 | * Copyright (C) 1999, 2000, 2003 by Theodore Ts'o |
| 4 | * Copyright (C) 2001 by Andreas Dilger |
| 5 | * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org> |
| 6 | * Copyright (C) 2008 Karel Zak <kzak@redhat.com> |
| 7 | * Copyright (C) 2012 Milan Broz <mbroz@redhat.com> |
| 8 | * |
| 9 | * This file may be redistributed under the terms of the |
| 10 | * GNU Lesser General Public License. |
| 11 | */ |
| 12 | #include <stdio.h> |
| 13 | #include <stdlib.h> |
| 14 | #include <unistd.h> |
| 15 | #include <string.h> |
| 16 | #include <stdint.h> |
| 17 | |
| 18 | #include "superblocks.h" |
| 19 | |
| 20 | #define LVM1_ID_LEN 128 |
| 21 | #define LVM2_ID_LEN 32 |
| 22 | |
| 23 | struct lvm2_pv_label_header { |
| 24 | /* label_header */ |
| 25 | uint8_t id[8]; /* LABELONE */ |
| 26 | uint64_t sector_xl; /* Sector number of this label */ |
| 27 | uint32_t crc_xl; /* From next field to end of sector */ |
| 28 | uint32_t offset_xl; /* Offset from start of struct to contents */ |
| 29 | uint8_t type[8]; /* LVM2 001 */ |
| 30 | /* pv_header */ |
| 31 | uint8_t pv_uuid[LVM2_ID_LEN]; |
| 32 | } __attribute__ ((packed)); |
| 33 | |
| 34 | struct lvm1_pv_label_header { |
| 35 | uint8_t id[2]; /* HM */ |
| 36 | uint16_t version; /* version 1 or 2 */ |
| 37 | uint32_t _notused[10]; /* lvm1 internals */ |
| 38 | uint8_t pv_uuid[LVM1_ID_LEN]; |
| 39 | } __attribute__ ((packed)); |
| 40 | |
| 41 | #define LVM2_LABEL_SIZE 512 |
| 42 | static unsigned int lvm2_calc_crc(const void *buf, unsigned int size) |
| 43 | { |
| 44 | static const unsigned int crctab[] = { |
| 45 | 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, |
| 46 | 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, |
| 47 | 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, |
| 48 | 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c |
| 49 | }; |
| 50 | unsigned int i, crc = 0xf597a6cf; |
| 51 | const uint8_t *data = (const uint8_t *) buf; |
| 52 | |
| 53 | for (i = 0; i < size; i++) { |
| 54 | crc ^= *data++; |
| 55 | crc = (crc >> 4) ^ crctab[crc & 0xf]; |
| 56 | crc = (crc >> 4) ^ crctab[crc & 0xf]; |
| 57 | } |
| 58 | return crc; |
| 59 | } |
| 60 | |
| 61 | /* Length of real UUID is always LVM2_ID_LEN */ |
| 62 | static void format_lvm_uuid(char *dst_uuid, char *src_uuid) |
| 63 | { |
| 64 | unsigned int i, b; |
| 65 | |
| 66 | for (i = 0, b = 1; i < LVM2_ID_LEN; i++, b <<= 1) { |
| 67 | if (b & 0x4444440) |
| 68 | *dst_uuid++ = '-'; |
| 69 | *dst_uuid++ = *src_uuid++; |
| 70 | } |
| 71 | *dst_uuid = '\0'; |
| 72 | } |
| 73 | |
| 74 | static int probe_lvm2(blkid_probe pr, const struct blkid_idmag *mag) |
| 75 | { |
| 76 | int sector = mag->kboff << 1; |
| 77 | struct lvm2_pv_label_header *label; |
| 78 | char uuid[LVM2_ID_LEN + 7]; |
| 79 | unsigned char *buf; |
| 80 | |
| 81 | buf = blkid_probe_get_buffer(pr, |
| 82 | mag->kboff << 10, |
| 83 | 512 + sizeof(struct lvm2_pv_label_header)); |
| 84 | if (!buf) |
| 85 | return -1; |
| 86 | |
| 87 | /* buf is at 0k or 1k offset; find label inside */ |
| 88 | if (memcmp(buf, "LABELONE", 8) == 0) { |
| 89 | label = (struct lvm2_pv_label_header *) buf; |
| 90 | } else if (memcmp(buf + 512, "LABELONE", 8) == 0) { |
| 91 | label = (struct lvm2_pv_label_header *)(buf + 512); |
| 92 | sector++; |
| 93 | } else { |
| 94 | return 1; |
| 95 | } |
| 96 | |
| 97 | if (le64_to_cpu(label->sector_xl) != (unsigned) sector) |
| 98 | return 1; |
| 99 | |
| 100 | if (lvm2_calc_crc(&label->offset_xl, LVM2_LABEL_SIZE - |
| 101 | ((char *) &label->offset_xl - (char *) label)) != |
| 102 | le32_to_cpu(label->crc_xl)) { |
| 103 | DBG(DEBUG_PROBE, |
| 104 | printf("LVM2: label checksum incorrect at sector %d\n", |
| 105 | sector)); |
| 106 | return 1; |
| 107 | } |
| 108 | |
| 109 | format_lvm_uuid(uuid, (char *) label->pv_uuid); |
| 110 | blkid_probe_sprintf_uuid(pr, label->pv_uuid, sizeof(label->pv_uuid), |
| 111 | "%s", uuid); |
| 112 | |
| 113 | /* the mag->magic is the same string as label->type, |
| 114 | * but zero terminated */ |
| 115 | blkid_probe_set_version(pr, mag->magic); |
| 116 | |
| 117 | /* LVM (pvcreate) wipes begin of the device -- let's remember this |
| 118 | * to resolve conflicts bettween LVM and partition tables, ... |
| 119 | */ |
| 120 | blkid_probe_set_wiper(pr, 0, 8 * 1024); |
| 121 | |
| 122 | return 0; |
| 123 | } |
| 124 | |
| 125 | static int probe_lvm1(blkid_probe pr, const struct blkid_idmag *mag) |
| 126 | { |
| 127 | struct lvm1_pv_label_header *label; |
| 128 | char uuid[LVM2_ID_LEN + 7]; |
| 129 | unsigned int version; |
| 130 | |
| 131 | label = blkid_probe_get_sb(pr, mag, struct lvm1_pv_label_header); |
| 132 | if (!label) |
| 133 | return -1; |
| 134 | |
| 135 | version = le16_to_cpu(label->version); |
| 136 | if (version != 1 && version != 2) |
| 137 | return 1; |
| 138 | |
| 139 | format_lvm_uuid(uuid, (char *) label->pv_uuid); |
| 140 | blkid_probe_sprintf_uuid(pr, label->pv_uuid, sizeof(label->pv_uuid), |
| 141 | "%s", uuid); |
| 142 | |
| 143 | return 0; |
| 144 | } |
| 145 | |
| 146 | struct verity_sb { |
| 147 | uint8_t signature[8]; /* "verity\0\0" */ |
| 148 | uint32_t version; /* superblock version */ |
| 149 | uint32_t hash_type; /* 0 - Chrome OS, 1 - normal */ |
| 150 | uint8_t uuid[16]; /* UUID of hash device */ |
| 151 | uint8_t algorithm[32];/* hash algorithm name */ |
| 152 | uint32_t data_block_size; /* data block in bytes */ |
| 153 | uint32_t hash_block_size; /* hash block in bytes */ |
| 154 | uint64_t data_blocks; /* number of data blocks */ |
| 155 | uint16_t salt_size; /* salt size */ |
| 156 | uint8_t _pad1[6]; |
| 157 | uint8_t salt[256]; /* salt */ |
| 158 | uint8_t _pad2[168]; |
| 159 | } __attribute__((packed)); |
| 160 | |
| 161 | static int probe_verity(blkid_probe pr, const struct blkid_idmag *mag) |
| 162 | { |
| 163 | struct verity_sb *sb; |
| 164 | unsigned int version; |
| 165 | |
| 166 | sb = blkid_probe_get_sb(pr, mag, struct verity_sb); |
| 167 | if (sb == NULL) |
| 168 | return -1; |
| 169 | |
| 170 | version = le32_to_cpu(sb->version); |
| 171 | if (version != 1) |
| 172 | return 1; |
| 173 | |
| 174 | blkid_probe_set_uuid(pr, sb->uuid); |
| 175 | blkid_probe_sprintf_version(pr, "%u", version); |
| 176 | return 0; |
| 177 | } |
| 178 | |
| 179 | /* NOTE: the original libblkid uses "lvm2pv" as a name */ |
| 180 | const struct blkid_idinfo lvm2_idinfo = |
| 181 | { |
| 182 | .name = "LVM2_member", |
| 183 | .usage = BLKID_USAGE_RAID, |
| 184 | .probefunc = probe_lvm2, |
| 185 | .magics = |
| 186 | { |
| 187 | { .magic = "LVM2 001", .len = 8, .sboff = 0x218 }, |
| 188 | { .magic = "LVM2 001", .len = 8, .sboff = 0x018 }, |
| 189 | { .magic = "LVM2 001", .len = 8, .kboff = 1, .sboff = 0x018 }, |
| 190 | { .magic = "LVM2 001", .len = 8, .kboff = 1, .sboff = 0x218 }, |
| 191 | { NULL } |
| 192 | } |
| 193 | }; |
| 194 | |
| 195 | const struct blkid_idinfo lvm1_idinfo = |
| 196 | { |
| 197 | .name = "LVM1_member", |
| 198 | .usage = BLKID_USAGE_RAID, |
| 199 | .probefunc = probe_lvm1, |
| 200 | .magics = |
| 201 | { |
| 202 | { .magic = "HM", .len = 2 }, |
| 203 | { NULL } |
| 204 | } |
| 205 | }; |
| 206 | |
| 207 | const struct blkid_idinfo snapcow_idinfo = |
| 208 | { |
| 209 | .name = "DM_snapshot_cow", |
| 210 | .usage = BLKID_USAGE_OTHER, |
| 211 | .magics = |
| 212 | { |
| 213 | { .magic = "SnAp", .len = 4 }, |
| 214 | { NULL } |
| 215 | } |
| 216 | }; |
| 217 | |
| 218 | const struct blkid_idinfo verity_hash_idinfo = |
| 219 | { |
| 220 | .name = "DM_verity_hash", |
| 221 | .usage = BLKID_USAGE_CRYPTO, |
| 222 | .probefunc = probe_verity, |
| 223 | .magics = |
| 224 | { |
| 225 | { .magic = "verity\0\0", .len = 8 }, |
| 226 | { NULL } |
| 227 | } |
| 228 | }; |