Do not hardcode number of DM segments for BitLocker devices

Sometimes there is no gap between the metadata so we don't want to
create a dm-crypt segment there.
This commit is contained in:
Vojtech Trefny
2019-11-28 15:52:25 +01:00
committed by Milan Broz
parent 5ec2fbcd38
commit 834059ddfa
2 changed files with 130 additions and 121 deletions

View File

@@ -52,6 +52,8 @@
#define BITLK_KDF_HASH "sha256" #define BITLK_KDF_HASH "sha256"
#define BITLK_KDF_ITERATION_COUNT 0x100000 #define BITLK_KDF_ITERATION_COUNT 0x100000
/* maximum number of segments for the DM device */
#define MAX_BITLK_SEGMENTS 10
/* January 1, 1970 as MS file time */ /* January 1, 1970 as MS file time */
#define EPOCH_AS_FILETIME 116444736000000000 #define EPOCH_AS_FILETIME 116444736000000000
@@ -83,6 +85,18 @@ static void guid_to_string(struct bitlk_guid *guid, char *out) {
uuid_unparse((unsigned char *) guid, out); uuid_unparse((unsigned char *) guid, out);
} }
typedef enum {
BITLK_SEGTYPE_CRYPT,
BITLK_SEGTYPE_ZERO,
} BitlkSegmentType;
struct segment {
uint64_t offset;
uint64_t length;
uint64_t iv_offset;
BitlkSegmentType type;
};
struct bitlk_signature { struct bitlk_signature {
uint8_t boot_code[3]; uint8_t boot_code[3];
uint8_t signature[8]; uint8_t signature[8];
@@ -830,8 +844,10 @@ int BITLK_activate(struct crypt_device *cd,
uint32_t flags) uint32_t flags)
{ {
int r = 0; int r = 0;
uint64_t start = 0; int i = 0;
uint64_t size = 0; int j = 0;
int min = 0;
int num_segments = 0;
struct crypt_dm_active_device dmd = { struct crypt_dm_active_device dmd = {
.flags = flags, .flags = flags,
}; };
@@ -841,6 +857,11 @@ int BITLK_activate(struct crypt_device *cd,
struct volume_key *vmk_dec_key = NULL; struct volume_key *vmk_dec_key = NULL;
struct volume_key *recovery_key = NULL; struct volume_key *recovery_key = NULL;
const struct bitlk_vmk *next_vmk = NULL; const struct bitlk_vmk *next_vmk = NULL;
struct segment segments[MAX_BITLK_SEGMENTS] = {};
struct segment temp;
uint64_t next_start = 0;
uint64_t next_end = 0;
uint64_t last_segment = 0;
next_vmk = params->vmks; next_vmk = params->vmks;
while (next_vmk) { while (next_vmk) {
@@ -939,130 +960,118 @@ int BITLK_activate(struct crypt_device *cd,
return r; return r;
} }
r = dm_targets_allocate(&dmd.segment, 9); /* there will be always 4 dm-zero segments: 3x metadata, 1x FS header */
for (i = 0; i < 3; i++) {
segments[num_segments].offset = params->metadata_offset[i] / SECTOR_SIZE;
segments[num_segments].length = BITLK_FVE_METADATA_SIZE / SECTOR_SIZE;
segments[num_segments].iv_offset = 0;
segments[num_segments].type = BITLK_SEGTYPE_ZERO;
num_segments++;
}
segments[num_segments].offset = params->volume_header_offset / SECTOR_SIZE;
segments[num_segments].length = params->volume_header_size / SECTOR_SIZE;
segments[num_segments].iv_offset = 0;
segments[num_segments].type = BITLK_SEGTYPE_ZERO;
num_segments++;
/* filesystem header (moved from the special location) */
segments[num_segments].offset = 0;
segments[num_segments].length = params->volume_header_size / SECTOR_SIZE;
segments[num_segments].iv_offset = params->volume_header_offset / SECTOR_SIZE;
segments[num_segments].type = BITLK_SEGTYPE_CRYPT;
num_segments++;
/* now fill gaps between the dm-zero segments with dm-crypt */
last_segment = params->volume_header_size / SECTOR_SIZE;
while (true) {
next_start = dmd.size;
next_end = dmd.size;
/* start of the next segment: end of the first existing segment after the last added */
for (i = 0; i < num_segments; i++)
if (segments[i].offset + segments[i].length < next_start && segments[i].offset + segments[i].length >= last_segment)
next_start = segments[i].offset + segments[i].length;
/* end of the next segment: start of the next segment after start we found above */
for (i = 0; i < num_segments; i++)
if (segments[i].offset < next_end && segments[i].offset >= next_start)
next_end = segments[i].offset;
/* two zero segments next to each other, just bump the last_segment
so the algorithm moves */
if (next_end - next_start == 0) {
last_segment = next_end + 1;
continue;
}
segments[num_segments].offset = next_start;
segments[num_segments].length = next_end - next_start;
segments[num_segments].iv_offset = next_start;
segments[num_segments].type = BITLK_SEGTYPE_CRYPT;
last_segment = next_end;
num_segments++;
if (next_end == dmd.size)
break;
if (num_segments == 10) {
log_err(cd, "Failed to calculate number of dm-crypt segments for open.");
r = -EINVAL;
goto out;
}
}
/* device mapper needs the segment sorted */
for (i = 0; i < num_segments - 1; i++) {
min = i;
for (j = i + 1; j < num_segments; j++)
if (segments[j].offset < segments[min].offset)
min = j;
if (min != i) {
temp.offset = segments[min].offset;
temp.length = segments[min].length;
temp.iv_offset = segments[min].iv_offset;
temp.type = segments[min].type;
segments[min].offset = segments[i].offset;
segments[min].length = segments[i].length;
segments[min].iv_offset = segments[i].iv_offset;
segments[min].type = segments[i].type;
segments[i].offset = temp.offset;
segments[i].length = temp.length;
segments[i].iv_offset = temp.iv_offset;
segments[i].type = temp.type;
}
}
r = dm_targets_allocate(&dmd.segment, num_segments);
if (r) if (r)
goto out; goto out;
next_segment = &dmd.segment; next_segment = &dmd.segment;
/* filesystem header (moved from the special location) */ for (i = 0; i < num_segments; i++) {
start = 0; if (segments[i].type == BITLK_SEGTYPE_ZERO)
size = params->volume_header_size / SECTOR_SIZE; r = dm_zero_target_set(next_segment,
r = dm_crypt_target_set(next_segment, segments[i].offset,
start, size, segments[i].length);
crypt_data_device(cd), else if (segments[i].type == BITLK_SEGTYPE_CRYPT)
open_fvek_key, r = dm_crypt_target_set(next_segment,
crypt_get_cipher_spec(cd), segments[i].offset,
params->volume_header_offset / SECTOR_SIZE, segments[i].length,
params->volume_header_offset / SECTOR_SIZE, crypt_data_device(cd),
NULL, 0, open_fvek_key,
SECTOR_SIZE); crypt_get_cipher_spec(cd),
if (r) segments[i].iv_offset,
goto out; segments[i].iv_offset,
start += size; NULL, 0,
next_segment = next_segment->next; SECTOR_SIZE);
if (r)
goto out;
next_segment = next_segment->next;
/* first data part up to the first fve header */ }
size = (params->metadata_offset[0] / SECTOR_SIZE) - start;
r = dm_crypt_target_set(next_segment,
start, size,
crypt_data_device(cd),
open_fvek_key,
crypt_get_cipher_spec(cd),
start,
start,
NULL, 0,
SECTOR_SIZE);
if (r)
goto out;
start += size;
next_segment = next_segment->next;
/* zeroes instead of the first fve header */
size = BITLK_FVE_METADATA_SIZE / SECTOR_SIZE;
r = dm_zero_target_set(next_segment,
start,
size);
if (r)
goto out;
start += size;
next_segment = next_segment->next;
/* zeroes instead of the the encrypted filesystem header */
size = params->volume_header_size / SECTOR_SIZE;
r = dm_zero_target_set(next_segment,
start,
size);
if (r)
goto out;
start += size;
next_segment = next_segment->next;
/* second data part up to the second fve header */
size = (params->metadata_offset[1] / SECTOR_SIZE) - start;
r = dm_crypt_target_set(next_segment,
start, size,
crypt_data_device(cd),
open_fvek_key,
crypt_get_cipher_spec(cd),
start,
start,
NULL, 0,
SECTOR_SIZE);
if (r)
goto out;
start += size;
next_segment = next_segment->next;
/* zeroes instead of the second fve header */
size = BITLK_FVE_METADATA_SIZE / SECTOR_SIZE;
r = dm_zero_target_set(next_segment,
start,
size);
if (r)
goto out;
start += size;
next_segment = next_segment->next;
/* third data part up to the third fve header */
size = (params->metadata_offset[2] / SECTOR_SIZE) - start;
r = dm_crypt_target_set(next_segment,
start, size,
crypt_data_device(cd),
open_fvek_key,
crypt_get_cipher_spec(cd),
start,
start,
NULL, 0,
SECTOR_SIZE);
if (r)
goto out;
start += size;
next_segment = next_segment->next;
/* zeroes instead of the third fve header */
size = BITLK_FVE_METADATA_SIZE / SECTOR_SIZE;
r = dm_zero_target_set(next_segment,
start,
size);
if (r)
goto out;
start += size;
next_segment = next_segment->next;
/* fourth (and last) part of the data */
size = dmd.size - start;
r = dm_crypt_target_set(next_segment,
start, size,
crypt_data_device(cd),
open_fvek_key,
crypt_get_cipher_spec(cd),
start,
start,
NULL, 0,
SECTOR_SIZE);
if (r)
goto out;
log_dbg(cd, "Trying to activate BITLK on device %s%s%s.\n", log_dbg(cd, "Trying to activate BITLK on device %s%s%s.\n",
device_path(crypt_data_device(cd)), name ? " with name " :"", name ?: ""); device_path(crypt_data_device(cd)), name ? " with name " :"", name ?: "");

Binary file not shown.