/src/util-linux/libblkid/src/superblocks/lvm.c
Line | Count | Source |
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 | 132 | #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 | 620 | #define LVM2_LABEL_SIZE 512 |
42 | | static unsigned int lvm2_calc_crc(const void *buf, unsigned int size) |
43 | 4 | { |
44 | 4 | static const unsigned int crctab[] = { |
45 | 4 | 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, |
46 | 4 | 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, |
47 | 4 | 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, |
48 | 4 | 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c |
49 | 4 | }; |
50 | 4 | unsigned int i, crc = 0xf597a6cf; |
51 | 4 | const uint8_t *data = (const uint8_t *) buf; |
52 | | |
53 | 1.97k | for (i = 0; i < size; i++) { |
54 | 1.96k | crc ^= *data++; |
55 | 1.96k | crc = (crc >> 4) ^ crctab[crc & 0xf]; |
56 | 1.96k | crc = (crc >> 4) ^ crctab[crc & 0xf]; |
57 | 1.96k | } |
58 | 4 | return crc; |
59 | 4 | } |
60 | | |
61 | | /* Length of real UUID is always LVM2_ID_LEN */ |
62 | | static void format_lvm_uuid(char *dst_uuid, char *src_uuid) |
63 | 4 | { |
64 | 4 | unsigned int i, b; |
65 | | |
66 | 132 | for (i = 0, b = 1; i < LVM2_ID_LEN; i++, b <<= 1) { |
67 | 128 | if (b & 0x4444440) |
68 | 24 | *dst_uuid++ = '-'; |
69 | 128 | *dst_uuid++ = *src_uuid++; |
70 | 128 | } |
71 | 4 | *dst_uuid = '\0'; |
72 | 4 | } |
73 | | |
74 | | static int probe_lvm2(blkid_probe pr, const struct blkid_idmag *mag) |
75 | 616 | { |
76 | 616 | int sector = mag->kboff << 1; |
77 | 616 | struct lvm2_pv_label_header *label; |
78 | 616 | char uuid[LVM2_ID_LEN + 7]; |
79 | 616 | const unsigned char *buf; |
80 | | |
81 | 616 | buf = blkid_probe_get_buffer(pr, |
82 | 616 | mag->kboff << 10, |
83 | 616 | 512 + LVM2_LABEL_SIZE); |
84 | 616 | if (!buf) |
85 | 0 | return errno ? -errno : 1; |
86 | | |
87 | | /* buf is at 0k or 1k offset; find label inside */ |
88 | 616 | if (memcmp(buf, "LABELONE", 8) == 0) { |
89 | 57 | label = (struct lvm2_pv_label_header *) buf; |
90 | 559 | } else if (memcmp(buf + 512, "LABELONE", 8) == 0) { |
91 | 81 | label = (struct lvm2_pv_label_header *)(buf + 512); |
92 | 81 | sector++; |
93 | 478 | } else { |
94 | 478 | return 1; |
95 | 478 | } |
96 | | |
97 | 138 | if (le64_to_cpu(label->sector_xl) != (unsigned) sector) |
98 | 134 | return 1; |
99 | | |
100 | 4 | if (!blkid_probe_verify_csum( |
101 | 4 | pr, lvm2_calc_crc( |
102 | 4 | &label->offset_xl, LVM2_LABEL_SIZE - |
103 | 4 | ((char *) &label->offset_xl - (char *) label)), |
104 | 4 | le32_to_cpu(label->crc_xl))) |
105 | 3 | return 1; |
106 | | |
107 | 1 | format_lvm_uuid(uuid, (char *) label->pv_uuid); |
108 | 1 | blkid_probe_sprintf_uuid(pr, label->pv_uuid, sizeof(label->pv_uuid), |
109 | 1 | "%s", uuid); |
110 | | |
111 | | /* the mag->magic is the same string as label->type, |
112 | | * but zero terminated */ |
113 | 1 | 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 | 1 | blkid_probe_set_wiper(pr, 0, 8 * 1024); |
119 | | |
120 | 1 | return 0; |
121 | 4 | } |
122 | | |
123 | | static int probe_lvm1(blkid_probe pr, const struct blkid_idmag *mag) |
124 | 106 | { |
125 | 106 | const struct lvm1_pv_label_header *label; |
126 | 106 | char uuid[LVM2_ID_LEN + 7]; |
127 | 106 | unsigned int version; |
128 | | |
129 | 106 | label = blkid_probe_get_sb(pr, mag, struct lvm1_pv_label_header); |
130 | 106 | if (!label) |
131 | 0 | return errno ? -errno : 1; |
132 | | |
133 | 106 | version = le16_to_cpu(label->version); |
134 | 106 | if (version != 1 && version != 2) |
135 | 103 | return 1; |
136 | | |
137 | 3 | format_lvm_uuid(uuid, (char *) label->pv_uuid); |
138 | 3 | blkid_probe_sprintf_uuid(pr, label->pv_uuid, sizeof(label->pv_uuid), |
139 | 3 | "%s", uuid); |
140 | | |
141 | 3 | return 0; |
142 | 106 | } |
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 | 38 | { |
161 | 38 | const struct verity_sb *sb; |
162 | 38 | unsigned int version; |
163 | | |
164 | 38 | sb = blkid_probe_get_sb(pr, mag, struct verity_sb); |
165 | 38 | if (sb == NULL) |
166 | 0 | return errno ? -errno : 1; |
167 | | |
168 | 38 | version = le32_to_cpu(sb->version); |
169 | 38 | if (version != 1) |
170 | 37 | return 1; |
171 | | |
172 | 1 | blkid_probe_set_uuid(pr, sb->uuid); |
173 | 1 | blkid_probe_sprintf_version(pr, "%u", version); |
174 | 1 | return 0; |
175 | 38 | } |
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 | 10 | { |
190 | 10 | const struct integrity_sb *sb; |
191 | | |
192 | 10 | sb = blkid_probe_get_sb(pr, mag, struct integrity_sb); |
193 | 10 | if (sb == NULL) |
194 | 0 | return errno ? -errno : 1; |
195 | | |
196 | 10 | if (!sb->version) |
197 | 7 | return 1; |
198 | | |
199 | 3 | blkid_probe_sprintf_version(pr, "%u", sb->version); |
200 | 3 | return 0; |
201 | 10 | } |
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 | | }; |