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 <gmazyland@gmail.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 errno ? -errno : 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 (!blkid_probe_verify_csum(
101 pr, lvm2_calc_crc(
102 &label->offset_xl, LVM2_LABEL_SIZE -
103 ((char *) &label->offset_xl - (char *) label)),
104 le32_to_cpu(label->crc_xl)))
105 return 1;
106
107 format_lvm_uuid(uuid, (char *) label->pv_uuid);
108 blkid_probe_sprintf_uuid(pr, label->pv_uuid, sizeof(label->pv_uuid),
109 "%s", uuid);
110
111 /* the mag->magic is the same string as label->type,
112 * but zero terminated */
113 blkid_probe_set_version(pr, mag->magic);
114
115 /* LVM (pvcreate) wipes begin of the device -- let's remember this
116 * to resolve conflicts between LVM and partition tables, ...
117 */
118 blkid_probe_set_wiper(pr, 0, 8 * 1024);
119
120 return 0;
121 }
122
123 static int probe_lvm1(blkid_probe pr, const struct blkid_idmag *mag)
124 {
125 struct lvm1_pv_label_header *label;
126 char uuid[LVM2_ID_LEN + 7];
127 unsigned int version;
128
129 label = blkid_probe_get_sb(pr, mag, struct lvm1_pv_label_header);
130 if (!label)
131 return errno ? -errno : 1;
132
133 version = le16_to_cpu(label->version);
134 if (version != 1 && version != 2)
135 return 1;
136
137 format_lvm_uuid(uuid, (char *) label->pv_uuid);
138 blkid_probe_sprintf_uuid(pr, label->pv_uuid, sizeof(label->pv_uuid),
139 "%s", uuid);
140
141 return 0;
142 }
143
144 struct verity_sb {
145 uint8_t signature[8]; /* "verity\0\0" */
146 uint32_t version; /* superblock version */
147 uint32_t hash_type; /* 0 - Chrome OS, 1 - normal */
148 uint8_t uuid[16]; /* UUID of hash device */
149 uint8_t algorithm[32];/* hash algorithm name */
150 uint32_t data_block_size; /* data block in bytes */
151 uint32_t hash_block_size; /* hash block in bytes */
152 uint64_t data_blocks; /* number of data blocks */
153 uint16_t salt_size; /* salt size */
154 uint8_t _pad1[6];
155 uint8_t salt[256]; /* salt */
156 uint8_t _pad2[168];
157 } __attribute__((packed));
158
159 static int probe_verity(blkid_probe pr, const struct blkid_idmag *mag)
160 {
161 struct verity_sb *sb;
162 unsigned int version;
163
164 sb = blkid_probe_get_sb(pr, mag, struct verity_sb);
165 if (sb == NULL)
166 return errno ? -errno : 1;
167
168 version = le32_to_cpu(sb->version);
169 if (version != 1)
170 return 1;
171
172 blkid_probe_set_uuid(pr, sb->uuid);
173 blkid_probe_sprintf_version(pr, "%u", version);
174 return 0;
175 }
176
177 struct integrity_sb {
178 uint8_t magic[8];
179 uint8_t version;
180 int8_t log2_interleave_sectors;
181 uint16_t integrity_tag_size;
182 uint32_t journal_sections;
183 uint64_t provided_data_sectors;
184 uint32_t flags;
185 uint8_t log2_sectors_per_block;
186 } __attribute__ ((packed));
187
188 static int probe_integrity(blkid_probe pr, const struct blkid_idmag *mag)
189 {
190 struct integrity_sb *sb;
191
192 sb = blkid_probe_get_sb(pr, mag, struct integrity_sb);
193 if (sb == NULL)
194 return errno ? -errno : 1;
195
196 if (!sb->version)
197 return 1;
198
199 blkid_probe_sprintf_version(pr, "%u", sb->version);
200 return 0;
201 }
202
203 /* NOTE: the original libblkid uses "lvm2pv" as a name */
204 const struct blkid_idinfo lvm2_idinfo =
205 {
206 .name = "LVM2_member",
207 .usage = BLKID_USAGE_RAID,
208 .probefunc = probe_lvm2,
209 .magics =
210 {
211 { .magic = "LVM2 001", .len = 8, .sboff = 0x218 },
212 { .magic = "LVM2 001", .len = 8, .sboff = 0x018 },
213 { .magic = "LVM2 001", .len = 8, .kboff = 1, .sboff = 0x018 },
214 { .magic = "LVM2 001", .len = 8, .kboff = 1, .sboff = 0x218 },
215 { NULL }
216 }
217 };
218
219 const struct blkid_idinfo lvm1_idinfo =
220 {
221 .name = "LVM1_member",
222 .usage = BLKID_USAGE_RAID,
223 .probefunc = probe_lvm1,
224 .magics =
225 {
226 { .magic = "HM", .len = 2 },
227 { NULL }
228 }
229 };
230
231 const struct blkid_idinfo snapcow_idinfo =
232 {
233 .name = "DM_snapshot_cow",
234 .usage = BLKID_USAGE_OTHER,
235 .magics =
236 {
237 { .magic = "SnAp", .len = 4 },
238 { NULL }
239 }
240 };
241
242 const struct blkid_idinfo verity_hash_idinfo =
243 {
244 .name = "DM_verity_hash",
245 .usage = BLKID_USAGE_CRYPTO,
246 .probefunc = probe_verity,
247 .magics =
248 {
249 { .magic = "verity\0\0", .len = 8 },
250 { NULL }
251 }
252 };
253
254 const struct blkid_idinfo integrity_idinfo =
255 {
256 .name = "DM_integrity",
257 .usage = BLKID_USAGE_CRYPTO,
258 .probefunc = probe_integrity,
259 .magics =
260 {
261 { .magic = "integrt\0", .len = 8 },
262 { NULL }
263 }
264 };