From b42d183b0852ddf4501fe991ce013e2c4d5cf1ac Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Tue, 10 Oct 2017 13:52:50 +0200 Subject: [PATCH] Create LUKS header file in luksFormat if it does not exist. --- configure.ac | 2 +- lib/internal.h | 1 + lib/luks1/keymanage.c | 12 ++++++++---- lib/luks2/luks2_disk_metadata.c | 11 ++++++++--- lib/utils_device.c | 18 ++++++++++++++++++ man/cryptsetup.8 | 2 +- src/cryptsetup.c | 21 ++++++++++++++++++++- tests/compat-test | 1 - tests/compat-test2 | 1 - 9 files changed, 57 insertions(+), 12 deletions(-) diff --git a/configure.ac b/configure.ac index 3c4f9b4f..95978c32 100644 --- a/configure.ac +++ b/configure.ac @@ -73,7 +73,7 @@ AC_SUBST(UUID_LIBS, $LIBS) LIBS=$saved_LIBS AC_SEARCH_LIBS([clock_gettime],[rt posix4]) -AC_CHECK_FUNCS([posix_memalign clock_gettime]) +AC_CHECK_FUNCS([posix_memalign clock_gettime posix_fallocate]) if test "x$enable_largefile" = "xno" ; then AC_MSG_ERROR([Building with --disable-largefile is not supported, it can cause data corruption.]) diff --git a/lib/internal.h b/lib/internal.h index 90bf8d3c..5d7be7a4 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -104,6 +104,7 @@ int device_is_identical(struct device *device1, struct device *device2); int device_is_rotational(struct device *device); size_t device_alignment(struct device *device); int device_direct_io(const struct device *device); +int device_fallocate(struct device *device, uint64_t size); int device_open_locked(struct device *device, int flags); int device_read_lock(struct crypt_device *cd, struct device *device); diff --git a/lib/luks1/keymanage.c b/lib/luks1/keymanage.c index f316bb75..4d81e854 100644 --- a/lib/luks1/keymanage.c +++ b/lib/luks1/keymanage.c @@ -102,7 +102,7 @@ size_t LUKS_keyslots_offset(const struct luks_phdr *hdr) return hdr->keyblock[sorted_areas[0]].keyMaterialOffset; } -static int LUKS_check_device_size(struct crypt_device *ctx, const struct luks_phdr *hdr) +static int LUKS_check_device_size(struct crypt_device *ctx, const struct luks_phdr *hdr, int falloc) { struct device *device = crypt_metadata_device(ctx); uint64_t dev_sectors, hdr_sectors; @@ -110,7 +110,7 @@ static int LUKS_check_device_size(struct crypt_device *ctx, const struct luks_ph if (!hdr->keyBytes) return -EINVAL; - if(device_size(device, &dev_sectors)) { + if (device_size(device, &dev_sectors)) { log_dbg("Cannot get device size for device %s.", device_path(device)); return -EIO; } @@ -121,6 +121,10 @@ static int LUKS_check_device_size(struct crypt_device *ctx, const struct luks_ph PRIu64 " sectors.", hdr->keyBytes, dev_sectors, hdr_sectors); if (hdr_sectors > dev_sectors) { + /* If it is header file, increase its size */ + if (falloc && !device_fallocate(device, hdr_sectors << SECTOR_SHIFT)) + return 0; + log_err(ctx, _("Device %s is too small. (LUKS requires at least %" PRIu64 " bytes.)\n"), device_path(device), hdr_sectors * SECTOR_SIZE); return -EINVAL; @@ -611,7 +615,7 @@ int LUKS_read_phdr(struct luks_phdr *hdr, repair, ctx); if (!r) - r = LUKS_check_device_size(ctx, hdr); + r = LUKS_check_device_size(ctx, hdr, 0); /* * Cryptsetup 1.0.0 did not align keyslots to 4k (very rare version). @@ -640,7 +644,7 @@ int LUKS_write_phdr(struct luks_phdr *hdr, log_dbg("Updating LUKS header of size %zu on device %s", sizeof(struct luks_phdr), device_path(device)); - r = LUKS_check_device_size(ctx, hdr); + r = LUKS_check_device_size(ctx, hdr, 1); if (r) return r; diff --git a/lib/luks2/luks2_disk_metadata.c b/lib/luks2/luks2_disk_metadata.c index 91579f11..db4d9f67 100644 --- a/lib/luks2/luks2_disk_metadata.c +++ b/lib/luks2/luks2_disk_metadata.c @@ -343,7 +343,8 @@ static int hdr_write_disk(struct device *device, struct luks2_hdr *hdr, return r; } -static int LUKS2_check_device_size(struct crypt_device *cd, struct device *device, uint64_t hdr_size) +static int LUKS2_check_device_size(struct crypt_device *cd, struct device *device, + uint64_t hdr_size, int falloc) { uint64_t dev_size; @@ -356,6 +357,10 @@ static int LUKS2_check_device_size(struct crypt_device *cd, struct device *devic PRIu64 ".", dev_size, hdr_size); if (hdr_size > dev_size) { + /* If it is header file, increase its size */ + if (falloc && !device_fallocate(device, hdr_size)) + return 0; + log_err(cd, _("Device %s is too small. (LUKS2 requires at least %" PRIu64 " bytes.)\n"), device_path(device), hdr_size); return -EINVAL; @@ -385,7 +390,7 @@ int LUKS2_disk_hdr_write(struct crypt_device *cd, struct luks2_hdr *hdr, struct return -EINVAL; } - r = LUKS2_check_device_size(cd, crypt_metadata_device(cd), LUKS2_hdr_and_areas_size(hdr->jobj)); + r = LUKS2_check_device_size(cd, crypt_metadata_device(cd), LUKS2_hdr_and_areas_size(hdr->jobj), 1); if (r) return r; @@ -589,7 +594,7 @@ int LUKS2_disk_hdr_read(struct crypt_device *cd, struct luks2_hdr *hdr, goto err; } - r = LUKS2_check_device_size(cd, device, hdr_size); + r = LUKS2_check_device_size(cd, device, hdr_size, 0); if (r) goto err; diff --git a/lib/utils_device.c b/lib/utils_device.c index 0aba1422..4476e964 100644 --- a/lib/utils_device.c +++ b/lib/utils_device.c @@ -492,6 +492,24 @@ out: return r; } +/* For a file, allocate the required space */ +int device_fallocate(struct device *device, uint64_t size) +{ + struct stat st; + int devfd, r = -EINVAL; + + devfd = open(device->path, O_WRONLY); + if(devfd == -1) + return -EINVAL; + + if (!fstat(devfd, &st) && S_ISREG(st.st_mode) && + !posix_fallocate(devfd, 0, size)) + r = 0; + + close(devfd); + return r; +} + static int device_info(struct crypt_device *cd, struct device *device, enum devcheck device_check, diff --git a/man/cryptsetup.8 b/man/cryptsetup.8 index 75ad1cac..d8d9c5dd 100644 --- a/man/cryptsetup.8 +++ b/man/cryptsetup.8 @@ -1016,7 +1016,7 @@ used with the \fIluksFormat\fR, \fIopen\fR, \fIluksSuspend\fR, \fIluksResume\fR, \fIstatus\fR and \fIresize\fR commands. For \fIluksFormat\fR with a file name as the argument to \-\-header, -it has to exist and be large enough to contain the LUKS header. +the file will be automatically created if it does not exist. See the cryptsetup FAQ for header size calculation. For other commands that change the LUKS header (e.g. \fIluksAddKey\fR), diff --git a/src/cryptsetup.c b/src/cryptsetup.c index 547b9860..9cbf827b 100644 --- a/src/cryptsetup.c +++ b/src/cryptsetup.c @@ -929,7 +929,8 @@ static int _wipe_data_device(struct crypt_device *cd) static int action_luksFormat(void) { - int r = -EINVAL, keysize, integrity_keysize = 0, luks_version; + int r = -EINVAL, keysize, integrity_keysize = 0, luks_version, fd; + struct stat st; const char *header_device; char *msg = NULL, *key = NULL, *password = NULL; char cipher [MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN], integrity[MAX_CIPHER_LEN]; @@ -960,6 +961,24 @@ static int action_luksFormat(void) return -EINVAL; } + /* Create header file (must contain at least one sector)? */ + if (opt_header_device && stat(opt_header_device, &st) < 0 && errno == ENOENT) { + if (!opt_batch_mode && + !yesDialog("Header file does not exist, do you want to create it?", NULL)) + return -EPERM; + + log_dbg("Creating header file."); + fd = open(opt_header_device, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR); + if (fd == -1 || posix_fallocate(fd, 0, 4096)) + log_err(_("Cannot create header file %s.\n"), opt_header_device); + else + r = 0; + if (fd != -1) + close(fd); + if (r < 0) + return r; + } + header_device = opt_header_device ?: action_argv[0]; if(asprintf(&msg, _("This will overwrite data on %s irrevocably."), diff --git a/tests/compat-test b/tests/compat-test index 29cf1df2..1fd4715f 100755 --- a/tests/compat-test +++ b/tests/compat-test @@ -639,7 +639,6 @@ $CRYPTSETUP luksOpen -S 5 -d $KEY1 $LOOPDEV $DEV_NAME && fail [ -b /dev/mapper/$DEV_NAME ] && fail prepare "[28] Detached LUKS header" wipe -dd if=/dev/zero of=$HEADER_IMG bs=1M count=4 >/dev/null 2>&1 echo $PWD1 | $CRYPTSETUP luksFormat $FAST_PBKDF_OPT $LOOPDEV --header $HEADER_IMG || fail echo $PWD1 | $CRYPTSETUP luksFormat $FAST_PBKDF_OPT $LOOPDEV --header $HEADER_IMG --align-payload 1 >/dev/null 2>&1 && fail echo $PWD1 | $CRYPTSETUP luksFormat $FAST_PBKDF_OPT $LOOPDEV --header $HEADER_IMG --align-payload 8192 || fail diff --git a/tests/compat-test2 b/tests/compat-test2 index c85475ad..8fe9daad 100755 --- a/tests/compat-test2 +++ b/tests/compat-test2 @@ -569,7 +569,6 @@ echo $PWD1 | $CRYPTSETUP open --test-passphrase $HEADER_KEYU || fail echo $PWD1 | $CRYPTSETUP open -S1 $HEADER_KEYU $DEV_NAME && fail prepare "[28] Detached LUKS header" wipe -dd if=/dev/zero of=$HEADER_IMG bs=1M count=4 >/dev/null 2>&1 echo $PWD1 | $CRYPTSETUP luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV --header $HEADER_IMG || fail #FIXME #echo $PWD1 | $CRYPTSETUP luksFormat $FAST_PBKDF_OPT $LOOPDEV --header $HEADER_IMG --align-payload 1 >/dev/null 2>&1 && fail