7714f9
From ae7b79ff8a7fb576c018bc9a7eaf9e135b7b553e Mon Sep 17 00:00:00 2001
7714f9
From: Karel Zak <kzak@redhat.com>
7714f9
Date: Tue, 24 Apr 2018 10:57:48 +0200
7714f9
Subject: [PATCH 36/40] libblkid: add BitLocker detection
7714f9
7714f9
Supported:
7714f9
* WinVista version
7714f9
* Win7 and later versions (based on NTFS)
7714f9
* BitLockerToGo (for removable media; based on FAT32)
7714f9
7714f9
Unfortunately, it's without LABEL and UUID. It seems BitLocker does
7714f9
not use volume_label and volume_serial stuff from NTFS header.
7714f9
7714f9
Upstream: http://github.com/karelzak/util-linux/commit/136f89ce5ed8cd159a1c56b5a775dada2363ecd3
7714f9
Upstream: http://github.com/karelzak/util-linux/commit/47afae0caaa2b3440d6ac812079e3ada5f2aa0bd (bitlocker.c part)
7714f9
Addresses: https://bugzilla.redhat.com/show_bug.cgi?id=1812576
7714f9
Addresses: https://github.com/karelzak/util-linux/issues/617
7714f9
Signed-off-by: Karel Zak <kzak@redhat.com>
7714f9
---
7714f9
 libblkid/src/Makemodule.am             |   1 +
7714f9
 libblkid/src/superblocks/bitlocker.c   | 191 +++++++++++++++++++++++++
7714f9
 libblkid/src/superblocks/superblocks.c |   1 +
7714f9
 libblkid/src/superblocks/superblocks.h |   3 +
7714f9
 libblkid/src/superblocks/vfat.c        |   3 +
7714f9
 5 files changed, 199 insertions(+)
7714f9
 create mode 100644 libblkid/src/superblocks/bitlocker.c
7714f9
7714f9
diff --git a/libblkid/src/Makemodule.am b/libblkid/src/Makemodule.am
7714f9
index 0e1c765fb..ea0230702 100644
7714f9
--- a/libblkid/src/Makemodule.am
7714f9
+++ b/libblkid/src/Makemodule.am
7714f9
@@ -47,6 +47,7 @@ libblkid_la_SOURCES = \
7714f9
 	libblkid/src/superblocks/bcache.c \
7714f9
 	libblkid/src/superblocks/befs.c \
7714f9
 	libblkid/src/superblocks/bfs.c \
7714f9
+	libblkid/src/superblocks/bitlocker.c \
7714f9
 	libblkid/src/superblocks/btrfs.c \
7714f9
 	libblkid/src/superblocks/cramfs.c \
7714f9
 	libblkid/src/superblocks/ddf_raid.c \
7714f9
diff --git a/libblkid/src/superblocks/bitlocker.c b/libblkid/src/superblocks/bitlocker.c
7714f9
new file mode 100644
7714f9
index 000000000..111edf39b
7714f9
--- /dev/null
7714f9
+++ b/libblkid/src/superblocks/bitlocker.c
7714f9
@@ -0,0 +1,191 @@
7714f9
+/*
7714f9
+ * Copyright (C) 2018 Karel Zak <kzak@redhat.com>
7714f9
+ *
7714f9
+ * This file may be redistributed under the terms of the
7714f9
+ * GNU Lesser General Public License.
7714f9
+ */
7714f9
+#include <stdio.h>
7714f9
+#include <stdlib.h>
7714f9
+#include <unistd.h>
7714f9
+#include <string.h>
7714f9
+#include <errno.h>
7714f9
+#include <ctype.h>
7714f9
+#include <stdint.h>
7714f9
+
7714f9
+#include "superblocks.h"
7714f9
+
7714f9
+#define BDE_HDR_SIZE	512
7714f9
+#define BDE_HDR_OFFSET	0
7714f9
+
7714f9
+struct bde_header_win7 {
7714f9
+/*   0 */ unsigned char	boot_entry_point[3];
7714f9
+/*   3 */ unsigned char	fs_signature[8];
7714f9
+/*  11 */ unsigned char	__dummy1[67 - 11];
7714f9
+/*  67 */ uint32_t      volume_serial;		/* NTFS uses 64bit serial number */
7714f9
+/*  71 */ unsigned char volume_label[11];	/* "NO NAME\x20\x20\x20\x20" only */
7714f9
+/*  82 */ unsigned char __dummy2[160 - 82];
7714f9
+/* 160 */ unsigned char guid[16];		/* BitLocker specific GUID */
7714f9
+/* 176 */ uint64_t      fve_metadata_offset;
7714f9
+} __attribute__((packed));
7714f9
+
7714f9
+
7714f9
+struct bde_header_togo {
7714f9
+/*   0 */ unsigned char	boot_entry_point[3];
7714f9
+/*   3 */ unsigned char	fs_signature[8];
7714f9
+/*  11 */ unsigned char	__dummy[424 - 11];
7714f9
+/* 424 */ unsigned char guid[16];
7714f9
+/* 440 */ uint64_t      fve_metadata_offset;
7714f9
+} __attribute__((packed));
7714f9
+
7714f9
+
7714f9
+struct bde_fve_metadata {
7714f9
+/*   0 */ unsigned char  signature[8];
7714f9
+/*   8 */ uint16_t       size;
7714f9
+/*  10 */ uint16_t       version;
7714f9
+};
7714f9
+
7714f9
+enum {
7714f9
+	BDE_VERSION_VISTA = 0,
7714f9
+	BDE_VERSION_WIN7,
7714f9
+	BDE_VERSION_TOGO
7714f9
+};
7714f9
+
7714f9
+#define BDE_MAGIC_VISTA		"\xeb\x52\x90-FVE-FS-"
7714f9
+#define BDE_MAGIC_WIN7		"\xeb\x58\x90-FVE-FS-"
7714f9
+#define BDE_MAGIC_TOGO		"\xeb\x58\x90MSWIN4.1"
7714f9
+
7714f9
+#define BDE_MAGIC_FVE		"-FVE-FS-"
7714f9
+
7714f9
+static int get_bitlocker_type(const unsigned char *buf)
7714f9
+{
7714f9
+	size_t i;
7714f9
+	static const char *map[] = {
7714f9
+		[BDE_VERSION_VISTA] = BDE_MAGIC_VISTA,
7714f9
+		[BDE_VERSION_WIN7]  = BDE_MAGIC_WIN7,
7714f9
+		[BDE_VERSION_TOGO]  = BDE_MAGIC_TOGO
7714f9
+	};
7714f9
+
7714f9
+	for (i = 0; i < ARRAY_SIZE(map); i++) {
7714f9
+		if (memcmp(buf, map[i], 11) == 0)
7714f9
+			return (int) i;
7714f9
+	}
7714f9
+
7714f9
+	return -1;
7714f9
+}
7714f9
+
7714f9
+/* Returns: < 0 error, 1 nothing, 0 success
7714f9
+ */
7714f9
+static int get_bitlocker_headers(blkid_probe pr,
7714f9
+				int *type,
7714f9
+				const unsigned char **buf_hdr,
7714f9
+				const unsigned char **buf_fve)
7714f9
+{
7714f9
+
7714f9
+	const unsigned char *buf;
7714f9
+	const struct bde_fve_metadata *fve;
7714f9
+	uint64_t off = 0;
7714f9
+	int kind;
7714f9
+
7714f9
+	if (buf_hdr)
7714f9
+		*buf_hdr = NULL;
7714f9
+	if (buf_fve)
7714f9
+		*buf_fve = NULL;
7714f9
+	if (type)
7714f9
+		*type = -1;
7714f9
+
7714f9
+	buf = blkid_probe_get_buffer(pr, BDE_HDR_OFFSET, BDE_HDR_SIZE);
7714f9
+	if (!buf)
7714f9
+		return errno ? -errno : 1;
7714f9
+
7714f9
+	kind = get_bitlocker_type(buf);
7714f9
+
7714f9
+	/* Check BitLocker header */
7714f9
+	switch (kind) {
7714f9
+	case BDE_VERSION_WIN7:
7714f9
+		off = le64_to_cpu(((const struct bde_header_win7 *) buf)->fve_metadata_offset);
7714f9
+		break;
7714f9
+	case BDE_VERSION_TOGO:
7714f9
+		off = le64_to_cpu(((const struct bde_header_togo *) buf)->fve_metadata_offset);
7714f9
+		break;
7714f9
+	case BDE_VERSION_VISTA:
7714f9
+		goto done;
7714f9
+	default:
7714f9
+		goto nothing;
7714f9
+	}
7714f9
+
7714f9
+	if (!off)
7714f9
+		goto nothing;
7714f9
+	if (buf_hdr)
7714f9
+		*buf_hdr = buf;
7714f9
+
7714f9
+	/* Check Bitlocker FVE metadata header */
7714f9
+	buf = blkid_probe_get_buffer(pr, off, sizeof(struct bde_fve_metadata));
7714f9
+	if (!buf)
7714f9
+		return errno ? -errno : 1;
7714f9
+
7714f9
+	fve = (const struct bde_fve_metadata *) buf;
7714f9
+	if (memcmp(fve->signature, BDE_MAGIC_FVE, sizeof(fve->signature)) != 0)
7714f9
+		goto nothing;
7714f9
+	if (buf_fve)
7714f9
+		*buf_fve = buf;
7714f9
+done:
7714f9
+	if (type)
7714f9
+		*type = kind;
7714f9
+	return 0;
7714f9
+nothing:
7714f9
+	return 1;
7714f9
+}
7714f9
+
7714f9
+/*
7714f9
+ * This is used by vFAT and NTFS prober to avoid collisions with bitlocker.
7714f9
+ */
7714f9
+int blkid_probe_is_bitlocker(blkid_probe pr)
7714f9
+{
7714f9
+	return get_bitlocker_headers(pr, NULL, NULL, NULL) == 0;
7714f9
+}
7714f9
+
7714f9
+static int probe_bitlocker(blkid_probe pr,
7714f9
+		const struct blkid_idmag *mag __attribute__((__unused__)))
7714f9
+{
7714f9
+	const unsigned char *buf_fve = NULL;
7714f9
+	const unsigned char *buf_hdr = NULL;
7714f9
+	int rc, kind;
7714f9
+
7714f9
+	rc = get_bitlocker_headers(pr, &kind, &buf_hdr, &buf_fve);
7714f9
+	if (rc)
7714f9
+		return rc;
7714f9
+
7714f9
+	if (kind == BDE_VERSION_WIN7) {
7714f9
+		const struct bde_header_win7 *hdr = (const struct bde_header_win7 *) buf_hdr;
7714f9
+
7714f9
+		/* Unfortunately, it seems volume_serial is always zero */
7714f9
+		blkid_probe_sprintf_uuid(pr,
7714f9
+				(const unsigned char *) &hdr->volume_serial,
7714f9
+				sizeof(hdr->volume_serial),
7714f9
+				"%016d", le32_to_cpu(hdr->volume_serial));
7714f9
+	}
7714f9
+
7714f9
+	if (buf_fve) {
7714f9
+		const struct bde_fve_metadata *fve = (const struct bde_fve_metadata *) buf_fve;
7714f9
+
7714f9
+		blkid_probe_sprintf_version(pr, "%d", fve->version);
7714f9
+	}
7714f9
+	return 0;
7714f9
+}
7714f9
+
7714f9
+/* See header details:
7714f9
+ * https://github.com/libyal/libbde/blob/master/documentation/BitLocker%20Drive%20Encryption%20(BDE)%20format.asciidoc
7714f9
+ */
7714f9
+const struct blkid_idinfo bitlocker_idinfo =
7714f9
+{
7714f9
+	.name		= "BitLocker",
7714f9
+	.usage		= BLKID_USAGE_CRYPTO,
7714f9
+	.probefunc	= probe_bitlocker,
7714f9
+	.magics		=
7714f9
+	{
7714f9
+		{ .magic = BDE_MAGIC_VISTA, .len = 11 },
7714f9
+		{ .magic = BDE_MAGIC_WIN7,  .len = 11 },
7714f9
+		{ .magic = BDE_MAGIC_TOGO,  .len = 11 },
7714f9
+		{ NULL }
7714f9
+	}
7714f9
+};
7714f9
diff --git a/libblkid/src/superblocks/superblocks.c b/libblkid/src/superblocks/superblocks.c
7714f9
index 076541d1a..6dfd2be64 100644
7714f9
--- a/libblkid/src/superblocks/superblocks.c
7714f9
+++ b/libblkid/src/superblocks/superblocks.c
7714f9
@@ -115,6 +115,7 @@ static const struct blkid_idinfo *idinfos[] =
7714f9
 	&ubi_idinfo,
7714f9
 	&vdo_idinfo,
7714f9
 	&stratis_idinfo,
7714f9
+	&bitlocker_idinfo,
7714f9
 
7714f9
 	/* Filesystems */
7714f9
 	&vfat_idinfo,
7714f9
diff --git a/libblkid/src/superblocks/superblocks.h b/libblkid/src/superblocks/superblocks.h
7714f9
index 2723fb1d5..d677f85bc 100644
7714f9
--- a/libblkid/src/superblocks/superblocks.h
7714f9
+++ b/libblkid/src/superblocks/superblocks.h
7714f9
@@ -81,6 +81,7 @@ extern const struct blkid_idinfo bcache_idinfo;
7714f9
 extern const struct blkid_idinfo mpool_idinfo;
7714f9
 extern const struct blkid_idinfo vdo_idinfo;
7714f9
 extern const struct blkid_idinfo stratis_idinfo;
7714f9
+extern const struct blkid_idinfo bitlocker_idinfo;
7714f9
 
7714f9
 /*
7714f9
  * superblock functions
7714f9
@@ -105,4 +106,6 @@ extern int blkid_probe_set_id_label(blkid_probe pr, const char *name,
7714f9
 extern int blkid_probe_set_utf8_id_label(blkid_probe pr, const char *name,
7714f9
 			     unsigned char *data, size_t len, int enc);
7714f9
 
7714f9
+extern int blkid_probe_is_bitlocker(blkid_probe pr);
7714f9
+
7714f9
 #endif /* _BLKID_SUPERBLOCKS_H */
7714f9
diff --git a/libblkid/src/superblocks/vfat.c b/libblkid/src/superblocks/vfat.c
7714f9
index 3aeba018a..29b3c501c 100644
7714f9
--- a/libblkid/src/superblocks/vfat.c
7714f9
+++ b/libblkid/src/superblocks/vfat.c
7714f9
@@ -268,6 +268,9 @@ static int fat_valid_superblock(blkid_probe pr,
7714f9
 		}
7714f9
 	}
7714f9
 
7714f9
+	if (blkid_probe_is_bitlocker(pr))
7714f9
+		return 0;
7714f9
+
7714f9
 	return 1;	/* valid */
7714f9
 }
7714f9
 
7714f9
-- 
7714f9
2.25.4
7714f9