From 18c92103423ffb312a49509881da4692eb98d9e9 Mon Sep 17 00:00:00 2001
From: Milan Broz <gmazyland@gmail.com>
Date: Sat, 24 Nov 2018 17:47:55 +0100
Subject: [PATCH 106/324] Check for device size and sector size misalignment.

Kernel prevents activation of device that is not aligned
to requested sector size.

Add early check to plain and LUKS2 formats to disallow
creation of such a device.
(Activation will fail in kernel later anyway.)

Fixes #390.
---
 lib/setup.c       | 20 ++++++++++++
 tests/align-test  | 53 +++++++++++++++++++++++++++---
 tests/align-test2 | 83 +++++++++++++++++++++++++++++++++--------------
 3 files changed, 127 insertions(+), 29 deletions(-)

diff --git a/lib/setup.c b/lib/setup.c
index a07c29c..ef4d453 100644
--- a/lib/setup.c
+++ b/lib/setup.c
@@ -1321,6 +1321,7 @@ static int _crypt_format_plain(struct crypt_device *cd,
 			       struct crypt_params_plain *params)
 {
 	unsigned int sector_size = params ? params->sector_size : SECTOR_SIZE;
+	uint64_t dev_size;
 
 	if (!cipher || !cipher_mode) {
 		log_err(cd, _("Invalid plain crypt parameters."));
@@ -1347,6 +1348,15 @@ static int _crypt_format_plain(struct crypt_device *cd,
 		return -EINVAL;
 	}
 
+	if (sector_size > SECTOR_SIZE && !device_size(cd->device, &dev_size)) {
+		if (params && params->offset)
+			dev_size -= (params->offset * SECTOR_SIZE);
+		if (dev_size % sector_size) {
+			log_err(cd, _("Device size is not aligned to requested sector size."));
+			return -EINVAL;
+		}
+	}
+
 	if (!(cd->type = strdup(CRYPT_PLAIN)))
 		return -ENOMEM;
 
@@ -1472,6 +1482,7 @@ static int _crypt_format_luks2(struct crypt_device *cd,
 	unsigned long alignment_offset = 0;
 	unsigned int sector_size = params ? params->sector_size : SECTOR_SIZE;
 	const char *integrity = params ? params->integrity : NULL;
+	uint64_t dev_size;
 
 	cd->u.luks2.hdr.jobj = NULL;
 
@@ -1578,6 +1589,15 @@ static int _crypt_format_luks2(struct crypt_device *cd,
 	if (r < 0)
 		goto out;
 
+	if (!integrity && sector_size > SECTOR_SIZE && !device_size(crypt_data_device(cd), &dev_size)) {
+		dev_size -= (crypt_get_data_offset(cd) * SECTOR_SIZE);
+		if (dev_size % sector_size) {
+			log_err(cd, _("Device size is not aligned to requested sector size."));
+			r = -EINVAL;
+			goto out;
+		}
+	}
+
 	if (params && (params->label || params->subsystem)) {
 		r = LUKS2_hdr_labels(cd, &cd->u.luks2.hdr,
 				     params->label, params->subsystem, 0);
-- 
2.19.1

