Coverage Report

Created: 2026-05-30 06:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
};