Coverage Report

Created: 2025-06-13 06:36

/src/util-linux/libblkid/src/superblocks/luks.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2008 Karel Zak <kzak@redhat.com>
3
 * Copyright (C) 2018-2024 Milan Broz <gmazyland@gmail.com>
4
 *
5
 * Inspired by libvolume_id by
6
 *     Kay Sievers <kay.sievers@vrfy.org>
7
 *
8
 * This file may be redistributed under the terms of the
9
 * GNU Lesser General Public License.
10
 */
11
#include <stdio.h>
12
#include <stdlib.h>
13
#include <unistd.h>
14
#include <string.h>
15
#include <errno.h>
16
#include <ctype.h>
17
#include <stdint.h>
18
#include <stdbool.h>
19
20
#include "superblocks.h"
21
22
#define LUKS_CIPHERNAME_L   32
23
#define LUKS_CIPHERMODE_L   32
24
#define LUKS_HASHSPEC_L     32
25
#define LUKS_DIGESTSIZE     20
26
#define LUKS_SALTSIZE     32
27
0
#define LUKS_MAGIC_L      6
28
0
#define UUID_STRING_L     40
29
0
#define LUKS2_LABEL_L     48
30
#define LUKS2_SALT_L      64
31
#define LUKS2_CHECKSUM_ALG_L    32
32
#define LUKS2_CHECKSUM_L    64
33
34
0
#define LUKS_MAGIC  "LUKS\xba\xbe"
35
0
#define LUKS_MAGIC_2  "SKUL\xba\xbe"
36
37
0
#define LUKS2_HW_OPAL_SUBSYSTEM "HW-OPAL"
38
39
/* Offsets for secondary header (for scan if primary header is corrupted). */
40
#define LUKS2_HDR2_OFFSETS { 0x04000, 0x008000, 0x010000, 0x020000, \
41
                             0x40000, 0x080000, 0x100000, 0x200000, 0x400000 }
42
43
static const uint64_t secondary_offsets[] = LUKS2_HDR2_OFFSETS;
44
45
struct luks_phdr {
46
  uint8_t   magic[LUKS_MAGIC_L];
47
  uint16_t  version;
48
  uint8_t   cipherName[LUKS_CIPHERNAME_L];
49
  uint8_t   cipherMode[LUKS_CIPHERMODE_L];
50
  uint8_t   hashSpec[LUKS_HASHSPEC_L];
51
  uint32_t  payloadOffset;
52
  uint32_t  keyBytes;
53
  uint8_t   mkDigest[LUKS_DIGESTSIZE];
54
  uint8_t   mkDigestSalt[LUKS_SALTSIZE];
55
  uint32_t  mkDigestIterations;
56
  uint8_t   uuid[UUID_STRING_L];
57
} __attribute__((packed));
58
59
struct luks2_phdr {
60
  char    magic[LUKS_MAGIC_L];
61
  uint16_t  version;
62
  uint64_t  hdr_size; /* in bytes, including JSON area */
63
  uint64_t  seqid;    /* increased on every update */
64
  char    label[LUKS2_LABEL_L];
65
  char    checksum_alg[LUKS2_CHECKSUM_ALG_L];
66
  uint8_t   salt[LUKS2_SALT_L]; /* unique for every header/offset */
67
  char    uuid[UUID_STRING_L];
68
  char    subsystem[LUKS2_LABEL_L]; /* owner subsystem label */
69
  uint64_t  hdr_offset; /* offset from device start in bytes */
70
  char    _padding[184];
71
  uint8_t   csum[LUKS2_CHECKSUM_L];
72
  /* Padding to 4k, then JSON area */
73
} __attribute__ ((packed));
74
75
static int luks_attributes(blkid_probe pr, struct luks2_phdr *header, uint64_t offset)
76
0
{
77
0
  int version;
78
0
  struct luks_phdr *header_v1;
79
80
0
  if (blkid_probe_set_magic(pr, offset, LUKS_MAGIC_L, (unsigned char *) &header->magic))
81
0
    return BLKID_PROBE_NONE;
82
83
0
  version = be16_to_cpu(header->version);
84
0
  blkid_probe_sprintf_version(pr, "%u", version);
85
86
0
  if (version == 1) {
87
0
    header_v1 = (struct luks_phdr *)header;
88
0
    blkid_probe_strncpy_uuid(pr,
89
0
      (unsigned char *) header_v1->uuid, UUID_STRING_L);
90
0
  } else if (version == 2) {
91
0
    blkid_probe_strncpy_uuid(pr,
92
0
      (unsigned char *) header->uuid, UUID_STRING_L);
93
0
    blkid_probe_set_label(pr,
94
0
      (unsigned char *) header->label, LUKS2_LABEL_L);
95
0
    blkid_probe_set_id_label(pr, "SUBSYSTEM",
96
0
      (unsigned char *) header->subsystem, LUKS2_LABEL_L);
97
0
  }
98
99
0
  return BLKID_PROBE_OK;
100
0
}
101
102
static bool luks_valid(struct luks2_phdr *header, const char *magic, uint64_t offset)
103
0
{
104
0
  if (memcmp(header->magic, magic, LUKS_MAGIC_L))
105
0
    return false;
106
107
  /* LUKS2 header is not at expected offset */
108
0
  if (be16_to_cpu(header->version) == 2 &&
109
0
      be64_to_cpu(header->hdr_offset) != offset)
110
0
    return false;
111
112
0
  return true;
113
0
}
114
115
static int probe_luks(blkid_probe pr, const struct blkid_idmag *mag __attribute__((__unused__)))
116
0
{
117
0
  struct luks2_phdr *header;
118
0
  size_t i;
119
120
0
  header = (struct luks2_phdr *) blkid_probe_get_buffer(pr, 0, sizeof(struct luks2_phdr));
121
0
  if (!header)
122
0
    return errno ? -errno : BLKID_PROBE_NONE;
123
124
0
  if (luks_valid(header, LUKS_MAGIC, 0)) {
125
    /* LUKS primary header was found. */
126
0
    return luks_attributes(pr, header, 0);
127
0
  }
128
129
  /* No primary header, scan for known offsets of LUKS2 secondary header. */
130
0
  for (i = 0; i < ARRAY_SIZE(secondary_offsets); i++) {
131
0
    header = (struct luks2_phdr *) blkid_probe_get_buffer(pr,
132
0
        secondary_offsets[i], sizeof(struct luks2_phdr));
133
134
0
    if (!header)
135
0
      return errno ? -errno : BLKID_PROBE_NONE;
136
137
0
    if (luks_valid(header, LUKS_MAGIC_2, secondary_offsets[i]))
138
0
      return luks_attributes(pr, header, secondary_offsets[i]);
139
0
  }
140
141
0
  return BLKID_PROBE_NONE;
142
0
}
143
144
static int probe_luks_opal(blkid_probe pr, const struct blkid_idmag *mag __attribute__((__unused__)))
145
0
{
146
0
  struct luks2_phdr *header;
147
0
  int version;
148
149
0
  header = (struct luks2_phdr *) blkid_probe_get_buffer(pr, 0, sizeof(struct luks2_phdr));
150
0
  if (!header)
151
0
    return errno ? -errno : BLKID_PROBE_NONE;
152
153
0
  if (!luks_valid(header, LUKS_MAGIC, 0))
154
0
    return BLKID_PROBE_NONE;
155
156
0
  version = be16_to_cpu(header->version);
157
158
0
  if (version != 2)
159
0
    return BLKID_PROBE_NONE;
160
161
0
  if (memcmp(header->subsystem, LUKS2_HW_OPAL_SUBSYSTEM, sizeof(LUKS2_HW_OPAL_SUBSYSTEM)) != 0)
162
0
    return BLKID_PROBE_NONE;
163
164
0
  if (!blkdid_probe_is_opal_locked(pr))
165
0
    return BLKID_PROBE_NONE;
166
167
  /* Locked drive with LUKS2 HW OPAL encryption, finish probe now */
168
0
  return luks_attributes(pr, header, 0);
169
0
}
170
171
const struct blkid_idinfo luks_idinfo =
172
{
173
  .name   = "crypto_LUKS",
174
  .usage    = BLKID_USAGE_CRYPTO,
175
  .probefunc  = probe_luks,
176
  .magics   = BLKID_NONE_MAGIC
177
};
178
179
const struct blkid_idinfo luks_opal_idinfo =
180
{
181
  .name   = "crypto_LUKS",
182
  .usage    = BLKID_USAGE_CRYPTO,
183
  .probefunc  = probe_luks_opal,
184
  .magics   = BLKID_NONE_MAGIC,
185
};