On Sun, 21 Mar 2021 at 00:51:06 +0100, Guilhem Moulin wrote: > I'm seeking pre-approval to upload cryptsetup/2:2.3.5-1 to unstable. > Hopefully the attached debdiff is not too large/intrusive for inclusion > in Bullseye. For convenience I'm also attaching a diff with the ‘tests’ > and ‘po’ directories (which arguably add a lot of clutter), as well as a > diff with only upstream's ‘lib’ and ‘src’ directories (given it's really > what this is about). Ooops Savaltore pointed out that the message wasn't delivered to debian-release@l.d.o due to its attachment size. Not a good sign perhaps, although most of the clutter is due to offset updates in .po file annotations… The original attachments can be found at https://bugs.debian.org/985629 , but here is a new try with only .debdiff-trimmed (source tree diff excluding ‘tests’ and ‘po’ directories) , as well as the output of `git diff -b debian/2%2.3.4-2 -- lib src debian` *after* reverting upstream's copyright year update in headings (so preserving only upstream code changes and debian changes). -- Guilhem.
Attachment:
cryptsetup.debdiff-trimmed.gz
Description: application/gzip
diff --git a/debian/README.source b/debian/README.source
index 15c40923..a24270ac 100644
--- a/debian/README.source
+++ b/debian/README.source
@@ -21,31 +21,19 @@ Importing a new upstream release
git remote add upstream https://gitlab.com/cryptsetup/cryptsetup.git
git config remote.upstream.fetch +refs/heads/master:refs/remotes/upstream/master
git branch -u refs/remotes/upstream/master upstream/latest
+ git config remote.upstream.tagOpt --tags
- 1. Update 'upstream' remote
-
- git fetch --tags upstream
-
- 2. Determine the release tag corresponding to the new release. At the time
- of this writing, upstream uses tags in the form:
-
- TAG="v$VERSION"
-
- This convention may change, so double-check with 'git tag'.
-
- 3. Validate the gpg signature for this release tag:
-
- git verify-tag "$TAG"
-
- The signing key can be found in 'debian/upstream-signing-key.asc'.
- Use `gpg -q debian/upstream-signing-key.asc` to show its
- fingerprint.
-
- 4. Merge the upstream release tag <tag> into the 'debian/latest'
+ 1. Merge the newest upstream release tag (pass --upstream-version=$VERSION
+ if you want a specific upstream version) into the 'debian/latest'
branch of your packaging repository:
- git checkout debian/latest
- git merge -m "Updated version $VERSION from '$TAG'" "$TAG"
+ gbp import-orig --uscan
+
+ That commands does all the magic, namely
+ - updating the `upstream` remote,
+ - verifying the cryptographic signature on the upstream tag 'v$VERSION',
+ - creating a new tag 'upstream/$VERSION' with 'v$VERSION' as additional parent, and
+ - merging 'upstream/$VERSION' it into 'debian/latest'
N. After development and testing, the final packages to be uploaded to
Debian are built and tagged in the repository as follows:
diff --git a/debian/changelog b/debian/changelog
index cf73b180..9f71768f 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,18 @@
+cryptsetup (2:2.3.5-1) unstable; urgency=medium
+
+ * New upstream bugfix release. (Closes: #985581)
+ * d/watch: Monitor upstream tags rather than tarballs.
+ * d/gbp.conf: Set 'upstream-vcs-tag' to add upstream tag as additional
+ parent.
+ * Simplify d/README.source in accordance with the above.
+ * Rename d/upstream-signing-key.asc to d/upstream/signing-key.asc as uscan
+ is now able to verify git tags.
+ * encrypted-boot.md: Clarify how to solve double password prompt for the
+ device holding /boot.
+ * d/copyright: Update copyright year.
+
+ -- Guilhem Moulin <guilhem@debian.org> Thu, 11 Mar 2021 23:33:13 +0100
+
cryptsetup (2:2.3.4-2) unstable; urgency=medium
[ Guilhem Moulin ]
diff --git a/debian/copyright b/debian/copyright
index 058d0c35..8ce5f177 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -5,8 +5,8 @@ Source: https://gitlab.com/cryptsetup/cryptsetup
Files: *
Copyright: © 2004 Christophe Saout <christophe@saout.de>
© 2004-2008 Clemens Fruhwirth <clemens@endorphin.org>
- © 2008-2019 Red Hat, Inc.
- © 2008-2019 Milan Broz <gmazyland@gmail.com>
+ © 2008-2021 Red Hat, Inc.
+ © 2008-2021 Milan Broz <gmazyland@gmail.com>
License: GPL-2+ with OpenSSL exception
Files: debian/*
@@ -45,7 +45,7 @@ Copyright: © 2005-2015 Jonas Meurer <jonas@freesources.org>
License: GPL-2+
Files: docs/examples/*
-Copyright: © 2011-2019 Red Hat, Inc.
+Copyright: © 2011-2021 Red Hat, Inc.
License: LGPL-2.1+
Files: lib/base64.c
@@ -53,13 +53,13 @@ Copyright: © 1999-2001, 2004-2006, 2009-2018 Free Software Foundation, Inc.
License: GPL-2+
Files: lib/crypto_backend/* lib/loopaes/* lib/tcrypt/* lib/verity/*
-Copyright: © 2009-2019 Red Hat, Inc.
- © 2010-2019 Milan Broz <gmazyland@gmail.com>
+Copyright: © 2009-2021 Red Hat, Inc.
+ © 2010-2021 Milan Broz <gmazyland@gmail.com>
License: LGPL-2.1+
Files: lib/crypto_backend/crypto_openssl.c
-Copyright: © 2009-2019 Red Hat, Inc.
- © 2010-2019 Milan Broz <gmazyland@gmail.com>
+Copyright: © 2009-2021 Red Hat, Inc.
+ © 2010-2021 Milan Broz <gmazyland@gmail.com>
License: LGPL-2.1+ with OpenSSL exception
Files: lib/crypto_backend/argon2/*
diff --git a/debian/doc/pandoc/encrypted-boot.md b/debian/doc/pandoc/encrypted-boot.md
index 39ca4deb..52db07f4 100644
--- a/debian/doc/pandoc/encrypted-boot.md
+++ b/debian/doc/pandoc/encrypted-boot.md
@@ -158,10 +158,11 @@ system: no need to reboot into a live CD or an initramfs shell.
You can skip the next sub-section and go directly to [Enabling
`cryptomount` in GRUB2]. Note that `init`(1) needs to unlock the
`/boot` partition *again* during the boot process. See [Avoiding the
-extra password prompt] for details and a proposed workaround. (Only
-steps 1-3 from that section are relevant here; no need to copy the key
-file to the initramfs image since `/boot` can be unlocked and mounted
-later during the boot process.)
+extra password prompt] for details and a proposed workaround. (You'll
+need to substitute `/` resp. `sda5` with `/boot` resp. `sda1` in that
+section, however only steps 1-3 are relevant here: no need to copy the
+key file to the initramfs image since `/boot` can be unlocked and
+mounted later during the boot process.)
Moving `/boot` to the root file system
diff --git a/debian/gbp.conf b/debian/gbp.conf
index d9d405ee..823bf5ba 100644
--- a/debian/gbp.conf
+++ b/debian/gbp.conf
@@ -1,5 +1,7 @@
[DEFAULT]
debian-branch = debian/latest
upstream-branch = upstream/latest
-upstream-tag = v%(version)s
pristine-tar = False
+
+[import-orig]
+upstream-vcs-tag = v%(version)s
diff --git a/debian/upstream-signing-key.asc b/debian/upstream/signing-key.asc
similarity index 100%
rename from debian/upstream-signing-key.asc
rename to debian/upstream/signing-key.asc
diff --git a/debian/watch b/debian/watch
index 39eee672..161cf2c2 100644
--- a/debian/watch
+++ b/debian/watch
@@ -1,4 +1,4 @@
version=4
-#options="decompress,pgpsigurlmangle=s/\.(?:gz|xz)$/.sign/" \
-https://www.kernel.org/pub/linux/utils/cryptsetup/v(\d[\d\.]*)/ \
- cryptsetup-(\d[\d\.]*)\.tar\.(?:gz|xz)
+options="mode=git,pgpmode=gittag" \
+ https://gitlab.com/cryptsetup/cryptsetup.git \
+ refs/tags/v?@ANY_VERSION@
diff --git a/lib/bitlk/bitlk.c b/lib/bitlk/bitlk.c
index ea3d0c5b..9c3fba37 100644
--- a/lib/bitlk/bitlk.c
+++ b/lib/bitlk/bitlk.c
@@ -54,6 +54,9 @@
#define BITLK_RECOVERY_PARTS 8
#define BITLK_RECOVERY_PART_LEN 6
+#define BITLK_BEK_FILE_HEADER_LEN 48
+#define BITLK_STARTUP_KEY_HEADER_LEN 24
+
#define BITLK_KDF_HASH "sha256"
#define BITLK_KDF_ITERATION_COUNT 0x100000
@@ -162,6 +165,18 @@ struct bitlk_kdf_data {
uint64_t count;
};
+struct bitlk_bek_header {
+ uint32_t metadata_size;
+ uint32_t metadata_version;
+ uint32_t metadata_header_size;
+ uint32_t metada_size_copy;
+ struct bitlk_guid guid;
+ uint32_t next_nonce;
+ uint16_t encryption;
+ uint16_t unknown;
+ uint64_t creation_time;
+} __attribute__ ((packed));
+
static BITLKVMKProtection get_vmk_protection(uint16_t protection)
{
switch (protection) {
@@ -311,7 +326,9 @@ static int parse_vmk_entry(struct crypt_device *cd, uint8_t *data, int start, in
bool supported = false;
/* only passphrase or recovery passphrase vmks are supported (can be used to activate) */
- supported = (*vmk)->protection == BITLK_PROTECTION_PASSPHRASE || (*vmk)->protection == BITLK_PROTECTION_RECOVERY_PASSPHRASE;
+ supported = (*vmk)->protection == BITLK_PROTECTION_PASSPHRASE ||
+ (*vmk)->protection == BITLK_PROTECTION_RECOVERY_PASSPHRASE ||
+ (*vmk)->protection == BITLK_PROTECTION_STARTUP_KEY;
while (end - start > 2) {
/* size of this entry */
@@ -394,6 +411,9 @@ static int parse_vmk_entry(struct crypt_device *cd, uint8_t *data, int start, in
(*vmk)->name = string;
string = NULL;
}
+ /* no idea what this is, lets hope it's not important */
+ } else if (key_entry_value == BITLK_ENTRY_VALUE_USE_KEY && (*vmk)->protection == BITLK_PROTECTION_STARTUP_KEY) {
+ ;
} else {
if (supported) {
log_err(cd, _("Unexpected metadata entry value '%u' found when parsing supported Volume Master Key."), key_entry_value);
@@ -436,6 +456,9 @@ void BITLK_bitlk_vmk_free(struct bitlk_vmk *vmk)
void BITLK_bitlk_metadata_free(struct bitlk_metadata *metadata)
{
+ if (!metadata)
+ return;
+
free(metadata->guid);
if (metadata->description)
free(metadata->description);
@@ -481,18 +504,6 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
goto out;
}
- if (memcmp(sig.boot_code, BITLK_BOOTCODE_V1, sizeof(sig.boot_code)) == 0) {
- log_err(cd, _("BITLK version 1 is currently not supported."));
- r = -ENOTSUP;
- goto out;
- } else if (memcmp(sig.boot_code, BITLK_BOOTCODE_V2, sizeof(sig.boot_code)) == 0)
- ;
- else {
- log_err(cd, _("Invalid or unknown boot signature for BITLK device."));
- r = -EINVAL;
- goto out;
- }
-
if (memcmp(sig.signature, BITLK_SIGNATURE, sizeof(sig.signature)) == 0) {
params->togo = false;
fve_offset = BITLK_HEADER_METADATA_OFFSET;
@@ -505,6 +516,18 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
goto out;
}
+ if (memcmp(sig.boot_code, BITLK_BOOTCODE_V1, sizeof(sig.boot_code)) == 0) {
+ log_err(cd, _("BITLK version 1 is currently not supported."));
+ r = -ENOTSUP;
+ goto out;
+ } else if (memcmp(sig.boot_code, BITLK_BOOTCODE_V2, sizeof(sig.boot_code)) == 0)
+ ;
+ else {
+ log_err(cd, _("Invalid or unknown boot signature for BITLK device."));
+ r = -EINVAL;
+ goto out;
+ }
+
params->sector_size = le16_to_cpu(sig.sector_size);
if (params->sector_size == 0) {
log_dbg(cd, "Got sector size 0, assuming 512.");
@@ -564,12 +587,12 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
switch (le16_to_cpu(fve.encryption)) {
/* AES-CBC with Elephant difuser */
case 0x8000:
- params->key_size = 128;
+ params->key_size = 256;
params->cipher = "aes";
params->cipher_mode = "cbc-elephant";
break;
case 0x8001:
- params->key_size = 256;
+ params->key_size = 512;
params->cipher = "aes";
params->cipher_mode = "cbc-elephant";
break;
@@ -586,12 +609,12 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
break;
/* AES-XTS */
case 0x8004:
- params->key_size = 128;
+ params->key_size = 256;
params->cipher = "aes";
params->cipher_mode = "xts-plain64";
break;
case 0x8005:
- params->key_size = 256;
+ params->key_size = 512;
params->cipher = "aes";
params->cipher_mode = "xts-plain64";
break;
@@ -628,7 +651,7 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), fve_entries, fve_metadata_size - BITLK_FVE_METADATA_HEADER_LEN,
- params->metadata_offset[0] + BITLK_FVE_METADATA_HEADERS_LEN) != fve_metadata_size - BITLK_FVE_METADATA_HEADER_LEN) {
+ params->metadata_offset[0] + BITLK_FVE_METADATA_HEADERS_LEN) != (ssize_t)(fve_metadata_size - BITLK_FVE_METADATA_HEADER_LEN)) {
log_err(cd, _("Failed to read BITLK metadata entries from %s."), device_path(device));
r = -EINVAL;
goto out;
@@ -654,6 +677,10 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
sizeof(entry_vmk));
vmk = malloc(sizeof(struct bitlk_vmk));
+ if (!vmk) {
+ r = -ENOMEM;
+ goto out;
+ }
memset(vmk, 0, sizeof(struct bitlk_vmk));
guid_to_string(&entry_vmk.guid, guid_buf);
@@ -682,6 +709,10 @@ int BITLK_read_sb(struct crypt_device *cd, struct bitlk_metadata *params)
/* FVEK */
} else if (entry_type == BITLK_ENTRY_TYPE_FVEK) {
params->fvek = malloc(sizeof(struct bitlk_fvek));
+ if (!params->fvek) {
+ r = -ENOMEM;
+ goto out;
+ }
memcpy(params->fvek->nonce,
fve_entries + start + BITLK_ENTRY_HEADER_LEN,
sizeof(params->fvek->nonce));
@@ -838,6 +869,120 @@ static int get_recovery_key(struct crypt_device *cd,
return 0;
}
+static int parse_external_key_entry(struct crypt_device *cd, const char *data, int start, int end, struct volume_key **vk)
+{
+ uint16_t key_entry_size = 0;
+ uint16_t key_entry_type = 0;
+ uint16_t key_entry_value = 0;
+ size_t key_size = 0;
+ const char *key = NULL;
+
+ while (end - start > 2) {
+ /* size of this entry */
+ memcpy(&key_entry_size, data + start, sizeof(key_entry_size));
+ key_entry_size = le16_to_cpu(key_entry_size);
+ if (key_entry_size == 0)
+ break;
+
+ /* type and value of this entry */
+ memcpy(&key_entry_type, data + start + sizeof(key_entry_size), sizeof(key_entry_type));
+ memcpy(&key_entry_value,
+ data + start + sizeof(key_entry_size) + sizeof(key_entry_type),
+ sizeof(key_entry_value));
+ key_entry_type = le16_to_cpu(key_entry_type);
+ key_entry_value = le16_to_cpu(key_entry_value);
+
+ /* only properties should be in this entry */
+ if (key_entry_type != BITLK_ENTRY_TYPE_PROPERTY) {
+ log_err(cd, _("Unexpected metadata entry type '%u' found when parsing external key."), key_entry_type);
+ return -EINVAL;
+ }
+
+ if (key_entry_value == BITLK_ENTRY_VALUE_KEY) {
+ key_size = key_entry_size - (BITLK_ENTRY_HEADER_LEN + 4);
+ key = (const char *) data + start + BITLK_ENTRY_HEADER_LEN + 4;
+ *vk = crypt_alloc_volume_key(key_size, key);
+ if (*vk == NULL)
+ return -ENOMEM;
+ return 0;
+ /* optional "ExternalKey" string, we can safely ignore it */
+ } else if (key_entry_value == BITLK_ENTRY_VALUE_STRING)
+ ;
+ else {
+ log_err(cd, _("Unexpected metadata entry value '%u' found when parsing external key."), key_entry_value);
+ return -EINVAL;
+ }
+
+ start += key_entry_size;
+ }
+
+ /* if we got here we failed to parse the metadata */
+ return -EINVAL;
+}
+
+/* check if given passphrase can be a startup key (has right format) and convert it */
+static int get_startup_key(struct crypt_device *cd,
+ const char *password,
+ size_t passwordLen,
+ const struct bitlk_vmk *vmk,
+ struct volume_key **su_key)
+{
+ struct bitlk_bek_header bek_header = {0};
+ char guid_buf[UUID_STR_LEN] = {0};
+
+ uint16_t key_entry_size = 0;
+ uint16_t key_entry_type = 0;
+ uint16_t key_entry_value = 0;
+
+ if (passwordLen < BITLK_BEK_FILE_HEADER_LEN)
+ return -EPERM;
+
+ memcpy(&bek_header, password, BITLK_BEK_FILE_HEADER_LEN);
+
+ /* metadata should contain GUID of the VMK this startup key is used for */
+ guid_to_string(&bek_header.guid, guid_buf);
+ if (strcmp(guid_buf, vmk->guid) == 0)
+ log_dbg(cd, "Found matching startup key for VMK %s", vmk->guid);
+ else
+ return -EPERM;
+
+ if (bek_header.metadata_version != 1) {
+ log_err(cd, "Unsupported BEK metadata version %" PRIu32 "", bek_header.metadata_version);
+ return -ENOTSUP;
+ }
+
+ if (bek_header.metadata_size != passwordLen) {
+ log_err(cd, "Unexpected BEK metadata size %" PRIu32 " does not match BEK file length", bek_header.metadata_size);
+ return -EINVAL;
+ }
+
+ /* we are expecting exactly one metadata entry starting immediately after the header */
+ memcpy(&key_entry_size, password + BITLK_BEK_FILE_HEADER_LEN, sizeof(key_entry_size));
+ key_entry_size = le16_to_cpu(key_entry_size);
+ if (key_entry_size < BITLK_ENTRY_HEADER_LEN) {
+ log_dbg(cd, "Unexpected metadata entry size %" PRIu16 " when parsing BEK file", key_entry_size);
+ return -EINVAL;
+ }
+
+ /* type and value of this entry */
+ memcpy(&key_entry_type, password + BITLK_BEK_FILE_HEADER_LEN + sizeof(key_entry_size), sizeof(key_entry_type));
+ memcpy(&key_entry_value,
+ password + BITLK_BEK_FILE_HEADER_LEN + sizeof(key_entry_size) + sizeof(key_entry_type),
+ sizeof(key_entry_value));
+ key_entry_type = le16_to_cpu(key_entry_type);
+ key_entry_value = le16_to_cpu(key_entry_value);
+
+ if (key_entry_type == BITLK_ENTRY_TYPE_STARTUP_KEY && key_entry_value == BITLK_ENTRY_VALUE_EXTERNAL_KEY) {
+ return parse_external_key_entry(cd, password,
+ BITLK_BEK_FILE_HEADER_LEN + BITLK_ENTRY_HEADER_LEN + BITLK_STARTUP_KEY_HEADER_LEN,
+ passwordLen, su_key);
+ } else {
+ log_err(cd, _("Unexpected metadata entry found when parsing startup key."));
+ log_dbg(cd, "Entry type: %u, entry value: %u", key_entry_type, key_entry_value);
+ return -EINVAL;
+ }
+}
+
static int bitlk_kdf(struct crypt_device *cd,
const char *password,
size_t passwordLen,
@@ -939,7 +1084,7 @@ static int decrypt_key(struct crypt_device *cd,
}
if (is_fvek && strcmp(crypt_get_cipher_mode(cd), "cbc-elephant") == 0 &&
- crypt_get_volume_key_size(cd) == 16) {
+ crypt_get_volume_key_size(cd) == 32) {
/* 128bit AES-CBC with Elephant -- key size is 256 bit (2 keys) but key data is 512 bits,
data: 16B CBC key, 16B empty, 16B elephant key, 16B empty */
memcpy(outbuf + 16 + BITLK_OPEN_KEY_METADATA_LEN,
@@ -1000,12 +1145,18 @@ int BITLK_activate(struct crypt_device *cd,
while (next_vmk) {
if (next_vmk->protection == BITLK_PROTECTION_PASSPHRASE) {
r = bitlk_kdf(cd, password, passwordLen, false, next_vmk->salt, &vmk_dec_key);
- if (r)
- return r;
+ if (r) {
+ /* something wrong happened, but we still want to check other key slots */
+ next_vmk = next_vmk->next;
+ continue;
+ }
} else if (next_vmk->protection == BITLK_PROTECTION_RECOVERY_PASSPHRASE) {
r = get_recovery_key(cd, password, passwordLen, &recovery_key);
- if (r)
- return r;
+ if (r) {
+ /* something wrong happened, but we still want to check other key slots */
+ next_vmk = next_vmk->next;
+ continue;
+ }
if (recovery_key == NULL) {
/* r = 0 but no key -> given passphrase is not a recovery passphrase */
r = -EPERM;
@@ -1018,8 +1169,15 @@ int BITLK_activate(struct crypt_device *cd,
crypt_free_volume_key(recovery_key);
if (r)
return r;
+ } else if (next_vmk->protection == BITLK_PROTECTION_STARTUP_KEY) {
+ r = get_startup_key(cd, password, passwordLen, next_vmk, &vmk_dec_key);
+ if (r) {
+ next_vmk = next_vmk->next;
+ continue;
+ }
+ log_dbg(cd, "Trying to use external key found in provided password.");
} else {
- /* only passphrase and recovery passphrase VMKs supported right now */
+ /* only passphrase, recovery passphrase and startup key VMKs supported right now */
log_dbg(cd, "Skipping %s", get_vmk_protection_string(next_vmk->protection));
next_vmk = next_vmk->next;
if (r == 0)
diff --git a/lib/crypto_backend/crypto_cipher_kernel.c b/lib/crypto_backend/crypto_cipher_kernel.c
index 1a8aecfc..b2a92b51 100644
--- a/lib/crypto_backend/crypto_cipher_kernel.c
+++ b/lib/crypto_backend/crypto_cipher_kernel.c
@@ -152,6 +152,9 @@ static int _crypt_cipher_crypt(struct crypt_cipher_kernel *ctx,
/* Set IV */
if (iv) {
header = CMSG_NXTHDR(&msg, header);
+ if (!header)
+ return -EINVAL;
+
header->cmsg_level = SOL_ALG;
header->cmsg_type = ALG_SET_IV;
header->cmsg_len = iv_msg_size;
diff --git a/lib/crypto_backend/pbkdf_check.c b/lib/crypto_backend/pbkdf_check.c
index 7444e0aa..2c86036c 100644
--- a/lib/crypto_backend/pbkdf_check.c
+++ b/lib/crypto_backend/pbkdf_check.c
@@ -361,8 +361,10 @@ static int crypt_pbkdf_check(const char *kdf, const char *hash,
ms = time_ms(&rstart, &rend);
if (ms) {
PBKDF2_temp = (double)iterations * target_ms / ms;
- if (PBKDF2_temp > UINT32_MAX)
- return -EINVAL;
+ if (PBKDF2_temp > UINT32_MAX) {
+ r = -EINVAL;
+ goto out;
+ }
*iter_secs = (uint32_t)PBKDF2_temp;
}
diff --git a/lib/integrity/integrity.c b/lib/integrity/integrity.c
index 86305ce4..39b6a39f 100644
--- a/lib/integrity/integrity.c
+++ b/lib/integrity/integrity.c
@@ -40,7 +40,7 @@ static int INTEGRITY_read_superblock(struct crypt_device *cd,
if (read_lseek_blockwise(devfd, device_block_size(cd, device),
device_alignment(device), sb, sizeof(*sb), offset) != sizeof(*sb) ||
memcmp(sb->magic, SB_MAGIC, sizeof(sb->magic)) ||
- sb->version < SB_VERSION_1 || sb->version > SB_VERSION_4) {
+ sb->version < SB_VERSION_1 || sb->version > SB_VERSION_5) {
log_std(cd, "No integrity superblock detected on %s.\n",
device_path(device));
r = -EINVAL;
@@ -92,14 +92,15 @@ int INTEGRITY_dump(struct crypt_device *cd, struct device *device, uint64_t offs
log_std(cd, "journal_sections %u\n", sb.journal_sections);
log_std(cd, "provided_data_sectors %" PRIu64 "\n", sb.provided_data_sectors);
log_std(cd, "sector_size %u\n", SECTOR_SIZE << sb.log2_sectors_per_block);
- if (sb.version == SB_VERSION_2 && (sb.flags & SB_FLAG_RECALCULATING))
+ if (sb.version >= SB_VERSION_2 && (sb.flags & SB_FLAG_RECALCULATING))
log_std(cd, "recalc_sector %" PRIu64 "\n", sb.recalc_sector);
log_std(cd, "log2_blocks_per_bitmap %u\n", sb.log2_blocks_per_bitmap_bit);
- log_std(cd, "flags %s%s%s%s\n",
+ log_std(cd, "flags %s%s%s%s%s\n",
sb.flags & SB_FLAG_HAVE_JOURNAL_MAC ? "have_journal_mac " : "",
sb.flags & SB_FLAG_RECALCULATING ? "recalculating " : "",
sb.flags & SB_FLAG_DIRTY_BITMAP ? "dirty_bitmap " : "",
- sb.flags & SB_FLAG_FIXED_PADDING ? "fix_padding " : "");
+ sb.flags & SB_FLAG_FIXED_PADDING ? "fix_padding " : "",
+ sb.flags & SB_FLAG_FIXED_HMAC ? "fix_hmac " : "");
return 0;
}
@@ -278,6 +279,15 @@ int INTEGRITY_activate_dmd_device(struct crypt_device *cd,
return -ENOTSUP;
}
+ if (r < 0 && (dmd->flags & CRYPT_ACTIVATE_RECALCULATE) &&
+ !(crypt_get_compatibility(cd) & CRYPT_COMPAT_LEGACY_INTEGRITY_RECALC) &&
+ ((sb_flags & SB_FLAG_FIXED_HMAC) ?
+ (tgt->u.integrity.vk && !tgt->u.integrity.journal_integrity_key) :
+ (tgt->u.integrity.vk || tgt->u.integrity.journal_integrity_key))) {
+ log_err(cd, _("Kernel refuses to activate insecure recalculate option (see legacy activation options to override)."));
+ return -ENOTSUP;
+ }
+
return r;
}
diff --git a/lib/integrity/integrity.h b/lib/integrity/integrity.h
index 38c4c5ee..72737dd6 100644
--- a/lib/integrity/integrity.h
+++ b/lib/integrity/integrity.h
@@ -35,11 +35,13 @@ struct crypt_dm_active_device;
#define SB_VERSION_2 2
#define SB_VERSION_3 3
#define SB_VERSION_4 4
+#define SB_VERSION_5 5
#define SB_FLAG_HAVE_JOURNAL_MAC (1 << 0)
#define SB_FLAG_RECALCULATING (1 << 1) /* V2 only */
#define SB_FLAG_DIRTY_BITMAP (1 << 2) /* V3 only */
#define SB_FLAG_FIXED_PADDING (1 << 3) /* V4 only */
+#define SB_FLAG_FIXED_HMAC (1 << 4) /* V5 only */
struct superblock {
uint8_t magic[8];
diff --git a/lib/internal.h b/lib/internal.h
index a418a465..89403cf2 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -266,4 +266,12 @@ int crypt_compare_dm_devices(struct crypt_device *cd,
const struct crypt_dm_active_device *tgt);
static inline void *crypt_zalloc(size_t size) { return calloc(1, size); }
+static inline bool uint64_mult_overflow(uint64_t *u, uint64_t b, size_t size)
+{
+ *u = (uint64_t)b * size;
+ if ((uint64_t)(*u / size) != b)
+ return true;
+ return false;
+}
+
#endif /* INTERNAL_H */
diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h
index 3d002c0c..9620ebbe 100644
--- a/lib/libcryptsetup.h
+++ b/lib/libcryptsetup.h
@@ -652,6 +652,10 @@ uint32_t crypt_get_compatibility(struct crypt_device *cd);
/** dm-integrity device uses less effective (legacy) padding (old kernels) */
#define CRYPT_COMPAT_LEGACY_INTEGRITY_PADDING (1 << 0)
+/** dm-integrity device does not protect superblock with HMAC (old kernels) */
+#define CRYPT_COMPAT_LEGACY_INTEGRITY_HMAC (1 << 1)
+/** dm-integrity allow recalculating of volumes with HMAC keys (old kernels) */
+#define CRYPT_COMPAT_LEGACY_INTEGRITY_RECALC (1 << 2)
/**
* Convert to new type for already existing device.
@@ -1485,11 +1489,11 @@ const char *crypt_get_cipher_mode(struct crypt_device *cd);
const char *crypt_get_uuid(struct crypt_device *cd);
/**
- * Get path to underlaying device.
+ * Get path to underlying device.
*
* @param cd crypt device handle
*
- * @return path to underlaying device name
+ * @return path to underlying device name
*
*/
const char *crypt_get_device_name(struct crypt_device *cd);
@@ -1499,7 +1503,7 @@ const char *crypt_get_device_name(struct crypt_device *cd);
*
* @param cd crypt device handle
*
- * @return path to underlaying device name
+ * @return path to underlying device name
*
*/
const char *crypt_get_metadata_device_name(struct crypt_device *cd);
@@ -2295,7 +2299,7 @@ int crypt_reencrypt_init_by_keyring(struct crypt_device *cd,
* Run data reencryption.
*
* @param cd crypt device handle
- * @param progress is a callback funtion reporting device \b size,
+ * @param progress is a callback function reporting device \b size,
* current \b offset of reencryption and provided \b usrptr identification
*
* @return @e 0 on success or negative errno value otherwise.
@@ -2336,17 +2340,15 @@ crypt_reencrypt_info crypt_reencrypt_status(struct crypt_device *cd,
*
* @param size size of memory in bytes
*
- * @return pointer to allocate memory or @e NULL.
+ * @return pointer to allocated memory or @e NULL.
*/
void *crypt_safe_alloc(size_t size);
/**
- * Release safe memory, content is safely wiped
+ * Release safe memory, content is safely wiped.
* The pointer must be allocated with @link crypt_safe_alloc @endlink
*
* @param data pointer to memory to be deallocated
- *
- * @return pointer to allocate memory or @e NULL.
*/
void crypt_safe_free(void *data);
@@ -2356,17 +2358,15 @@ void crypt_safe_free(void *data);
* @param data pointer to memory to be deallocated
* @param size new size of memory in bytes
*
- * @return pointer to allocate memory or @e NULL.
+ * @return pointer to allocated memory or @e NULL.
*/
void *crypt_safe_realloc(void *data, size_t size);
/**
* Safe clear memory area (compile should not compile this call out).
*
- * @param data pointer to memory to cleared
- * @param size new size of memory in bytes
- *
- * @return pointer to allocate memory or @e NULL.
+ * @param data pointer to memory to be cleared
+ * @param size size of memory in bytes
*/
void crypt_safe_memzero(void *data, size_t size);
diff --git a/lib/libdevmapper.c b/lib/libdevmapper.c
index 8f8c94b5..aebd4513 100644
--- a/lib/libdevmapper.c
+++ b/lib/libdevmapper.c
@@ -239,6 +239,9 @@ static void _dm_set_integrity_compat(struct crypt_device *cd,
if (_dm_satisfies_version(1, 6, 0, integrity_maj, integrity_min, integrity_patch))
_dm_flags |= DM_INTEGRITY_DISCARDS_SUPPORTED;
+ if (_dm_satisfies_version(1, 7, 0, integrity_maj, integrity_min, integrity_patch))
+ _dm_flags |= DM_INTEGRITY_FIX_HMAC_SUPPORTED;
+
_dm_integrity_checked = true;
}
@@ -648,14 +651,16 @@ static char *get_dm_crypt_params(const struct dm_target *tgt, uint32_t flags)
} else
*features = '\0';
- if (!strncmp(cipher_dm, "cipher_null-", 12))
+ if (crypt_is_cipher_null(cipher_dm))
null_cipher = 1;
- if (flags & CRYPT_ACTIVATE_KEYRING_KEY) {
+ if (null_cipher)
+ hexkey = crypt_safe_alloc(2);
+ else if (flags & CRYPT_ACTIVATE_KEYRING_KEY) {
keystr_len = strlen(tgt->u.crypt.vk->key_description) + int_log10(tgt->u.crypt.vk->keylength) + 10;
hexkey = crypt_safe_alloc(keystr_len);
} else
- hexkey = crypt_safe_alloc(null_cipher ? 2 : (tgt->u.crypt.vk->keylength * 2 + 1));
+ hexkey = crypt_safe_alloc(tgt->u.crypt.vk->keylength * 2 + 1);
if (!hexkey)
return NULL;
@@ -728,7 +733,7 @@ static char *get_dm_verity_params(const struct dm_target *tgt, uint32_t flags)
snprintf(fec_features, sizeof(fec_features)-1,
" use_fec_from_device %s fec_start %" PRIu64 " fec_blocks %" PRIu64 " fec_roots %" PRIu32,
device_block_path(tgt->u.verity.fec_device), tgt->u.verity.fec_offset,
- vp->data_size + tgt->u.verity.hash_blocks, vp->fec_roots);
+ tgt->u.verity.fec_blocks, vp->fec_roots);
} else
*fec_features = '\0';
@@ -912,12 +917,25 @@ static char *get_dm_integrity_params(const struct dm_target *tgt, uint32_t flags
strncat(features, feature, sizeof(features) - strlen(features) - 1);
crypt_safe_free(hexkey);
}
+
if (tgt->u.integrity.fix_padding) {
num_options++;
snprintf(feature, sizeof(feature), "fix_padding ");
strncat(features, feature, sizeof(features) - strlen(features) - 1);
}
+ if (tgt->u.integrity.fix_hmac) {
+ num_options++;
+ snprintf(feature, sizeof(feature), "fix_hmac ");
+ strncat(features, feature, sizeof(features) - strlen(features) - 1);
+ }
+
+ if (tgt->u.integrity.legacy_recalc) {
+ num_options++;
+ snprintf(feature, sizeof(feature), "legacy_recalculate ");
+ strncat(features, feature, sizeof(features) - strlen(features) - 1);
+ }
+
if (flags & CRYPT_ACTIVATE_RECALCULATE) {
num_options++;
snprintf(feature, sizeof(feature), "recalculate ");
@@ -1654,6 +1672,14 @@ int dm_create_device(struct crypt_device *cd, const char *name,
r = _dm_create_device(cd, name, type, dmd->uuid, dmd);
}
+ /*
+ * Print warning if activating dm-crypt cipher_null device unless it's reencryption helper or
+ * keyslot encryption helper device (LUKS1 cipher_null devices).
+ */
+ if (!r && !(dmd->flags & CRYPT_ACTIVATE_PRIVATE) && single_segment(dmd) && dmd->segment.type == DM_CRYPT &&
+ crypt_is_cipher_null(dmd->segment.u.crypt.cipher))
+ log_dbg(cd, "Activated dm-crypt device with cipher_null. Device is not encrypted.");
+
if (r == -EINVAL &&
dmd->flags & (CRYPT_ACTIVATE_SAME_CPU_CRYPT|CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS) &&
!(dmt_flags & (DM_SAME_CPU_CRYPT_SUPPORTED|DM_SUBMIT_FROM_CRYPT_CPUS_SUPPORTED)))
@@ -2474,6 +2500,10 @@ static int _dm_target_query_integrity(struct crypt_device *cd,
*act_flags |= CRYPT_ACTIVATE_RECALCULATE;
} else if (!strcmp(arg, "fix_padding")) {
tgt->u.integrity.fix_padding = true;
+ } else if (!strcmp(arg, "fix_hmac")) {
+ tgt->u.integrity.fix_hmac = true;
+ } else if (!strcmp(arg, "legacy_recalculate")) {
+ tgt->u.integrity.legacy_recalc = true;
} else if (!strcmp(arg, "allow_discards")) {
*act_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
} else /* unknown option */
@@ -2913,7 +2943,9 @@ int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name,
if (!(dmt_flags & DM_KEY_WIPE_SUPPORTED))
goto out;
- if (vk->key_description)
+ if (!vk->keylength)
+ msg_size = 11; // key set -
+ else if (vk->key_description)
msg_size = strlen(vk->key_description) + int_log10(vk->keylength) + 18;
else
msg_size = vk->keylength * 2 + 10; // key set <key>
@@ -2925,7 +2957,9 @@ int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name,
}
strcpy(msg, "key set ");
- if (vk->key_description)
+ if (!vk->keylength)
+ snprintf(msg + 8, msg_size - 8, "-");
+ else if (vk->key_description)
snprintf(msg + 8, msg_size - 8, ":%zu:logon:%s", vk->keylength, vk->key_description);
else
hex_key(&msg[8], vk->keylength, vk->key);
@@ -3000,8 +3034,8 @@ err:
int dm_verity_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t seg_size,
struct device *data_device, struct device *hash_device, struct device *fec_device,
- const char *root_hash, uint32_t root_hash_size, const char *root_hash_sig_key_desc,
- uint64_t hash_offset_block, uint64_t hash_blocks, struct crypt_params_verity *vp)
+ const char *root_hash, uint32_t root_hash_size, const char* root_hash_sig_key_desc,
+ uint64_t hash_offset_block, uint64_t fec_blocks, struct crypt_params_verity *vp)
{
if (!data_device || !hash_device || !vp)
return -EINVAL;
@@ -3019,7 +3053,7 @@ int dm_verity_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t se
tgt->u.verity.root_hash_sig_key_desc = root_hash_sig_key_desc;
tgt->u.verity.hash_offset = hash_offset_block;
tgt->u.verity.fec_offset = vp->fec_area_offset / vp->hash_block_size;
- tgt->u.verity.hash_blocks = hash_blocks;
+ tgt->u.verity.fec_blocks = fec_blocks;
tgt->u.verity.vp = vp;
return 0;
@@ -3060,6 +3094,15 @@ int dm_integrity_target_set(struct crypt_device *cd,
!(crypt_get_compatibility(cd) & CRYPT_COMPAT_LEGACY_INTEGRITY_PADDING))
tgt->u.integrity.fix_padding = true;
+ if (!dm_flags(cd, DM_INTEGRITY, &dmi_flags) &&
+ (dmi_flags & DM_INTEGRITY_FIX_HMAC_SUPPORTED) &&
+ !(crypt_get_compatibility(cd) & CRYPT_COMPAT_LEGACY_INTEGRITY_HMAC))
+ tgt->u.integrity.fix_hmac = true;
+
+ /* This flag can be backported, just try to set it always */
+ if (crypt_get_compatibility(cd) & CRYPT_COMPAT_LEGACY_INTEGRITY_RECALC)
+ tgt->u.integrity.legacy_recalc = true;
+
if (ip) {
tgt->u.integrity.journal_size = ip->journal_size;
tgt->u.integrity.journal_watermark = ip->journal_watermark;
diff --git a/lib/luks1/keymanage.c b/lib/luks1/keymanage.c
index a08ff50f..4cbb5f86 100644
--- a/lib/luks1/keymanage.c
+++ b/lib/luks1/keymanage.c
@@ -375,8 +375,13 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
log_err(ctx, _("Non standard key size, manual repair required."));
return -EINVAL;
}
- /* cryptsetup 1.0 did not align to 4k, cannot repair this one */
- if (LUKS_keyslots_offset(phdr) < (LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE)) {
+
+ /*
+ * cryptsetup 1.0 did not align keyslots to 4k, cannot repair this one
+ * Also we cannot trust possibly broken keyslots metadata here through LUKS_keyslots_offset().
+ * Expect first keyslot is aligned, if not, then manual repair is neccessary.
+ */
+ if (phdr->keyblock[0].keyMaterialOffset < (LUKS_ALIGN_KEYSLOTS / SECTOR_SIZE)) {
log_err(ctx, _("Non standard keyslots alignment, manual repair required."));
return -EINVAL;
}
@@ -386,6 +391,8 @@ static int _keyslot_repair(struct luks_phdr *phdr, struct crypt_device *ctx)
return -EINVAL;
vk = crypt_alloc_volume_key(phdr->keyBytes, NULL);
+ if (!vk)
+ return -ENOMEM;
log_verbose(ctx, _("Repairing keyslots."));
@@ -955,12 +962,12 @@ static int LUKS_open_key(unsigned int keyIndex,
const char *password,
size_t passwordLen,
struct luks_phdr *hdr,
- struct volume_key *vk,
+ struct volume_key **vk,
struct crypt_device *ctx)
{
crypt_keyslot_info ki = LUKS_keyslot_info(hdr, keyIndex);
struct volume_key *derived_key;
- char *AfKey;
+ char *AfKey = NULL;
size_t AFEKSize;
int r;
@@ -974,8 +981,13 @@ static int LUKS_open_key(unsigned int keyIndex,
if (!derived_key)
return -ENOMEM;
- assert(vk->keylength == hdr->keyBytes);
- AFEKSize = AF_split_sectors(vk->keylength, hdr->keyblock[keyIndex].stripes) * SECTOR_SIZE;
+ *vk = crypt_alloc_volume_key(hdr->keyBytes, NULL);
+ if (!*vk) {
+ r = -ENOMEM;
+ goto out;
+ }
+
+ AFEKSize = AF_split_sectors(hdr->keyBytes, hdr->keyblock[keyIndex].stripes) * SECTOR_SIZE;
AfKey = crypt_safe_alloc(AFEKSize);
if (!AfKey) {
r = -ENOMEM;
@@ -1001,16 +1013,20 @@ static int LUKS_open_key(unsigned int keyIndex,
if (r < 0)
goto out;
- r = AF_merge(ctx, AfKey, vk->key, vk->keylength, hdr->keyblock[keyIndex].stripes, hdr->hashSpec);
+ r = AF_merge(ctx, AfKey, (*vk)->key, (*vk)->keylength, hdr->keyblock[keyIndex].stripes, hdr->hashSpec);
if (r < 0)
goto out;
- r = LUKS_verify_volume_key(hdr, vk);
+ r = LUKS_verify_volume_key(hdr, *vk);
/* Allow only empty passphrase with null cipher */
- if (!r && !strcmp(hdr->cipherName, "cipher_null") && passwordLen)
+ if (!r && crypt_is_cipher_null(hdr->cipherName) && passwordLen)
r = -EPERM;
out:
+ if (r < 0) {
+ crypt_free_volume_key(*vk);
+ *vk = NULL;
+ }
crypt_safe_free(AfKey);
crypt_free_volume_key(derived_key);
return r;
@@ -1026,16 +1042,14 @@ int LUKS_open_key_with_hdr(int keyIndex,
unsigned int i, tried = 0;
int r;
- *vk = crypt_alloc_volume_key(hdr->keyBytes, NULL);
-
if (keyIndex >= 0) {
- r = LUKS_open_key(keyIndex, password, passwordLen, hdr, *vk, ctx);
+ r = LUKS_open_key(keyIndex, password, passwordLen, hdr, vk, ctx);
return (r < 0) ? r : keyIndex;
}
for (i = 0; i < LUKS_NUMKEYS; i++) {
- r = LUKS_open_key(i, password, passwordLen, hdr, *vk, ctx);
- if(r == 0)
+ r = LUKS_open_key(i, password, passwordLen, hdr, vk, ctx);
+ if (r == 0)
return i;
/* Do not retry for errors that are no -EPERM or -ENOENT,
diff --git a/lib/luks2/luks2.h b/lib/luks2/luks2.h
index 5b29a627..79560d33 100644
--- a/lib/luks2/luks2.h
+++ b/lib/luks2/luks2.h
@@ -23,6 +23,8 @@
#define _CRYPTSETUP_LUKS2_ONDISK_H
#include <stdbool.h>
+#include <stdint.h>
+#include <sys/types.h>
#include "libcryptsetup.h"
@@ -330,6 +332,12 @@ int LUKS2_token_is_assigned(struct crypt_device *cd,
int keyslot,
int token);
+int LUKS2_token_assignment_copy(struct crypt_device *cd,
+ struct luks2_hdr *hdr,
+ int keyslot_from,
+ int keyslot_to,
+ int commit);
+
int LUKS2_token_create(struct crypt_device *cd,
struct luks2_hdr *hdr,
int token,
diff --git a/lib/luks2/luks2_disk_metadata.c b/lib/luks2/luks2_disk_metadata.c
index 9654cdb8..47ad5462 100644
--- a/lib/luks2/luks2_disk_metadata.c
+++ b/lib/luks2/luks2_disk_metadata.c
@@ -175,13 +175,13 @@ static void hdr_to_disk(struct luks2_hdr *hdr,
hdr_disk->hdr_offset = cpu_to_be64(offset);
hdr_disk->seqid = cpu_to_be64(hdr->seqid);
- strncpy(hdr_disk->label, hdr->label, LUKS2_LABEL_L);
+ memcpy(hdr_disk->label, hdr->label, MIN(strlen(hdr->label), LUKS2_LABEL_L));
hdr_disk->label[LUKS2_LABEL_L - 1] = '\0';
- strncpy(hdr_disk->subsystem, hdr->subsystem, LUKS2_LABEL_L);
+ memcpy(hdr_disk->subsystem, hdr->subsystem, MIN(strlen(hdr->subsystem), LUKS2_LABEL_L));
hdr_disk->subsystem[LUKS2_LABEL_L - 1] = '\0';
- strncpy(hdr_disk->checksum_alg, hdr->checksum_alg, LUKS2_CHECKSUM_ALG_L);
+ memcpy(hdr_disk->checksum_alg, hdr->checksum_alg, MIN(strlen(hdr->checksum_alg), LUKS2_CHECKSUM_ALG_L));
hdr_disk->checksum_alg[LUKS2_CHECKSUM_ALG_L - 1] = '\0';
- strncpy(hdr_disk->uuid, hdr->uuid, LUKS2_UUID_L);
+ memcpy(hdr_disk->uuid, hdr->uuid, MIN(strlen(hdr->uuid), LUKS2_UUID_L));
hdr_disk->uuid[LUKS2_UUID_L - 1] = '\0';
memcpy(hdr_disk->salt, secondary ? hdr->salt2 : hdr->salt1, LUKS2_SALT_L);
diff --git a/lib/luks2/luks2_json_format.c b/lib/luks2/luks2_json_format.c
index fb695f08..5cc92d98 100644
--- a/lib/luks2/luks2_json_format.c
+++ b/lib/luks2/luks2_json_format.c
@@ -244,7 +244,8 @@ int LUKS2_generate_hdr(
/* Decrease keyslots_size due to metadata device being too small */
if (!device_size(crypt_metadata_device(cd), &mdev_size) &&
((keyslots_size + get_min_offset(hdr)) > mdev_size) &&
- device_fallocate(crypt_metadata_device(cd), keyslots_size + get_min_offset(hdr)))
+ device_fallocate(crypt_metadata_device(cd), keyslots_size + get_min_offset(hdr)) &&
+ (get_min_offset(hdr) <= mdev_size))
keyslots_size = mdev_size - get_min_offset(hdr);
}
diff --git a/lib/luks2/luks2_keyslot.c b/lib/luks2/luks2_keyslot.c
index 3b8c889d..c90cb728 100644
--- a/lib/luks2/luks2_keyslot.c
+++ b/lib/luks2/luks2_keyslot.c
@@ -148,7 +148,7 @@ int LUKS2_keyslot_cipher_incompatible(struct crypt_device *cd, const char *ciphe
{
char cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
- if (!cipher_spec || !strcmp(cipher_spec, "null") || !strcmp(cipher_spec, "cipher_null"))
+ if (!cipher_spec || crypt_is_cipher_null(cipher_spec))
return 1;
if (crypt_parse_name_and_mode(cipher_spec, cipher, NULL, cipher_mode) < 0)
diff --git a/lib/luks2/luks2_reencrypt.c b/lib/luks2/luks2_reencrypt.c
index a76cb16e..ed914a27 100644
--- a/lib/luks2/luks2_reencrypt.c
+++ b/lib/luks2/luks2_reencrypt.c
@@ -2238,7 +2238,7 @@ static int reencrypt_verify_and_upload_keys(struct crypt_device *cd, struct luks
if (LUKS2_digest_verify_by_digest(cd, hdr, digest_new, vk) != digest_new)
return -EINVAL;
- if (crypt_use_keyring_for_vk(cd) &&
+ if (crypt_use_keyring_for_vk(cd) && !crypt_is_cipher_null(reencrypt_segment_cipher_new(hdr)) &&
(r = LUKS2_volume_key_load_in_keyring_by_digest(cd, hdr, vk, crypt_volume_key_get_id(vk))))
return r;
}
@@ -2254,7 +2254,7 @@ static int reencrypt_verify_and_upload_keys(struct crypt_device *cd, struct luks
r = -EINVAL;
goto err;
}
- if (crypt_use_keyring_for_vk(cd) &&
+ if (crypt_use_keyring_for_vk(cd) && !crypt_is_cipher_null(reencrypt_segment_cipher_old(hdr)) &&
(r = LUKS2_volume_key_load_in_keyring_by_digest(cd, hdr, vk, crypt_volume_key_get_id(vk))))
goto err;
}
@@ -2664,6 +2664,7 @@ static int reencrypt_load_by_passphrase(struct crypt_device *cd,
struct luks2_hdr *hdr;
struct crypt_lock_handle *reencrypt_lock;
struct luks2_reenc_context *rh;
+ const struct volume_key *vk;
struct crypt_dm_active_device dmd_target, dmd_source = {
.uuid = crypt_get_uuid(cd),
.flags = CRYPT_ACTIVATE_SHARED /* turn off exclusive open checks */
@@ -2730,6 +2731,19 @@ static int reencrypt_load_by_passphrase(struct crypt_device *cd,
goto err;
flags = dmd_target.flags;
+ /*
+ * By default reencryption code aims to retain flags from existing dm device.
+ * The keyring activation flag can not be inherited if original cipher is null.
+ *
+ * In this case override the flag based on decision made in reencrypt_verify_and_upload_keys
+ * above. The code checks if new VK is eligible for keyring.
+ */
+ vk = crypt_volume_key_by_id(*vks, LUKS2_reencrypt_digest_new(hdr));
+ if (vk && vk->key_description && crypt_is_cipher_null(reencrypt_segment_cipher_old(hdr))) {
+ flags |= CRYPT_ACTIVATE_KEYRING_KEY;
+ dmd_source.flags |= CRYPT_ACTIVATE_KEYRING_KEY;
+ }
+
r = LUKS2_assembly_multisegment_dmd(cd, hdr, *vks, LUKS2_get_segments_jobj(hdr), &dmd_source);
if (!r) {
r = crypt_compare_dm_devices(cd, &dmd_source, &dmd_target);
diff --git a/lib/luks2/luks2_token.c b/lib/luks2/luks2_token.c
index ad6722a3..101f4f59 100644
--- a/lib/luks2/luks2_token.c
+++ b/lib/luks2/luks2_token.c
@@ -329,7 +329,7 @@ static void LUKS2_token_buffer_free(struct crypt_device *cd,
{
const crypt_token_handler *h = LUKS2_token_handler(cd, token);
- if (h->buffer_free)
+ if (h && h->buffer_free)
h->buffer_free(buffer, buffer_len);
else {
crypt_safe_memzero(buffer, buffer_len);
@@ -383,6 +383,7 @@ int LUKS2_token_open_and_activate(struct crypt_device *cd,
uint32_t flags,
void *usrptr)
{
+ bool use_keyring;
int keyslot, r;
char *buffer;
size_t buffer_len;
@@ -404,7 +405,13 @@ int LUKS2_token_open_and_activate(struct crypt_device *cd,
keyslot = r;
- if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd)) {
+ if (!crypt_use_keyring_for_vk(cd))
+ use_keyring = false;
+ else
+ use_keyring = ((name && !crypt_is_cipher_null(crypt_get_cipher(cd))) ||
+ (flags & CRYPT_ACTIVATE_KEYRING_KEY));
+
+ if (use_keyring) {
if (!(r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk, keyslot)))
flags |= CRYPT_ACTIVATE_KEYRING_KEY;
}
@@ -576,16 +583,12 @@ int LUKS2_token_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
return token;
}
-int LUKS2_token_is_assigned(struct crypt_device *cd, struct luks2_hdr *hdr,
- int keyslot, int token)
+static int token_is_assigned(struct luks2_hdr *hdr, int keyslot, int token)
{
int i;
- json_object *jobj_token, *jobj_token_keyslots, *jobj;
+ json_object *jobj, *jobj_token_keyslots,
+ *jobj_token = LUKS2_get_token_jobj(hdr, token);
- if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX || token < 0 || token >= LUKS2_TOKENS_MAX)
- return -EINVAL;
-
- jobj_token = LUKS2_get_token_jobj(hdr, token);
if (!jobj_token)
return -ENOENT;
@@ -600,6 +603,15 @@ int LUKS2_token_is_assigned(struct crypt_device *cd, struct luks2_hdr *hdr,
return -ENOENT;
}
+int LUKS2_token_is_assigned(struct crypt_device *cd, struct luks2_hdr *hdr,
+ int keyslot, int token)
+{
+ if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX || token < 0 || token >= LUKS2_TOKENS_MAX)
+ return -EINVAL;
+
+ return token_is_assigned(hdr, keyslot, token);
+}
+
int LUKS2_tokens_count(struct luks2_hdr *hdr)
{
json_object *jobj_tokens = LUKS2_get_tokens_jobj(hdr);
@@ -608,3 +620,28 @@ int LUKS2_tokens_count(struct luks2_hdr *hdr)
return json_object_object_length(jobj_tokens);
}
+
+int LUKS2_token_assignment_copy(struct crypt_device *cd,
+ struct luks2_hdr *hdr,
+ int keyslot_from,
+ int keyslot_to,
+ int commit)
+{
+ int i, r;
+
+ if (keyslot_from < 0 || keyslot_from >= LUKS2_KEYSLOTS_MAX || keyslot_to < 0 || keyslot_to >= LUKS2_KEYSLOTS_MAX)
+ return -EINVAL;
+
+ r = LUKS2_tokens_count(hdr);
+ if (r <= 0)
+ return r;
+
+ for (i = 0; i < LUKS2_TOKENS_MAX; i++) {
+ if (!token_is_assigned(hdr, keyslot_from, i)) {
+ if ((r = assign_one_token(cd, hdr, keyslot_to, i, 1)))
+ return r;
+ }
+ }
+
+ return commit ? LUKS2_hdr_write(cd, hdr) : 0;
+}
diff --git a/lib/setup.c b/lib/setup.c
index d8e665c0..1e8e456f 100644
--- a/lib/setup.c
+++ b/lib/setup.c
@@ -1210,7 +1210,7 @@ static int _init_by_name_crypt(struct crypt_device *cd, const char *name)
}
/* do not try to lookup LUKS2 header in detached header mode */
- if (!cd->metadata_device && !found) {
+ if (dmd.uuid && !cd->metadata_device && !found) {
while (*dep && !found) {
r = dm_query_device(cd, *dep, DM_ACTIVE_DEVICE, &dmdep);
if (r < 0)
@@ -2035,7 +2035,7 @@ static int _crypt_format_verity(struct crypt_device *cd,
} else
cd->u.verity.hdr.data_size = params->data_size;
- if (device_is_identical(crypt_metadata_device(cd), crypt_data_device(cd)) &&
+ if (device_is_identical(crypt_metadata_device(cd), crypt_data_device(cd)) > 0 &&
(cd->u.verity.hdr.data_size * params->data_block_size) > params->hash_area_offset) {
log_err(cd, _("Data area overlaps with hash area."));
return -EINVAL;
@@ -2060,14 +2060,14 @@ static int _crypt_format_verity(struct crypt_device *cd,
}
hash_blocks_size = VERITY_hash_blocks(cd, params) * params->hash_block_size;
- if (device_is_identical(crypt_metadata_device(cd), fec_device) &&
+ if (device_is_identical(crypt_metadata_device(cd), fec_device) > 0 &&
(params->hash_area_offset + hash_blocks_size) > params->fec_area_offset) {
log_err(cd, _("Hash area overlaps with FEC area."));
r = -EINVAL;
goto err;
}
- if (device_is_identical(crypt_data_device(cd), fec_device) &&
+ if (device_is_identical(crypt_data_device(cd), fec_device) > 0 &&
(cd->u.verity.hdr.data_size * params->data_block_size) > params->fec_area_offset) {
log_err(cd, _("Data area overlaps with FEC area."));
r = -EINVAL;
@@ -2388,11 +2388,6 @@ static int _compare_crypt_devices(struct crypt_device *cd,
if (!src->u.crypt.vk || !tgt->u.crypt.vk)
return -EINVAL;
- if (_compare_volume_keys(src->u.crypt.vk, 0, tgt->u.crypt.vk, tgt->u.crypt.vk->key_description != NULL)) {
- log_dbg(cd, "Keys in context and target device do not match.");
- return -EINVAL;
- }
-
/* CIPHER checks */
if (!src->u.crypt.cipher || !tgt->u.crypt.cipher)
return -EINVAL;
@@ -2400,6 +2395,14 @@ static int _compare_crypt_devices(struct crypt_device *cd,
log_dbg(cd, "Cipher specs do not match.");
return -EINVAL;
}
+
+ if (tgt->u.crypt.vk->keylength == 0 && crypt_is_cipher_null(tgt->u.crypt.cipher))
+ log_dbg(cd, "Existing device uses cipher null. Skipping key comparison.");
+ else if (_compare_volume_keys(src->u.crypt.vk, 0, tgt->u.crypt.vk, tgt->u.crypt.vk->key_description != NULL)) {
+ log_dbg(cd, "Keys in context and target device do not match.");
+ return -EINVAL;
+ }
+
if (crypt_strcmp(src->u.crypt.integrity, tgt->u.crypt.integrity)) {
log_dbg(cd, "Integrity parameters do not match.");
return -EINVAL;
@@ -2413,7 +2416,7 @@ static int _compare_crypt_devices(struct crypt_device *cd,
return -EINVAL;
}
- if (!device_is_identical(src->data_device, tgt->data_device)) {
+ if (device_is_identical(src->data_device, tgt->data_device) <= 0) {
log_dbg(cd, "Data devices do not match.");
return -EINVAL;
}
@@ -2467,7 +2470,7 @@ static int _compare_integrity_devices(struct crypt_device *cd,
return -EINVAL;
}
- if (!device_is_identical(src->data_device, tgt->data_device)) {
+ if (device_is_identical(src->data_device, tgt->data_device) <= 0) {
log_dbg(cd, "Data devices do not match.");
return -EINVAL;
}
@@ -2770,6 +2773,11 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
if (!cd || !cd->type || !name)
return -EINVAL;
+ if (isTCRYPT(cd->type) || isBITLK(cd->type)) {
+ log_err(cd, _("This operation is not supported for this device type."));
+ return -ENOTSUP;
+ }
+
log_dbg(cd, "Resizing device %s to %" PRIu64 " sectors.", name, new_size);
r = dm_query_device(cd, name, DM_ACTIVE_CRYPT_KEYSIZE | DM_ACTIVE_CRYPT_KEY, &dmdq);
@@ -3090,6 +3098,45 @@ out:
return r;
}
+/* key must be properly verified */
+static int resume_by_volume_key(struct crypt_device *cd,
+ struct volume_key *vk,
+ const char *name)
+{
+ int digest, r;
+ struct volume_key *zerokey = NULL;
+
+ if (crypt_is_cipher_null(crypt_get_cipher_spec(cd))) {
+ zerokey = crypt_alloc_volume_key(0, NULL);
+ if (!zerokey)
+ return -ENOMEM;
+ vk = zerokey;
+ } else if (crypt_use_keyring_for_vk(cd)) {
+ /* LUKS2 path only */
+ digest = LUKS2_digest_by_segment(&cd->u.luks2.hdr, CRYPT_DEFAULT_SEGMENT);
+ if (digest < 0)
+ return -EINVAL;
+ r = LUKS2_volume_key_load_in_keyring_by_digest(cd,
+ &cd->u.luks2.hdr, vk, digest);
+ if (r < 0)
+ return r;
+ }
+
+ r = dm_resume_and_reinstate_key(cd, name, vk);
+
+ if (r == -ENOTSUP)
+ log_err(cd, _("Resume is not supported for device %s."), name);
+ else if (r)
+ log_err(cd, _("Error during resuming device %s."), name);
+
+ if (r < 0)
+ crypt_drop_keyring_key(cd, vk);
+
+ crypt_free_volume_key(zerokey);
+
+ return r;
+}
+
int crypt_resume_by_passphrase(struct crypt_device *cd,
const char *name,
int keyslot,
@@ -3125,32 +3172,13 @@ int crypt_resume_by_passphrase(struct crypt_device *cd,
r = LUKS2_keyslot_open(cd, keyslot, CRYPT_DEFAULT_SEGMENT, passphrase, passphrase_size, &vk);
if (r < 0)
- goto out;
+ return r;
keyslot = r;
- if (crypt_use_keyring_for_vk(cd)) {
- if (!isLUKS2(cd->type)) {
- r = -EINVAL;
- goto out;
- }
- r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd,
- &cd->u.luks2.hdr, vk, keyslot);
- if (r < 0)
- goto out;
- }
-
- r = dm_resume_and_reinstate_key(cd, name, vk);
+ r = resume_by_volume_key(cd, vk, name);
- if (r == -ENOTSUP)
- log_err(cd, _("Resume is not supported for device %s."), name);
- else if (r)
- log_err(cd, _("Error during resuming device %s."), name);
-out:
- if (r < 0)
- crypt_drop_keyring_key(cd, vk);
crypt_free_volume_key(vk);
-
return r < 0 ? r : keyslot;
}
@@ -3189,35 +3217,22 @@ int crypt_resume_by_keyfile_device_offset(struct crypt_device *cd,
&passphrase_read, &passphrase_size_read,
keyfile_offset, keyfile_size, 0);
if (r < 0)
- goto out;
+ return r;
if (isLUKS1(cd->type))
r = LUKS_open_key_with_hdr(keyslot, passphrase_read, passphrase_size_read,
&cd->u.luks1.hdr, &vk, cd);
else
r = LUKS2_keyslot_open(cd, keyslot, CRYPT_DEFAULT_SEGMENT, passphrase_read, passphrase_size_read, &vk);
+
+ crypt_safe_free(passphrase_read);
if (r < 0)
- goto out;
+ return r;
+
keyslot = r;
- if (crypt_use_keyring_for_vk(cd)) {
- if (!isLUKS2(cd->type)) {
- r = -EINVAL;
- goto out;
- }
- r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd,
- &cd->u.luks2.hdr, vk, keyslot);
- if (r < 0)
- goto out;
- }
+ r = resume_by_volume_key(cd, vk, name);
- r = dm_resume_and_reinstate_key(cd, name, vk);
- if (r < 0)
- log_err(cd, _("Error during resuming device %s."), name);
-out:
- crypt_safe_free(passphrase_read);
- if (r < 0)
- crypt_drop_keyring_key(cd, vk);
crypt_free_volume_key(vk);
return r < 0 ? r : keyslot;
}
@@ -3280,24 +3295,10 @@ int crypt_resume_by_volume_key(struct crypt_device *cd,
r = -EINVAL;
if (r == -EPERM || r == -ENOENT)
log_err(cd, _("Volume key does not match the volume."));
- if (r < 0)
- goto out;
- r = 0;
- if (crypt_use_keyring_for_vk(cd)) {
- r = LUKS2_key_description_by_segment(cd, &cd->u.luks2.hdr, vk, CRYPT_DEFAULT_SEGMENT);
- if (!r)
- r = crypt_volume_key_load_in_keyring(cd, vk);
- }
- if (r < 0)
- goto out;
+ if (r >= 0)
+ r = resume_by_volume_key(cd, vk, name);
- r = dm_resume_and_reinstate_key(cd, name, vk);
- if (r < 0)
- log_err(cd, _("Error during resuming device %s."), name);
-out:
- if (r < 0)
- crypt_drop_keyring_key(cd, vk);
crypt_free_volume_key(vk);
return r;
}
@@ -3459,6 +3460,9 @@ int crypt_keyslot_change_by_passphrase(struct crypt_device *cd,
r = LUKS2_digest_assign(cd, &cd->u.luks2.hdr, keyslot_new, digest, 1, 0);
if (r < 0)
goto out;
+ r = LUKS2_token_assignment_copy(cd, &cd->u.luks2.hdr, keyslot_old, keyslot_new, 0);
+ if (r < 0)
+ goto out;
} else {
log_dbg(cd, "Key slot %d is going to be overwritten.", keyslot_old);
/* FIXME: improve return code so that we can detect area is damaged */
@@ -3686,7 +3690,7 @@ static int _check_header_data_overlap(struct crypt_device *cd, const char *name)
if (!name || !isLUKS(cd->type))
return 0;
- if (!device_is_identical(crypt_data_device(cd), crypt_metadata_device(cd)))
+ if (device_is_identical(crypt_data_device(cd), crypt_metadata_device(cd)) <= 0)
return 0;
/* FIXME: check real header size */
@@ -3879,6 +3883,7 @@ static int _open_and_activate(struct crypt_device *cd,
size_t passphrase_size,
uint32_t flags)
{
+ bool use_keyring;
int r;
struct volume_key *vk = NULL;
@@ -3890,8 +3895,13 @@ static int _open_and_activate(struct crypt_device *cd,
return r;
keyslot = r;
- if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) &&
- crypt_use_keyring_for_vk(cd)) {
+ if (!crypt_use_keyring_for_vk(cd))
+ use_keyring = false;
+ else
+ use_keyring = ((name && !crypt_is_cipher_null(crypt_get_cipher(cd))) ||
+ (flags & CRYPT_ACTIVATE_KEYRING_KEY));
+
+ if (use_keyring) {
r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd,
&cd->u.luks2.hdr, vk, keyslot);
if (r < 0)
@@ -4274,6 +4284,7 @@ int crypt_activate_by_volume_key(struct crypt_device *cd,
size_t volume_key_size,
uint32_t flags)
{
+ bool use_keyring;
struct volume_key *vk = NULL;
int r;
@@ -4349,8 +4360,12 @@ int crypt_activate_by_volume_key(struct crypt_device *cd,
if (r > 0)
r = 0;
- if (!r && (name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) &&
- crypt_use_keyring_for_vk(cd)) {
+ if (!crypt_use_keyring_for_vk(cd))
+ use_keyring = false;
+ else
+ use_keyring = (name && !crypt_is_cipher_null(crypt_get_cipher(cd))) || (flags & CRYPT_ACTIVATE_KEYRING_KEY);
+
+ if (!r && use_keyring) {
r = LUKS2_key_description_by_segment(cd,
&cd->u.luks2.hdr, vk, CRYPT_DEFAULT_SEGMENT);
if (!r)
@@ -4411,7 +4426,7 @@ int crypt_activate_by_signed_key(struct crypt_device *cd,
return -EINVAL;
}
- log_dbg(cd, "%s volume %s by signed key.", name ? "Activating" : "Checking", name ?: "");
+ log_dbg(cd, "%s volume %s by %skey.", name ? "Activating" : "Checking", name ?: "", signature ? "signed " : "");
if (cd->u.verity.hdr.flags & CRYPT_VERITY_ROOT_HASH_SIGNATURE && !signature) {
log_err(cd, _("Root hash signature required."));
diff --git a/lib/utils_blkid.h b/lib/utils_blkid.h
index ca50da70..d03d4a50 100644
--- a/lib/utils_blkid.h
+++ b/lib/utils_blkid.h
@@ -21,6 +21,8 @@
#ifndef _UTILS_BLKID_H
#define _UTILS_BLKID_H
+#include <sys/types.h>
+
struct blkid_handle;
typedef enum { PRB_OK = 0, PRB_EMPTY, PRB_AMBIGUOUS, PRB_FAIL } blk_probe_status;
diff --git a/lib/utils_crypt.c b/lib/utils_crypt.c
index f09871c2..d799162b 100644
--- a/lib/utils_crypt.c
+++ b/lib/utils_crypt.c
@@ -177,3 +177,10 @@ ssize_t crypt_hex_to_bytes(const char *hex, char **result, int safe_alloc)
*result = bytes;
return i;
}
+
+bool crypt_is_cipher_null(const char *cipher_spec)
+{
+ if (!cipher_spec)
+ return false;
+ return (strstr(cipher_spec, "cipher_null") || !strcmp(cipher_spec, "null"));
+}
diff --git a/lib/utils_crypt.h b/lib/utils_crypt.h
index 32b77cb8..c5aa7068 100644
--- a/lib/utils_crypt.h
+++ b/lib/utils_crypt.h
@@ -23,6 +23,7 @@
#ifndef _UTILS_CRYPT_H
#define _UTILS_CRYPT_H
+#include <stdbool.h>
#include <unistd.h>
#define MAX_CIPHER_LEN 32
@@ -38,4 +39,6 @@ int crypt_parse_pbkdf(const char *s, const char **pbkdf);
ssize_t crypt_hex_to_bytes(const char *hex, char **result, int safe_alloc);
+bool crypt_is_cipher_null(const char *cipher_spec);
+
#endif /* _UTILS_CRYPT_H */
diff --git a/lib/utils_device.c b/lib/utils_device.c
index ddbe8362..5dda6924 100644
--- a/lib/utils_device.c
+++ b/lib/utils_device.c
@@ -300,6 +300,9 @@ static int device_open_internal(struct crypt_device *cd, struct device *device,
int device_open(struct crypt_device *cd, struct device *device, int flags)
{
+ if (!device)
+ return -EINVAL;
+
assert(!device_locked(device->lh));
return device_open_internal(cd, device, flags);
}
@@ -354,6 +357,9 @@ void device_release_excl(struct crypt_device *cd, struct device *device)
int device_open_locked(struct crypt_device *cd, struct device *device, int flags)
{
+ if (!device)
+ return -EINVAL;
+
assert(!crypt_metadata_locking_enabled() || device_locked(device->lh));
return device_open_internal(cd, device, flags);
}
@@ -528,7 +534,7 @@ void device_topology_alignment(struct crypt_device *cd,
if ((temp_alignment < (unsigned long)opt_io_size) &&
!((unsigned long)opt_io_size % temp_alignment) && !MISALIGNED_4K(opt_io_size))
temp_alignment = (unsigned long)opt_io_size;
- else if (opt_io_size)
+ else if (opt_io_size && (opt_io_size != min_io_size))
log_err(cd, _("Ignoring bogus optimal-io size for data device (%u bytes)."), opt_io_size);
/* If calculated alignment is multiple of default, keep default */
@@ -589,8 +595,11 @@ int device_size(struct device *device, uint64_t *size)
struct stat st;
int devfd, r = -EINVAL;
+ if (!device)
+ return -EINVAL;
+
devfd = open(device->path, O_RDONLY);
- if(devfd == -1)
+ if (devfd == -1)
return -EINVAL;
if (fstat(devfd, &st) < 0)
@@ -612,6 +621,9 @@ int device_fallocate(struct device *device, uint64_t size)
struct stat st;
int devfd, r = -EINVAL;
+ if (!device)
+ return -EINVAL;
+
devfd = open(device_path(device), O_RDWR);
if (devfd == -1)
return -EINVAL;
@@ -852,22 +864,30 @@ size_t size_round_up(size_t size, size_t block)
void device_disable_direct_io(struct device *device)
{
+ if (device)
device->o_direct = 0;
}
int device_direct_io(const struct device *device)
{
- return device->o_direct;
+ return device ? device->o_direct : 0;
}
-static dev_t device_devno(const struct device *device)
+static int device_compare_path(const char *path1, const char *path2)
{
- struct stat st;
+ struct stat st_path1, st_path2;
- if (stat(device->path, &st) || !S_ISBLK(st.st_mode))
- return 0;
+ if (stat(path1, &st_path1 ) < 0 || stat(path2, &st_path2 ) < 0)
+ return -EINVAL;
+
+ if (S_ISBLK(st_path1.st_mode) && S_ISBLK(st_path2.st_mode))
+ return (st_path1.st_rdev == st_path2.st_rdev) ? 1 : 0;
+
+ if (S_ISREG(st_path1.st_mode) && S_ISREG(st_path2.st_mode))
+ return (st_path1.st_ino == st_path2.st_ino &&
+ st_path1.st_dev == st_path2.st_dev) ? 1 : 0;
- return st.st_rdev;
+ return 0;
}
int device_is_identical(struct device *device1, struct device *device2)
@@ -878,21 +898,19 @@ int device_is_identical(struct device *device1, struct device *device2)
if (device1 == device2)
return 1;
- if (device1->init_done && device2->init_done)
- return (device_devno(device1) == device_devno(device2));
- else if (device1->init_done || device2->init_done)
- return 0;
-
if (!strcmp(device_path(device1), device_path(device2)))
return 1;
- return 0;
+ return device_compare_path(device_path(device1), device_path(device2));
}
int device_is_rotational(struct device *device)
{
struct stat st;
+ if (!device)
+ return -EINVAL;
+
if (stat(device_path(device), &st) < 0)
return -EINVAL;
@@ -906,6 +924,9 @@ size_t device_alignment(struct device *device)
{
int devfd;
+ if (!device)
+ return -EINVAL;
+
if (!device->alignment) {
devfd = open(device_path(device), O_RDONLY);
if (devfd != -1) {
@@ -919,17 +940,18 @@ size_t device_alignment(struct device *device)
void device_set_lock_handle(struct device *device, struct crypt_lock_handle *h)
{
+ if (device)
device->lh = h;
}
struct crypt_lock_handle *device_get_lock_handle(struct device *device)
{
- return device->lh;
+ return device ? device->lh : NULL;
}
int device_read_lock(struct crypt_device *cd, struct device *device)
{
- if (!crypt_metadata_locking_enabled())
+ if (!device || !crypt_metadata_locking_enabled())
return 0;
if (device_read_lock_internal(cd, device))
@@ -940,7 +962,7 @@ int device_read_lock(struct crypt_device *cd, struct device *device)
int device_write_lock(struct crypt_device *cd, struct device *device)
{
- if (!crypt_metadata_locking_enabled())
+ if (!device || !crypt_metadata_locking_enabled())
return 0;
assert(!device_locked(device->lh) || !device_locked_readonly(device->lh));
@@ -950,7 +972,7 @@ int device_write_lock(struct crypt_device *cd, struct device *device)
void device_read_unlock(struct crypt_device *cd, struct device *device)
{
- if (!crypt_metadata_locking_enabled())
+ if (!device || !crypt_metadata_locking_enabled())
return;
assert(device_locked(device->lh));
@@ -960,7 +982,7 @@ void device_read_unlock(struct crypt_device *cd, struct device *device)
void device_write_unlock(struct crypt_device *cd, struct device *device)
{
- if (!crypt_metadata_locking_enabled())
+ if (!device || !crypt_metadata_locking_enabled())
return;
assert(device_locked(device->lh) && !device_locked_readonly(device->lh));
diff --git a/lib/utils_device_locking.c b/lib/utils_device_locking.c
index dac8315a..c50dff8f 100644
--- a/lib/utils_device_locking.c
+++ b/lib/utils_device_locking.c
@@ -106,7 +106,7 @@ static int open_lock_dir(struct crypt_device *cd, const char *dir, const char *b
lockdfd = openat(dirfd, base, O_RDONLY | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
if (lockdfd < 0) {
if (errno == ENOENT) {
- log_std(cd, _("WARNING: Locking directory %s/%s is missing!\n"), dir, base);
+ log_dbg(cd, _("Locking directory %s/%s will be created with default compiled-in permissions."), dir, base);
/* success or failure w/ errno == EEXIST either way just try to open the 'base' directory again */
if (mkdirat(dirfd, base, DEFAULT_LUKS2_LOCK_DIR_PERMS) && errno != EEXIST)
diff --git a/lib/utils_device_locking.h b/lib/utils_device_locking.h
index 41d09349..d38b1a91 100644
--- a/lib/utils_device_locking.h
+++ b/lib/utils_device_locking.h
@@ -22,6 +22,8 @@
#ifndef _CRYPTSETUP_UTILS_LOCKING_H
#define _CRYPTSETUP_UTILS_LOCKING_H
+#include <stdbool.h>
+
struct crypt_device;
struct crypt_lock_handle;
struct device;
diff --git a/lib/utils_dm.h b/lib/utils_dm.h
index 22add180..c16541cd 100644
--- a/lib/utils_dm.h
+++ b/lib/utils_dm.h
@@ -25,7 +25,8 @@
#define _UTILS_DM_H
/* device-mapper library helpers */
-#include <inttypes.h>
+#include <stddef.h>
+#include <stdint.h>
struct crypt_device;
struct volume_key;
@@ -71,6 +72,7 @@ static inline uint32_t act2dmflags(uint32_t act_flags)
#define DM_INTEGRITY_DISCARDS_SUPPORTED (1 << 23) /* dm-integrity discards/TRIM option is supported */
#define DM_VERITY_PANIC_CORRUPTION_SUPPORTED (1 << 24) /* dm-verity panic on corruption */
#define DM_CRYPT_NO_WORKQUEUE_SUPPORTED (1 << 25) /* dm-crypt suppot for bypassing workqueues */
+#define DM_INTEGRITY_FIX_HMAC_SUPPORTED (1 << 26) /* hmac covers also superblock */
typedef enum { DM_CRYPT = 0, DM_VERITY, DM_INTEGRITY, DM_LINEAR, DM_ERROR, DM_ZERO, DM_UNKNOWN } dm_target_type;
enum tdirection { TARGET_SET = 1, TARGET_QUERY };
@@ -120,9 +122,8 @@ struct dm_target {
const char *root_hash_sig_key_desc;
uint64_t hash_offset; /* hash offset in blocks (not header) */
- uint64_t hash_blocks; /* size of hash device (in hash blocks) */
uint64_t fec_offset; /* FEC offset in blocks (not header) */
- uint64_t fec_blocks; /* size of FEC device (in hash blocks) */
+ uint64_t fec_blocks; /* FEC blocks covering data + hash + padding (foreign metadata)*/
struct crypt_params_verity *vp;
} verity;
struct {
@@ -148,6 +149,8 @@ struct dm_target {
struct device *meta_device;
bool fix_padding;
+ bool fix_hmac;
+ bool legacy_recalc;
} integrity;
struct {
uint64_t offset;
@@ -187,8 +190,8 @@ int dm_crypt_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t seg
uint32_t tag_size, uint32_t sector_size);
int dm_verity_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t seg_size,
struct device *data_device, struct device *hash_device, struct device *fec_device,
- const char *root_hash, uint32_t root_hash_size, const char *root_hash_sig_key_desc,
- uint64_t hash_offset_block, uint64_t hash_blocks, struct crypt_params_verity *vp);
+ const char *root_hash, uint32_t root_hash_size, const char* root_hash_sig_key_desc,
+ uint64_t hash_offset_block, uint64_t fec_blocks, struct crypt_params_verity *vp);
int dm_integrity_target_set(struct crypt_device *cd,
struct dm_target *tgt, uint64_t seg_offset, uint64_t seg_size,
struct device *meta_device,
diff --git a/lib/utils_safe_memory.c b/lib/utils_safe_memory.c
index 8c1fb5cb..6908ea42 100644
--- a/lib/utils_safe_memory.c
+++ b/lib/utils_safe_memory.c
@@ -66,6 +66,7 @@ void *crypt_safe_alloc(size_t size)
void crypt_safe_free(void *data)
{
struct safe_allocation *alloc;
+ volatile size_t *s;
if (!data)
return;
@@ -75,7 +76,8 @@ void crypt_safe_free(void *data)
crypt_safe_memzero(data, alloc->size);
- alloc->size = 0x55aa55aa;
+ s = (volatile size_t *)&alloc->size;
+ *s = 0x55aa55aa;
free(alloc);
}
diff --git a/lib/utils_storage_wrappers.c b/lib/utils_storage_wrappers.c
index 09d16117..e7863380 100644
--- a/lib/utils_storage_wrappers.c
+++ b/lib/utils_storage_wrappers.c
@@ -199,7 +199,7 @@ int crypt_storage_wrapper_init(struct crypt_device *cd,
goto err;
}
- if (!strcmp(_cipher, "cipher_null")) {
+ if (crypt_is_cipher_null(_cipher)) {
log_dbg(cd, "Requested cipher_null, switching to noop wrapper.");
w->type = NONE;
*cw = w;
diff --git a/lib/utils_storage_wrappers.h b/lib/utils_storage_wrappers.h
index f360955b..2519c0af 100644
--- a/lib/utils_storage_wrappers.h
+++ b/lib/utils_storage_wrappers.h
@@ -22,6 +22,9 @@
#ifndef _UTILS_STORAGE_WRAPPERS_H
#define _UTILS_STORAGE_WRAPPERS_H
+#include <stdint.h>
+#include <sys/types.h>
+
struct crypt_storage_wrapper;
struct device;
struct volume_key;
diff --git a/lib/verity/verity.c b/lib/verity/verity.c
index af31784d..d60af253 100644
--- a/lib/verity/verity.c
+++ b/lib/verity/verity.c
@@ -23,6 +23,7 @@
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
+#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netinet/in.h>
@@ -145,6 +146,13 @@ int VERITY_read_sb(struct crypt_device *cd,
return 0;
}
+static void _to_lower(char *str)
+{
+ for(; *str; str++)
+ if (isupper(*str))
+ *str = tolower(*str);
+}
+
/* Write verity superblock to disk */
int VERITY_write_sb(struct crypt_device *cd,
uint64_t sb_offset,
@@ -154,6 +162,7 @@ int VERITY_write_sb(struct crypt_device *cd,
struct device *device = crypt_metadata_device(cd);
struct verity_sb sb = {};
ssize_t hdr_size = sizeof(struct verity_sb);
+ size_t block_size;
char *algorithm;
uuid_t uuid;
int r, devfd;
@@ -173,6 +182,13 @@ int VERITY_write_sb(struct crypt_device *cd,
return -EINVAL;
}
+ /* Avoid possible increasing of image size - FEC could fail later because of it */
+ block_size = device_block_size(cd, device);
+ if (block_size > params->hash_block_size) {
+ device_disable_direct_io(device);
+ block_size = params->hash_block_size;
+ }
+
devfd = device_open(cd, device, O_RDWR);
if (devfd < 0) {
log_err(cd, _("Cannot open device %s."), device_path(device));
@@ -186,13 +202,17 @@ int VERITY_write_sb(struct crypt_device *cd,
sb.hash_block_size = cpu_to_le32(params->hash_block_size);
sb.salt_size = cpu_to_le16(params->salt_size);
sb.data_blocks = cpu_to_le64(params->data_size);
+
+ /* Kernel always use lower-case */
algorithm = (char *)sb.algorithm;
- algorithm[sizeof(sb.algorithm)-1] = '\0';
strncpy(algorithm, params->hash_name, sizeof(sb.algorithm)-1);
+ algorithm[sizeof(sb.algorithm)-1] = '\0';
+ _to_lower(algorithm);
+
memcpy(sb.salt, params->salt, params->salt_size);
memcpy(sb.uuid, uuid, sizeof(sb.uuid));
- r = write_lseek_blockwise(devfd, device_block_size(cd, device), device_alignment(device),
+ r = write_lseek_blockwise(devfd, block_size, device_alignment(device),
(char*)&sb, hdr_size, sb_offset) < hdr_size ? -EIO : 0;
if (r)
log_err(cd, _("Error during update of verity header on device %s."),
@@ -241,7 +261,7 @@ int VERITY_activate(struct crypt_device *cd,
{
uint32_t dmv_flags;
unsigned int fec_errors = 0;
- int r;
+ int r, v;
struct crypt_dm_active_device dmd = {
.size = verity_hdr->data_size * verity_hdr->data_block_size / 512,
.flags = activation_flags,
@@ -260,14 +280,19 @@ int VERITY_activate(struct crypt_device *cd,
log_dbg(cd, "Verification of data in userspace required.");
r = VERITY_verify(cd, verity_hdr, root_hash, root_hash_size);
- if (r == -EPERM && fec_device) {
+ if ((r == -EPERM || r == -EFAULT) && fec_device) {
+ v = r;
log_dbg(cd, "Verification failed, trying to repair with FEC device.");
r = VERITY_FEC_process(cd, verity_hdr, fec_device, 1, &fec_errors);
if (r < 0)
log_err(cd, _("Errors cannot be repaired with FEC device."));
- else if (fec_errors)
+ else if (fec_errors) {
log_err(cd, _("Found %u repairable errors with FEC device."),
fec_errors);
+ /* If root hash failed, we cannot be sure it was properly repaired */
+ }
+ if (v == -EFAULT)
+ r = -EPERM;
}
if (r < 0)
@@ -298,7 +323,7 @@ int VERITY_activate(struct crypt_device *cd,
crypt_metadata_device(cd), fec_device, root_hash,
root_hash_size, signature_description,
VERITY_hash_offset_block(verity_hdr),
- VERITY_hash_blocks(cd, verity_hdr), verity_hdr);
+ VERITY_FEC_blocks(cd, fec_device, verity_hdr), verity_hdr);
if (r)
return r;
diff --git a/lib/verity/verity.h b/lib/verity/verity.h
index 0b7f0cca..f189f460 100644
--- a/lib/verity/verity.h
+++ b/lib/verity/verity.h
@@ -71,6 +71,10 @@ uint64_t VERITY_hash_offset_block(struct crypt_params_verity *params);
uint64_t VERITY_hash_blocks(struct crypt_device *cd, struct crypt_params_verity *params);
+uint64_t VERITY_FEC_blocks(struct crypt_device *cd,
+ struct device *fec_device,
+ struct crypt_params_verity *params);
+
int VERITY_UUID_generate(struct crypt_device *cd, char **uuid_string);
#endif
diff --git a/lib/verity/verity_fec.c b/lib/verity/verity_fec.c
index a8a5e86f..5fd82d94 100644
--- a/lib/verity/verity_fec.c
+++ b/lib/verity/verity_fec.c
@@ -134,8 +134,11 @@ static int FEC_process_inputs(struct crypt_device *cd,
/* calculate the total area covered by error correction codes */
ctx.size = 0;
- for (n = 0; n < ctx.ninputs; ++n)
+ for (n = 0; n < ctx.ninputs; ++n) {
+ log_dbg(cd, "FEC input %s, offset %" PRIu64 " [bytes], length %" PRIu64 " [bytes]",
+ device_path(ctx.inputs[n].device), ctx.inputs[n].start, ctx.inputs[n].count);
ctx.size += ctx.inputs[n].count;
+ }
/* each byte in a data block is covered by a different code */
ctx.blocks = FEC_div_round_up(ctx.size, ctx.block_size);
@@ -203,8 +206,8 @@ int VERITY_FEC_process(struct crypt_device *cd,
struct device *fec_device, int check_fec,
unsigned int *errors)
{
- int r;
- int fd = -1;
+ int r = -EIO, fd = -1;
+ size_t ninputs = FEC_INPUT_DEVICES;
struct fec_input_device inputs[FEC_INPUT_DEVICES] = {
{
.device = crypt_data_device(cd),
@@ -214,7 +217,8 @@ int VERITY_FEC_process(struct crypt_device *cd,
},{
.device = crypt_metadata_device(cd),
.fd = -1,
- .start = VERITY_hash_offset_block(params) * params->data_block_size
+ .start = VERITY_hash_offset_block(params) * params->data_block_size,
+ .count = (VERITY_FEC_blocks(cd, fec_device, params) - params->data_size) * params->data_block_size
}
};
@@ -230,7 +234,12 @@ int VERITY_FEC_process(struct crypt_device *cd,
return -EINVAL;
}
- r = -EIO;
+ if (!inputs[0].count) {
+ log_err(cd, _("Invalid FEC segment length."));
+ return -EINVAL;
+ }
+ if (!inputs[1].count)
+ ninputs--;
if (check_fec)
fd = open(device_path(fec_device), O_RDONLY);
@@ -259,16 +268,7 @@ int VERITY_FEC_process(struct crypt_device *cd,
goto out;
}
- /* cover the entire hash device starting from hash_offset */
- r = device_size(inputs[1].device, &inputs[1].count);
- if (r) {
- log_err(cd, _("Failed to determine size for device %s."),
- device_path(inputs[1].device));
- goto out;
- }
- inputs[1].count -= inputs[1].start;
-
- r = FEC_process_inputs(cd, params, inputs, FEC_INPUT_DEVICES, fd, check_fec, errors);
+ r = FEC_process_inputs(cd, params, inputs, ninputs, fd, check_fec, errors);
out:
if (inputs[0].fd != -1)
close(inputs[0].fd);
@@ -279,3 +279,38 @@ out:
return r;
}
+
+uint64_t VERITY_FEC_blocks(struct crypt_device *cd,
+ struct device *fec_device,
+ struct crypt_params_verity *params)
+{
+ uint64_t blocks = 0;
+
+ /*
+ * FEC covers this data:
+ * | protected data | hash area | padding (optional foreign metadata) |
+ *
+ * If hash device is in a separate image, metadata covers the whole rest of the image after hash area.
+ * If hash and FEC device is in the image, metadata ends on the FEC area offset.
+ */
+ if (device_is_identical(crypt_metadata_device(cd), fec_device) > 0) {
+ log_dbg(cd, "FEC and hash device is the same.");
+ blocks = params->fec_area_offset;
+ } else {
+ /* cover the entire hash device starting from hash_offset */
+ if (device_size(crypt_metadata_device(cd), &blocks)) {
+ log_err(cd, _("Failed to determine size for device %s."),
+ device_path(crypt_metadata_device(cd)));
+ return 0;
+ }
+ }
+
+ blocks /= params->data_block_size;
+ if (blocks)
+ blocks -= VERITY_hash_offset_block(params);
+
+ /* Protected data */
+ blocks += params->data_size;
+
+ return blocks;
+}
diff --git a/lib/verity/verity_hash.c b/lib/verity/verity_hash.c
index 61424300..e6bc977f 100644
--- a/lib/verity/verity_hash.c
+++ b/lib/verity/verity_hash.c
@@ -89,20 +89,12 @@ out:
return r;
}
-static int mult_overflow(off_t *u, off_t b, size_t size)
-{
- *u = (uint64_t)b * size;
- if ((off_t)(*u / size) != b || (off_t)*u < 0)
- return 1;
- return 0;
-}
-
static int hash_levels(size_t hash_block_size, size_t digest_size,
- off_t data_file_blocks, off_t *hash_position, int *levels,
- off_t *hash_level_block, off_t *hash_level_size)
+ uint64_t data_file_blocks, uint64_t *hash_position, int *levels,
+ uint64_t *hash_level_block, uint64_t *hash_level_size)
{
size_t hash_per_block_bits;
- off_t s, s_shift;
+ uint64_t s, s_shift;
int i;
if (!digest_size)
@@ -127,11 +119,10 @@ static int hash_levels(size_t hash_block_size, size_t digest_size,
s_shift = (i + 1) * hash_per_block_bits;
if (s_shift > 63)
return -EINVAL;
- s = (data_file_blocks + ((off_t)1 << s_shift) - 1) >> ((i + 1) * hash_per_block_bits);
+ s = (data_file_blocks + ((uint64_t)1 << s_shift) - 1) >> ((i + 1) * hash_per_block_bits);
if (hash_level_size)
hash_level_size[i] = s;
- if ((*hash_position + s) < *hash_position ||
- (*hash_position + s) < 0)
+ if ((*hash_position + s) < *hash_position)
return -EINVAL;
*hash_position += s;
}
@@ -140,9 +131,9 @@ static int hash_levels(size_t hash_block_size, size_t digest_size,
}
static int create_or_verify(struct crypt_device *cd, FILE *rd, FILE *wr,
- off_t data_block, size_t data_block_size,
- off_t hash_block, size_t hash_block_size,
- off_t blocks, int version,
+ uint64_t data_block, size_t data_block_size,
+ uint64_t hash_block, size_t hash_block_size,
+ uint64_t blocks, int version,
const char *hash_name, int verify,
char *calculated_digest, size_t digest_size,
const char *salt, size_t salt_size)
@@ -152,14 +143,14 @@ static int create_or_verify(struct crypt_device *cd, FILE *rd, FILE *wr,
char read_digest[digest_size];
size_t hash_per_block = 1 << get_bits_down(hash_block_size / digest_size);
size_t digest_size_full = 1 << get_bits_up(digest_size);
- off_t blocks_to_write = (blocks + hash_per_block - 1) / hash_per_block;
- off_t seek_rd, seek_wr;
+ uint64_t blocks_to_write = (blocks + hash_per_block - 1) / hash_per_block;
+ uint64_t seek_rd, seek_wr;
size_t left_bytes;
unsigned i;
int r;
- if (mult_overflow(&seek_rd, data_block, data_block_size) ||
- mult_overflow(&seek_wr, hash_block, hash_block_size)) {
+ if (uint64_mult_overflow(&seek_rd, data_block, data_block_size) ||
+ uint64_mult_overflow(&seek_wr, hash_block, hash_block_size)) {
log_err(cd, _("Device offset overflow."));
return -EINVAL;
}
@@ -241,86 +232,68 @@ static int create_or_verify(struct crypt_device *cd, FILE *rd, FILE *wr,
return 0;
}
-static int VERITY_create_or_verify_hash(struct crypt_device *cd,
- int verify,
- int version,
- const char *hash_name,
- struct device *hash_device,
- struct device *data_device,
- size_t hash_block_size,
- size_t data_block_size,
- off_t data_blocks,
- off_t hash_position,
- char *root_hash,
- size_t digest_size,
- const char *salt,
- size_t salt_size)
+static int VERITY_create_or_verify_hash(struct crypt_device *cd, bool verify,
+ struct crypt_params_verity *params,
+ char *root_hash, size_t digest_size)
{
char calculated_digest[digest_size];
FILE *data_file = NULL;
FILE *hash_file = NULL, *hash_file_2;
- off_t hash_level_block[VERITY_MAX_LEVELS];
- off_t hash_level_size[VERITY_MAX_LEVELS];
- off_t data_file_blocks;
- off_t data_device_size = 0, hash_device_size = 0;
+ uint64_t hash_level_block[VERITY_MAX_LEVELS];
+ uint64_t hash_level_size[VERITY_MAX_LEVELS];
+ uint64_t data_file_blocks;
+ uint64_t data_device_offset_max = 0, hash_device_offset_max = 0;
+ uint64_t hash_position = VERITY_hash_offset_block(params);
uint64_t dev_size;
int levels, i, r;
log_dbg(cd, "Hash %s %s, data device %s, data blocks %" PRIu64
", hash_device %s, offset %" PRIu64 ".",
- verify ? "verification" : "creation", hash_name,
- device_path(data_device), data_blocks,
- device_path(hash_device), hash_position);
-
- if (data_blocks < 0 || hash_position < 0) {
- log_err(cd, _("Invalid size parameters for verity device."));
- return -EINVAL;
- }
+ verify ? "verification" : "creation", params->hash_name,
+ device_path(crypt_data_device(cd)), params->data_size,
+ device_path(crypt_metadata_device(cd)), hash_position);
- if (!data_blocks) {
- r = device_size(data_device, &dev_size);
+ if (!params->data_size) {
+ r = device_size(crypt_data_device(cd), &dev_size);
if (r < 0)
return r;
- data_file_blocks = dev_size / data_block_size;
+ data_file_blocks = dev_size / params->data_block_size;
} else
- data_file_blocks = data_blocks;
+ data_file_blocks = params->data_size;
- if (mult_overflow(&data_device_size, data_blocks, data_block_size)) {
+ if (uint64_mult_overflow(&data_device_offset_max, params->data_size, params->data_block_size)) {
log_err(cd, _("Device offset overflow."));
return -EINVAL;
}
+ log_dbg(cd, "Data device size required: %" PRIu64 " bytes.", data_device_offset_max);
- if (hash_levels(hash_block_size, digest_size, data_file_blocks, &hash_position,
+ if (hash_levels(params->hash_block_size, digest_size, data_file_blocks, &hash_position,
&levels, &hash_level_block[0], &hash_level_size[0])) {
log_err(cd, _("Hash area overflow."));
return -EINVAL;
}
-
- log_dbg(cd, "Using %d hash levels.", levels);
-
- if (mult_overflow(&hash_device_size, hash_position, hash_block_size)) {
+ if (uint64_mult_overflow(&hash_device_offset_max, hash_position, params->hash_block_size)) {
log_err(cd, _("Device offset overflow."));
return -EINVAL;
}
+ log_dbg(cd, "Hash device size required: %" PRIu64 " bytes.",
+ hash_device_offset_max - params->hash_area_offset);
+ log_dbg(cd, "Using %d hash levels.", levels);
- log_dbg(cd, "Data device size required: %" PRIu64 " bytes.",
- data_device_size);
- data_file = fopen(device_path(data_device), "r");
+ data_file = fopen(device_path(crypt_data_device(cd)), "r");
if (!data_file) {
log_err(cd, _("Cannot open device %s."),
- device_path(data_device)
+ device_path(crypt_data_device(cd))
);
r = -EIO;
goto out;
}
- log_dbg(cd, "Hash device size required: %" PRIu64 " bytes.",
- hash_device_size);
- hash_file = fopen(device_path(hash_device), verify ? "r" : "r+");
+ hash_file = fopen(device_path(crypt_metadata_device(cd)), verify ? "r" : "r+");
if (!hash_file) {
log_err(cd, _("Cannot open device %s."),
- device_path(hash_device));
+ device_path(crypt_metadata_device(cd)));
r = -EIO;
goto out;
}
@@ -330,25 +303,25 @@ static int VERITY_create_or_verify_hash(struct crypt_device *cd,
for (i = 0; i < levels; i++) {
if (!i) {
r = create_or_verify(cd, data_file, hash_file,
- 0, data_block_size,
- hash_level_block[i], hash_block_size,
- data_file_blocks, version, hash_name, verify,
- calculated_digest, digest_size, salt, salt_size);
+ 0, params->data_block_size,
+ hash_level_block[i], params->hash_block_size,
+ data_file_blocks, params->hash_type, params->hash_name, verify,
+ calculated_digest, digest_size, params->salt, params->salt_size);
if (r)
goto out;
} else {
- hash_file_2 = fopen(device_path(hash_device), "r");
+ hash_file_2 = fopen(device_path(crypt_metadata_device(cd)), "r");
if (!hash_file_2) {
log_err(cd, _("Cannot open device %s."),
- device_path(hash_device));
+ device_path(crypt_metadata_device(cd)));
r = -EIO;
goto out;
}
r = create_or_verify(cd, hash_file_2, hash_file,
- hash_level_block[i - 1], hash_block_size,
- hash_level_block[i], hash_block_size,
- hash_level_size[i - 1], version, hash_name, verify,
- calculated_digest, digest_size, salt, salt_size);
+ hash_level_block[i - 1], params->hash_block_size,
+ hash_level_block[i], params->hash_block_size,
+ hash_level_size[i - 1], params->hash_type, params->hash_name, verify,
+ calculated_digest, digest_size, params->salt, params->salt_size);
fclose(hash_file_2);
if (r)
goto out;
@@ -357,23 +330,23 @@ static int VERITY_create_or_verify_hash(struct crypt_device *cd,
if (levels)
r = create_or_verify(cd, hash_file, NULL,
- hash_level_block[levels - 1], hash_block_size,
- 0, hash_block_size,
- 1, version, hash_name, verify,
- calculated_digest, digest_size, salt, salt_size);
+ hash_level_block[levels - 1], params->hash_block_size,
+ 0, params->hash_block_size,
+ 1, params->hash_type, params->hash_name, verify,
+ calculated_digest, digest_size, params->salt, params->salt_size);
else
r = create_or_verify(cd, data_file, NULL,
- 0, data_block_size,
- 0, hash_block_size,
- data_file_blocks, version, hash_name, verify,
- calculated_digest, digest_size, salt, salt_size);
+ 0, params->data_block_size,
+ 0, params->hash_block_size,
+ data_file_blocks, params->hash_type, params->hash_name, verify,
+ calculated_digest, digest_size, params->salt, params->salt_size);
out:
if (verify) {
if (r)
log_err(cd, _("Verification of data area failed."));
else {
log_dbg(cd, "Verification of data area succeeded.");
- r = memcmp(root_hash, calculated_digest, digest_size) ? -EPERM : 0;
+ r = memcmp(root_hash, calculated_digest, digest_size) ? -EFAULT : 0;
if (r)
log_err(cd, _("Verification of root hash failed."));
else
@@ -403,19 +376,7 @@ int VERITY_verify(struct crypt_device *cd,
const char *root_hash,
size_t root_hash_size)
{
- return VERITY_create_or_verify_hash(cd, 1,
- verity_hdr->hash_type,
- verity_hdr->hash_name,
- crypt_metadata_device(cd),
- crypt_data_device(cd),
- verity_hdr->hash_block_size,
- verity_hdr->data_block_size,
- verity_hdr->data_size,
- VERITY_hash_offset_block(verity_hdr),
- CONST_CAST(char*)root_hash,
- root_hash_size,
- verity_hdr->salt,
- verity_hdr->salt_size);
+ return VERITY_create_or_verify_hash(cd, 1, verity_hdr, CONST_CAST(char*)root_hash, root_hash_size);
}
/* Create verity hash */
@@ -433,24 +394,12 @@ int VERITY_create(struct crypt_device *cd,
log_err(cd, _("WARNING: Kernel cannot activate device if data "
"block size exceeds page size (%u)."), pgsize);
- return VERITY_create_or_verify_hash(cd, 0,
- verity_hdr->hash_type,
- verity_hdr->hash_name,
- crypt_metadata_device(cd),
- crypt_data_device(cd),
- verity_hdr->hash_block_size,
- verity_hdr->data_block_size,
- verity_hdr->data_size,
- VERITY_hash_offset_block(verity_hdr),
- CONST_CAST(char*)root_hash,
- root_hash_size,
- verity_hdr->salt,
- verity_hdr->salt_size);
+ return VERITY_create_or_verify_hash(cd, 0, verity_hdr, CONST_CAST(char*)root_hash, root_hash_size);
}
uint64_t VERITY_hash_blocks(struct crypt_device *cd, struct crypt_params_verity *params)
{
- off_t hash_position = 0;
+ uint64_t hash_position = 0;
int levels = 0;
if (hash_levels(params->hash_block_size, crypt_get_volume_key_size(cd),
diff --git a/src/cryptsetup.c b/src/cryptsetup.c
index b32f167d..70e1f390 100644
--- a/src/cryptsetup.c
+++ b/src/cryptsetup.c
@@ -24,22 +24,43 @@
#include "cryptsetup.h"
#include <uuid/uuid.h>
-static const char *opt_cipher = NULL;
-static const char *opt_keyslot_cipher = NULL;
-static const char *opt_hash = NULL;
-static int opt_verify_passphrase = 0;
+static char *opt_cipher = NULL;
+static char *opt_keyslot_cipher = NULL;
+static char *opt_hash = NULL;
+static char *opt_json_file = NULL;
+static char *opt_key_file = NULL;
+static char *opt_keyfile_stdin = NULL;
+static char *opt_keyfiles[MAX_KEYFILES];
+static char *opt_master_key_file = NULL;
+static char *opt_header_backup_file = NULL;
+static char *opt_uuid = NULL;
+static char *opt_header_device = NULL;
+static char *opt_type = NULL;
+static char *opt_pbkdf = NULL;
+static char *opt_priority = NULL; /* normal */
+static char *opt_integrity = NULL; /* none */
+static char *opt_key_description = NULL;
+static char *opt_label = NULL;
+static char *opt_subsystem = NULL;
+static char *opt_active_name = NULL;
+static char *opt_resilience_mode = NULL; /* default value "checksum" */
+static char *opt_resilience_hash = NULL; /* default value "sha256" */
+
+/* helper strings converted to uint64_t later */
+static char *opt_reduce_size_str = NULL;
+static char *opt_hotzone_size_str = NULL;
+static char *opt_device_size_str = NULL;
+static char *opt_luks2_metadata_size_str = NULL;
+static char *opt_luks2_keyslots_size_str = NULL;
-static const char *opt_json_file = NULL;
-static const char *opt_key_file = NULL;
-static const char *opt_keyfile_stdin = NULL;
-static int opt_keyfiles_count = 0;
-static const char *opt_keyfiles[MAX_KEYFILES];
+static uint64_t opt_reduce_size = 0;
+static uint64_t opt_hotzone_size = 0;
+static uint64_t opt_device_size = 0;
+static uint64_t opt_luks2_metadata_size = 0;
+static uint64_t opt_luks2_keyslots_size = 0;
-static const char *opt_master_key_file = NULL;
-static const char *opt_header_backup_file = NULL;
-static const char *opt_uuid = NULL;
-static const char *opt_header_device = NULL;
-static const char *opt_type = "luks";
+static int opt_keyfiles_count = 0;
+static int opt_verify_passphrase = 0;
static int opt_key_size = 0;
static int opt_keyslot_key_size = 0;
static long opt_keyfile_size = 0;
@@ -76,57 +97,68 @@ static int opt_veracrypt_query_pim = 0;
static int opt_deferred_remove = 0;
static int opt_serialize_memory_hard_pbkdf = 0;
//FIXME: check uint32 overflow for long type
-static const char *opt_pbkdf = NULL;
static long opt_pbkdf_memory = DEFAULT_LUKS2_MEMORY_KB;
static long opt_pbkdf_parallel = DEFAULT_LUKS2_PARALLEL_THREADS;
static long opt_pbkdf_iterations = 0;
static int opt_iteration_time = 0;
static int opt_disable_locks = 0;
static int opt_disable_keyring = 0;
-static const char *opt_priority = NULL; /* normal */
-static const char *opt_integrity = NULL; /* none */
static int opt_integrity_nojournal = 0;
static int opt_integrity_no_wipe = 0;
static int opt_integrity_legacy_padding = 0;
-static const char *opt_key_description = NULL;
static int opt_sector_size = 0;
static int opt_iv_large_sectors = 0;
static int opt_persistent = 0;
-static const char *opt_label = NULL;
-static const char *opt_subsystem = NULL;
static int opt_unbound = 0;
static int opt_refresh = 0;
/* LUKS2 reencryption parameters */
-static const char *opt_active_name = NULL;
-static const char *opt_resilience_mode = "checksum"; // TODO: default resilience
-static const char *opt_resilience_hash = "sha256"; // TODO: default checksum hash
static int opt_encrypt = 0;
static int opt_reencrypt_init_only = 0;
static int opt_reencrypt_resume_only = 0;
static int opt_decrypt = 0;
-static const char *opt_reduce_size_str = NULL;
-static uint64_t opt_reduce_size = 0;
-
-static const char *opt_hotzone_size_str = NULL;
-static uint64_t opt_hotzone_size = 0;
-
-static const char *opt_device_size_str = NULL;
-static uint64_t opt_device_size = 0;
-
/* do not set from command line, use helpers above */
static int64_t opt_data_shift;
-
-static const char *opt_luks2_metadata_size_str = NULL;
-static uint64_t opt_luks2_metadata_size = 0;
-static const char *opt_luks2_keyslots_size_str = NULL;
-static uint64_t opt_luks2_keyslots_size = 0;
+static const char *device_type = "luks";
+static const char *set_pbkdf = NULL;
static const char **action_argv;
static int action_argc;
static const char *null_action_argv[] = {NULL, NULL};
+void tools_cleanup(void)
+{
+ FREE_AND_NULL(opt_cipher);
+ FREE_AND_NULL(opt_keyslot_cipher);
+ FREE_AND_NULL(opt_hash);
+ FREE_AND_NULL(opt_json_file);
+ FREE_AND_NULL(opt_key_file);
+ FREE_AND_NULL(opt_keyfile_stdin);
+ FREE_AND_NULL(opt_master_key_file);
+ FREE_AND_NULL(opt_header_backup_file);
+ FREE_AND_NULL(opt_uuid);
+ FREE_AND_NULL(opt_header_device);
+ FREE_AND_NULL(opt_type);
+ FREE_AND_NULL(opt_pbkdf);
+ FREE_AND_NULL(opt_priority);
+ FREE_AND_NULL(opt_integrity);
+ FREE_AND_NULL(opt_key_description);
+ FREE_AND_NULL(opt_label);
+ FREE_AND_NULL(opt_subsystem);
+ FREE_AND_NULL(opt_active_name);
+ FREE_AND_NULL(opt_resilience_mode);
+ FREE_AND_NULL(opt_resilience_hash);
+ FREE_AND_NULL(opt_reduce_size_str);
+ FREE_AND_NULL(opt_hotzone_size_str);
+ FREE_AND_NULL(opt_device_size_str);
+ FREE_AND_NULL(opt_luks2_metadata_size_str);
+ FREE_AND_NULL(opt_luks2_keyslots_size_str);
+
+ while (opt_keyfiles_count)
+ free(opt_keyfiles[--opt_keyfiles_count]);
+}
+
static const char *uuid_or_device_header(const char **data_device)
{
if (data_device)
@@ -440,7 +472,7 @@ static int tcrypt_load(struct crypt_device *cd, struct crypt_params_tcrypt *para
unsigned long long tmp_pim_ull = 0;
r = tools_get_key(_("Enter VeraCrypt PIM: "),
- CONST_CAST(char**)&tmp_pim_nptr,
+ &tmp_pim_nptr,
&tmp_pim_size, 0, 0, opt_keyfile_stdin, opt_timeout,
_verify_passphrase(0), 0, cd);
if (r < 0)
@@ -457,7 +489,7 @@ static int tcrypt_load(struct crypt_device *cd, struct crypt_params_tcrypt *para
log_err(_("Invalid PIM value: outside of range."));
r = -ERANGE;
}
- crypt_safe_free(CONST_CAST(char*)tmp_pim_nptr);
+ crypt_safe_free(tmp_pim_nptr);
if (r < 0)
continue;
@@ -500,7 +532,7 @@ static int action_open_tcrypt(void)
{
struct crypt_device *cd = NULL;
struct crypt_params_tcrypt params = {
- .keyfiles = opt_keyfiles,
+ .keyfiles = CONST_CAST(const char **)opt_keyfiles,
.keyfiles_count = opt_keyfiles_count,
.flags = CRYPT_TCRYPT_LEGACY_MODES |
(opt_veracrypt ? CRYPT_TCRYPT_VERA_MODES : 0),
@@ -618,7 +650,7 @@ static int action_tcryptDump(void)
{
struct crypt_device *cd = NULL;
struct crypt_params_tcrypt params = {
- .keyfiles = opt_keyfiles,
+ .keyfiles = CONST_CAST(const char **)opt_keyfiles,
.keyfiles_count = opt_keyfiles_count,
.flags = CRYPT_TCRYPT_LEGACY_MODES |
(opt_veracrypt ? CRYPT_TCRYPT_VERA_MODES : 0),
@@ -715,7 +747,9 @@ static int action_resize(void)
r = crypt_activate_by_token(cd, NULL, opt_token, NULL,
CRYPT_ACTIVATE_KEYRING_KEY);
tools_keyslot_msg(r, UNLOCKED);
- if (r < 0 && opt_token_only)
+ if (r >= 0)
+ goto resize;
+ else if (opt_token_only)
goto out;
r = tools_get_key(NULL, &password, &passwordLen,
@@ -731,7 +765,7 @@ static int action_resize(void)
tools_keyslot_msg(r, UNLOCKED);
crypt_safe_free(password);
}
-
+resize:
if (opt_device_size)
opt_size = opt_device_size / SECTOR_SIZE;
@@ -961,10 +995,10 @@ static int action_benchmark(void)
int i, r;
log_std(_("# Tests are approximate using memory only (no storage IO).\n"));
- if (opt_pbkdf || opt_hash) {
- if (!opt_pbkdf && opt_hash)
- opt_pbkdf = CRYPT_KDF_PBKDF2;
- r = action_benchmark_kdf(opt_pbkdf, opt_hash, key_size);
+ if (set_pbkdf || opt_hash) {
+ if (!set_pbkdf && opt_hash)
+ set_pbkdf = CRYPT_KDF_PBKDF2;
+ r = action_benchmark_kdf(set_pbkdf, opt_hash, key_size);
} else if (opt_cipher) {
r = crypt_parse_name_and_mode(opt_cipher, cipher, NULL, cipher_mode);
if (r < 0) {
@@ -1036,7 +1070,7 @@ static int set_pbkdf_params(struct crypt_device *cd, const char *dev_type)
if (!pbkdf_default)
return -EINVAL;
- pbkdf.type = opt_pbkdf ?: pbkdf_default->type;
+ pbkdf.type = set_pbkdf ?: pbkdf_default->type;
pbkdf.hash = opt_hash ?: pbkdf_default->hash;
pbkdf.time_ms = (uint32_t)opt_iteration_time ?: pbkdf_default->time_ms;
if (strcmp(pbkdf.type, CRYPT_KDF_PBKDF2)) {
@@ -1063,11 +1097,17 @@ static int set_keyslot_params(struct crypt_device *cd, int keyslot)
if (!cipher)
return -EINVAL;
+ if (crypt_is_cipher_null(cipher)) {
+ log_dbg("Keyslot %d uses cipher_null. Replacing with default encryption in new keyslot.", keyslot);
+ cipher = DEFAULT_LUKS2_KEYSLOT_CIPHER;
+ key_size = DEFAULT_LUKS2_KEYSLOT_KEYBITS / 8;
+ }
+
if (crypt_keyslot_set_encryption(cd, cipher, key_size))
return -EINVAL;
/* if requested any of those just reinitialize context pbkdf */
- if (opt_pbkdf || opt_hash || opt_pbkdf_iterations || opt_iteration_time)
+ if (set_pbkdf || opt_hash || opt_pbkdf_iterations || opt_iteration_time)
return set_pbkdf_params(cd, CRYPT_LUKS2);
if (crypt_keyslot_get_pbkdf(cd, keyslot, &pbkdf))
@@ -1139,7 +1179,7 @@ static int action_luksRepair(void)
goto out;
crypt_set_log_callback(cd, quiet_log, NULL);
- r = crypt_load(cd, luksType(opt_type), NULL);
+ r = crypt_load(cd, luksType(device_type), NULL);
crypt_set_log_callback(cd, tool_log, NULL);
if (r == 0) {
log_verbose(_("No known problems detected for LUKS header."));
@@ -1153,7 +1193,7 @@ static int action_luksRepair(void)
r = yesDialog(_("Really try to repair LUKS device header?"),
_("Operation aborted.\n")) ? 0 : -EINVAL;
if (r == 0)
- r = crypt_repair(cd, luksType(opt_type), NULL);
+ r = crypt_repair(cd, luksType(device_type), NULL);
skip_repair:
if (!r && crypt_get_type(cd) && !strcmp(crypt_get_type(cd), CRYPT_LUKS2))
r = _do_luks2_reencrypt_recovery(cd);
@@ -1202,6 +1242,21 @@ static int strcmp_or_null(const char *str, const char *expected)
return !str ? 0 : strcmp(str, expected);
}
+static int get_adjusted_key_size(const char *cipher_mode, uint32_t default_size_bits, int integrity_keysize)
+{
+ uint32_t keysize_bits = opt_key_size;
+
+#ifdef ENABLE_LUKS_ADJUST_XTS_KEYSIZE
+ if (!opt_key_size && !strncmp(cipher_mode, "xts-", 4)) {
+ if (default_size_bits == 128)
+ keysize_bits = 256;
+ else if (default_size_bits == 256)
+ keysize_bits = 512;
+ }
+#endif
+ return (keysize_bits ?: default_size_bits) / 8 + integrity_keysize;
+}
+
static int _luksFormat(struct crypt_device **r_cd, char **r_password, size_t *r_passwordLen)
{
int r = -EINVAL, keysize, integrity_keysize = 0, fd, created = 0;
@@ -1225,7 +1280,7 @@ static int _luksFormat(struct crypt_device **r_cd, char **r_password, size_t *r_
};
void *params;
- type = luksType(opt_type);
+ type = luksType(device_type);
if (!type)
type = crypt_get_default_type();
@@ -1254,7 +1309,7 @@ static int _luksFormat(struct crypt_device **r_cd, char **r_password, size_t *r_
/* 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?",
+ !yesDialog(_("Header file does not exist, do you want to create it?"),
_("Operation aborted.\n")))
return -EPERM;
@@ -1293,7 +1348,7 @@ static int _luksFormat(struct crypt_device **r_cd, char **r_password, size_t *r_
}
/* Never call pwquality if using null cipher */
- if (tools_is_cipher_null(cipher))
+ if (crypt_is_cipher_null(cipher))
opt_force_password = 1;
if ((r = crypt_init(&cd, header_device))) {
@@ -1334,15 +1389,7 @@ static int _luksFormat(struct crypt_device **r_cd, char **r_password, size_t *r_
goto out;
}
-#ifdef ENABLE_LUKS_ADJUST_XTS_KEYSIZE
- if (!opt_key_size && !strncmp(cipher_mode, "xts-", 4)) {
- if (DEFAULT_LUKS1_KEYBITS == 128)
- opt_key_size = 256;
- else if (DEFAULT_LUKS1_KEYBITS == 256)
- opt_key_size = 512;
- }
-#endif
- keysize = (opt_key_size ?: DEFAULT_LUKS1_KEYBITS) / 8 + integrity_keysize;
+ keysize = get_adjusted_key_size(cipher_mode, DEFAULT_LUKS1_KEYBITS, integrity_keysize);
if (opt_random)
crypt_set_rng_type(cd, CRYPT_RNG_RANDOM);
@@ -1441,7 +1488,7 @@ static int action_open_luks(void)
if ((r = crypt_init_data_device(&cd, header_device, data_device)))
goto out;
- if ((r = crypt_load(cd, luksType(opt_type), NULL))) {
+ if ((r = crypt_load(cd, luksType(device_type), NULL))) {
log_err(_("Device %s is not a valid LUKS device."),
header_device);
goto out;
@@ -1567,7 +1614,7 @@ static int action_luksKillSlot(void)
crypt_set_confirm_callback(cd, yesDialog, NULL);
- if ((r = crypt_load(cd, luksType(opt_type), NULL))) {
+ if ((r = crypt_load(cd, luksType(device_type), NULL))) {
log_err(_("Device %s is not a valid LUKS device."),
uuid_or_device_header(NULL));
goto out;
@@ -1624,7 +1671,7 @@ static int action_luksRemoveKey(void)
crypt_set_confirm_callback(cd, yesDialog, NULL);
- if ((r = crypt_load(cd, luksType(opt_type), NULL))) {
+ if ((r = crypt_load(cd, luksType(device_type), NULL))) {
log_err(_("Device %s is not a valid LUKS device."),
uuid_or_device_header(NULL));
goto out;
@@ -1691,7 +1738,7 @@ static int luksAddUnboundKey(void)
goto out;
/* Never call pwquality if using null cipher */
- if (tools_is_cipher_null(crypt_get_cipher(cd)))
+ if (crypt_is_cipher_null(crypt_get_cipher(cd)))
opt_force_password = 1;
keysize = opt_key_size / 8;
@@ -1747,7 +1794,7 @@ static int action_luksAddKey(void)
crypt_set_confirm_callback(cd, yesDialog, NULL);
- if ((r = crypt_load(cd, luksType(opt_type), NULL))) {
+ if ((r = crypt_load(cd, luksType(device_type), NULL))) {
log_err(_("Device %s is not a valid LUKS device."),
uuid_or_device_header(NULL));
goto out;
@@ -1758,7 +1805,7 @@ static int action_luksAddKey(void)
goto out;
/* Never call pwquality if using null cipher */
- if (tools_is_cipher_null(crypt_get_cipher(cd)))
+ if (crypt_is_cipher_null(crypt_get_cipher(cd)))
opt_force_password = 1;
keysize = crypt_get_volume_key_size(cd);
@@ -1850,7 +1897,7 @@ static int action_luksChangeKey(void)
if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
goto out;
- if ((r = crypt_load(cd, luksType(opt_type), NULL))) {
+ if ((r = crypt_load(cd, luksType(device_type), NULL))) {
log_err(_("Device %s is not a valid LUKS device."),
uuid_or_device_header(NULL));
goto out;
@@ -1861,7 +1908,7 @@ static int action_luksChangeKey(void)
goto out;
/* Never call pwquality if using null cipher */
- if (tools_is_cipher_null(crypt_get_cipher(cd)))
+ if (crypt_is_cipher_null(crypt_get_cipher(cd)))
opt_force_password = 1;
r = set_pbkdf_params(cd, crypt_get_type(cd));
@@ -1968,7 +2015,7 @@ static int action_isLuks(void)
goto out;
crypt_set_log_callback(cd, quiet_log, NULL);
- r = crypt_load(cd, luksType(opt_type), NULL);
+ r = crypt_load(cd, luksType(device_type), NULL);
out:
crypt_free(cd);
return r;
@@ -1985,7 +2032,7 @@ static int action_luksUUID(void)
crypt_set_confirm_callback(cd, yesDialog, _("Operation aborted.\n"));
- if ((r = crypt_load(cd, luksType(opt_type), NULL)))
+ if ((r = crypt_load(cd, luksType(device_type), NULL)))
goto out;
if (opt_uuid)
@@ -2144,7 +2191,7 @@ static int action_luksDump(void)
if ((r = crypt_init(&cd, uuid_or_device_header(NULL))))
goto out;
- if ((r = crypt_load(cd, luksType(opt_type), NULL))) {
+ if ((r = crypt_load(cd, luksType(device_type), NULL))) {
log_err(_("Device %s is not a valid LUKS device."),
uuid_or_device_header(NULL));
goto out;
@@ -2167,8 +2214,11 @@ static int action_luksSuspend(void)
int r;
r = crypt_init_by_name_and_header(&cd, action_argv[0], uuid_or_device(opt_header_device));
- if (!r)
+ if (!r) {
r = crypt_suspend(cd, action_argv[0]);
+ if (r == -ENODEV)
+ log_err(_("%s is not active %s device name."), action_argv[0], "LUKS");
+ }
crypt_free(cd);
return r;
@@ -2180,12 +2230,25 @@ static int action_luksResume(void)
char *password = NULL;
size_t passwordLen;
int r, tries;
+ const char *type, *req_type = luksType(device_type);
+
+ if (req_type && strcmp(req_type, CRYPT_LUKS1) && strcmp(req_type, CRYPT_LUKS2))
+ return -EINVAL;
if ((r = crypt_init_by_name_and_header(&cd, action_argv[0], uuid_or_device(opt_header_device))))
+ return r;
+
+ r = -EINVAL;
+ type = crypt_get_type(cd);
+ if (!type || (strcmp(type, CRYPT_LUKS1) && strcmp(type, CRYPT_LUKS2))) {
+ log_err(_("%s is not active LUKS device name or header is missing."), action_argv[0]);
goto out;
+ }
- if ((r = crypt_load(cd, luksType(opt_type), NULL)))
+ if (req_type && strcmp(req_type, crypt_get_type(cd))) {
+ log_err(_("%s is not active %s device name."), action_argv[0], req_type);
goto out;
+ }
tries = (tools_is_stdin(opt_key_file) && isatty(STDIN_FILENO)) ? opt_tries : 1;
do {
@@ -2289,38 +2352,38 @@ static const char *_get_device_type(void)
static int action_open(void)
{
- if (opt_refresh && !opt_type)
+ if (opt_refresh && !device_type)
/* read device type from active mapping */
- opt_type = _get_device_type();
+ device_type = _get_device_type();
- if (!opt_type)
+ if (!device_type)
return -EINVAL;
- if (!strcmp(opt_type, "luks") ||
- !strcmp(opt_type, "luks1") ||
- !strcmp(opt_type, "luks2")) {
+ if (!strcmp(device_type, "luks") ||
+ !strcmp(device_type, "luks1") ||
+ !strcmp(device_type, "luks2")) {
if (action_argc < 2 && (!opt_test_passphrase && !opt_refresh))
goto args;
return action_open_luks();
- } else if (!strcmp(opt_type, "plain")) {
+ } else if (!strcmp(device_type, "plain")) {
if (action_argc < 2 && !opt_refresh)
goto args;
return action_open_plain();
- } else if (!strcmp(opt_type, "loopaes")) {
+ } else if (!strcmp(device_type, "loopaes")) {
if (action_argc < 2 && !opt_refresh)
goto args;
return action_open_loopaes();
- } else if (!strcmp(opt_type, "tcrypt")) {
+ } else if (!strcmp(device_type, "tcrypt")) {
if (action_argc < 2 && !opt_test_passphrase)
goto args;
return action_open_tcrypt();
- } else if (!strcmp(opt_type, "bitlk")) {
+ } else if (!strcmp(device_type, "bitlk")) {
if (action_argc < 2 && !opt_test_passphrase)
goto args;
return action_open_bitlk();
}
- log_err(_("Unrecognized metadata device type %s."), opt_type);
+ log_err(_("Unrecognized metadata device type %s."), device_type);
return -EINVAL;
args:
log_err(_("Command requires device and mapped name as arguments."));
@@ -2339,7 +2402,7 @@ static int action_luksErase(void)
crypt_set_confirm_callback(cd, yesDialog, NULL);
- if ((r = crypt_load(cd, luksType(opt_type), NULL))) {
+ if ((r = crypt_load(cd, luksType(device_type), NULL))) {
log_err(_("Device %s is not a valid LUKS device."),
uuid_or_device_header(NULL));
goto out;
@@ -2359,8 +2422,10 @@ static int action_luksErase(void)
/* Safety check */
max = crypt_keyslot_max(crypt_get_type(cd));
- if (max <= 0)
- return -EINVAL;
+ if (max <= 0) {
+ r = -EINVAL;
+ goto out;
+ }
for (i = 0; i < max; i++) {
ki = crypt_keyslot_status(cd, i);
@@ -2384,9 +2449,9 @@ static int action_luksConvert(void)
const char *to_type, *from_type;
int r;
- if (!strcmp(opt_type, "luks2")) {
+ if (!strcmp(device_type, "luks2")) {
to_type = CRYPT_LUKS2;
- } else if (!strcmp(opt_type, "luks1")) {
+ } else if (!strcmp(device_type, "luks1")) {
to_type = CRYPT_LUKS1;
} else {
log_err(_("Invalid LUKS type, only luks1 and luks2 are supported."));
@@ -2705,8 +2770,8 @@ static int action_reencrypt_load(struct crypt_device *cd)
char dm_name[PATH_MAX] = {}, *password = NULL;
const char *active_name = NULL;
struct crypt_params_reencrypt params = {
- .resilience = opt_resilience_mode,
- .hash = opt_resilience_hash,
+ .resilience = opt_resilience_mode ?: "checksum",
+ .hash = opt_resilience_hash ?: "sha256",
.max_hotzone_size = opt_hotzone_size / SECTOR_SIZE,
.device_size = opt_device_size / SECTOR_SIZE,
.flags = CRYPT_REENCRYPT_RESUME_ONLY
@@ -2750,8 +2815,8 @@ static int action_encrypt_luks2(struct crypt_device **cd)
struct crypt_params_reencrypt params = {
.mode = CRYPT_REENCRYPT_ENCRYPT,
.direction = opt_data_shift < 0 ? CRYPT_REENCRYPT_BACKWARD : CRYPT_REENCRYPT_FORWARD,
- .resilience = opt_resilience_mode,
- .hash = opt_resilience_hash,
+ .resilience = opt_resilience_mode ?: "checksum",
+ .hash = opt_resilience_hash ?: "sha256",
.max_hotzone_size = opt_hotzone_size / SECTOR_SIZE,
.device_size = opt_device_size / SECTOR_SIZE,
.luks2 = &luks2_params,
@@ -2760,7 +2825,7 @@ static int action_encrypt_luks2(struct crypt_device **cd)
_set_reencryption_flags(¶ms.flags);
- type = luksType(opt_type);
+ type = luksType(device_type);
if (!type)
type = crypt_get_default_type();
@@ -2800,7 +2865,8 @@ static int action_encrypt_luks2(struct crypt_device **cd)
if (!opt_uuid) {
uuid_generate(uuid);
uuid_unparse(uuid, uuid_str);
- opt_uuid = uuid_str;
+ if (!(opt_uuid = strdup(uuid_str)))
+ return -ENOMEM;
}
/* Check the data device is not LUKS device already */
@@ -2839,7 +2905,10 @@ static int action_encrypt_luks2(struct crypt_device **cd)
goto err;
}
- opt_header_device = header_file;
+ if (!(opt_header_device = strdup(header_file))) {
+ r = -ENOMEM;
+ goto err;
+ }
/*
* FIXME: just override offset here, but we should support both.
* offset and implicit offset via data shift (lvprepend?)
@@ -2925,8 +2994,8 @@ static int action_decrypt_luks2(struct crypt_device *cd)
struct crypt_params_reencrypt params = {
.mode = CRYPT_REENCRYPT_DECRYPT,
.direction = opt_data_shift > 0 ? CRYPT_REENCRYPT_FORWARD : CRYPT_REENCRYPT_BACKWARD,
- .resilience = opt_data_shift ? "datashift" : opt_resilience_mode,
- .hash = opt_resilience_hash,
+ .resilience = opt_data_shift ? "datashift" : (opt_resilience_mode ?: "checksum"),
+ .hash = opt_resilience_hash ?: "sha256",
.data_shift = imaxabs(opt_data_shift) / SECTOR_SIZE,
.device_size = opt_device_size / SECTOR_SIZE,
.max_hotzone_size = opt_hotzone_size / SECTOR_SIZE,
@@ -3138,8 +3207,8 @@ static int action_reencrypt_luks2(struct crypt_device *cd)
struct crypt_params_reencrypt params = {
.mode = CRYPT_REENCRYPT_REENCRYPT,
.direction = opt_data_shift < 0 ? CRYPT_REENCRYPT_BACKWARD : CRYPT_REENCRYPT_FORWARD,
- .resilience = opt_data_shift ? "datashift" : opt_resilience_mode,
- .hash = opt_resilience_hash,
+ .resilience = opt_data_shift ? "datashift" : (opt_resilience_mode ?: "checksum"),
+ .hash = opt_resilience_hash ?: "sha256",
.data_shift = imaxabs(opt_data_shift) / SECTOR_SIZE,
.max_hotzone_size = opt_hotzone_size / SECTOR_SIZE,
.device_size = opt_device_size / SECTOR_SIZE,
@@ -3148,6 +3217,11 @@ static int action_reencrypt_luks2(struct crypt_device *cd)
_set_reencryption_flags(¶ms.flags);
+ if (!opt_cipher && crypt_is_cipher_null(crypt_get_cipher(cd))) {
+ opt_cipher = strdup(DEFAULT_CIPHER(LUKS1));
+ log_std(_("Switching data encryption cipher to %s.\n"), opt_cipher);
+ }
+
if (!opt_cipher) {
strncpy(cipher, crypt_get_cipher(cd), MAX_CIPHER_LEN - 1);
strncpy(mode, crypt_get_cipher_mode(cd), MAX_CIPHER_LEN - 1);
@@ -3164,10 +3238,8 @@ static int action_reencrypt_luks2(struct crypt_device *cd)
if (r)
return r;
- if (opt_key_size)
- key_size = opt_key_size / 8;
- else if (opt_cipher)
- key_size = DEFAULT_LUKS1_KEYBITS / 8;
+ if (opt_key_size || opt_cipher)
+ key_size = get_adjusted_key_size(mode, DEFAULT_LUKS1_KEYBITS, 0);
else
key_size = crypt_get_volume_key_size(cd);
@@ -3450,10 +3522,12 @@ static void help(poptContext popt_context,
#if defined(ENABLE_LUKS_ADJUST_XTS_KEYSIZE) && DEFAULT_LUKS1_KEYBITS != 512
log_std(_("\tLUKS: Default keysize with XTS mode (two internal keys) will be doubled.\n"));
#endif
+ tools_cleanup();
poptFreeContext(popt_context);
exit(EXIT_SUCCESS);
} else if (key->shortName == 'V') {
log_std("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+ tools_cleanup();
poptFreeContext(popt_context);
exit(EXIT_SUCCESS);
} else
@@ -3494,7 +3568,6 @@ static int run_action(struct action_type *action)
int main(int argc, const char **argv)
{
- static char *popt_tmp;
static struct poptOption popt_help_options[] = {
{ NULL, '\0', POPT_ARG_CALLBACK, help, 0, NULL, NULL },
{ "help", '?', POPT_ARG_NONE, NULL, 0, N_("Show this help message"), NULL },
@@ -3510,19 +3583,19 @@ int main(int argc, const char **argv)
{ "cipher", 'c', POPT_ARG_STRING, &opt_cipher, 0, N_("The cipher used to encrypt the disk (see /proc/crypto)"), NULL },
{ "hash", 'h', POPT_ARG_STRING, &opt_hash, 0, N_("The hash used to create the encryption key from the passphrase"), NULL },
{ "verify-passphrase", 'y', POPT_ARG_NONE, &opt_verify_passphrase, 0, N_("Verifies the passphrase by asking for it twice"), NULL },
- { "key-file", 'd', POPT_ARG_STRING, &opt_key_file, 6, N_("Read the key from a file"), NULL },
+ { "key-file", 'd', POPT_ARG_STRING, NULL, 6, N_("Read the key from a file"), NULL },
{ "master-key-file", '\0', POPT_ARG_STRING, &opt_master_key_file, 0, N_("Read the volume (master) key from file."), NULL },
{ "dump-master-key", '\0', POPT_ARG_NONE, &opt_dump_master_key, 0, N_("Dump volume (master) key instead of keyslots info"), NULL },
{ "key-size", 's', POPT_ARG_INT, &opt_key_size, 0, N_("The size of the encryption key"), N_("BITS") },
{ "keyfile-size", 'l', POPT_ARG_LONG, &opt_keyfile_size, 0, N_("Limits the read from keyfile"), N_("bytes") },
- { "keyfile-offset", '\0', POPT_ARG_STRING, &popt_tmp, 4, N_("Number of bytes to skip in keyfile"), N_("bytes") },
+ { "keyfile-offset", '\0', POPT_ARG_STRING, NULL, 4, N_("Number of bytes to skip in keyfile"), N_("bytes") },
{ "new-keyfile-size", '\0', POPT_ARG_LONG, &opt_new_keyfile_size, 0, N_("Limits the read from newly added keyfile"), N_("bytes") },
- { "new-keyfile-offset",'\0', POPT_ARG_STRING, &popt_tmp, 5, N_("Number of bytes to skip in newly added keyfile"), N_("bytes") },
+ { "new-keyfile-offset",'\0', POPT_ARG_STRING, NULL, 5, N_("Number of bytes to skip in newly added keyfile"), N_("bytes") },
{ "key-slot", 'S', POPT_ARG_INT, &opt_key_slot, 0, N_("Slot number for new key (default is first free)"), NULL },
- { "size", 'b', POPT_ARG_STRING, &popt_tmp, 1, N_("The size of the device"), N_("SECTORS") },
+ { "size", 'b', POPT_ARG_STRING, NULL, 1, N_("The size of the device"), N_("SECTORS") },
{ "device-size", '\0', POPT_ARG_STRING, &opt_device_size_str, 0, N_("Use only specified device size (ignore rest of device). DANGEROUS!"), N_("bytes") },
- { "offset", 'o', POPT_ARG_STRING, &popt_tmp, 2, N_("The start offset in the backend device"), N_("SECTORS") },
- { "skip", 'p', POPT_ARG_STRING, &popt_tmp, 3, N_("How many sectors of the encrypted data to skip at the beginning"), N_("SECTORS") },
+ { "offset", 'o', POPT_ARG_STRING, NULL, 2, N_("The start offset in the backend device"), N_("SECTORS") },
+ { "skip", 'p', POPT_ARG_STRING, NULL, 3, N_("How many sectors of the encrypted data to skip at the beginning"), N_("SECTORS") },
{ "readonly", 'r', POPT_ARG_NONE, &opt_readonly, 0, N_("Create a readonly mapping"), NULL },
{ "batch-mode", 'q', POPT_ARG_NONE, &opt_batch_mode, 0, N_("Do not ask for confirmation"), NULL },
{ "timeout", 't', POPT_ARG_INT, &opt_timeout, 0, N_("Timeout for interactive passphrase prompt (in seconds)"), N_("secs") },
@@ -3606,25 +3679,29 @@ int main(int argc, const char **argv)
while((r = poptGetNextOpt(popt_context)) > 0) {
unsigned long long ull_value;
- char *endp;
+ char *endp, *str = poptGetOptArg(popt_context);
if (r == 6) {
- const char *kf = poptGetOptArg(popt_context);
- if (tools_is_stdin(kf))
- opt_keyfile_stdin = kf;
- else if (opt_keyfiles_count < MAX_KEYFILES)
- opt_keyfiles[opt_keyfiles_count++] = kf;
+ free(opt_key_file);
+ opt_key_file = str;
+ if (tools_is_stdin(str)) {
+ free(opt_keyfile_stdin);
+ opt_keyfile_stdin = strdup(str);
+ } else if (opt_keyfiles_count < MAX_KEYFILES)
+ opt_keyfiles[opt_keyfiles_count++] = strdup(str);
total_keyfiles++;
continue;
}
errno = 0;
- ull_value = strtoull(popt_tmp, &endp, 0);
- if (*endp || !*popt_tmp || !isdigit(*popt_tmp) ||
+ ull_value = strtoull(str, &endp, 0);
+ if (*endp || !*str || !isdigit(*str) ||
(errno == ERANGE && ull_value == ULLONG_MAX) ||
(errno != 0 && ull_value == 0))
r = POPT_ERROR_BADNUMBER;
+ free(str);
+
switch(r) {
case 1:
opt_size = ull_value;
@@ -3675,26 +3752,26 @@ int main(int argc, const char **argv)
action_argv[1] = tmp;
}
aname = "open";
- opt_type = "plain";
+ device_type = "plain";
} else if (!strcmp(aname, "plainOpen")) {
aname = "open";
- opt_type = "plain";
+ device_type = "plain";
} else if (!strcmp(aname, "luksOpen")) {
aname = "open";
- opt_type = "luks";
+ device_type = "luks";
} else if (!strcmp(aname, "loopaesOpen")) {
aname = "open";
- opt_type = "loopaes";
+ device_type = "loopaes";
} else if (!strcmp(aname, "tcryptOpen")) {
aname = "open";
- opt_type = "tcrypt";
+ device_type = "tcrypt";
} else if (!strcmp(aname, "bitlkOpen")) {
aname = "open";
- opt_type = "bitlk";
+ device_type = "bitlk";
} else if (!strcmp(aname, "tcryptDump")) {
- opt_type = "tcrypt";
+ device_type = "tcrypt";
} else if (!strcmp(aname, "bitlkDump")) {
- opt_type = "bitlk";
+ device_type = "bitlk";
} else if (!strcmp(aname, "remove") ||
!strcmp(aname, "plainClose") ||
!strcmp(aname, "luksClose") ||
@@ -3704,18 +3781,19 @@ int main(int argc, const char **argv)
aname = "close";
} else if (!strcmp(aname, "luksErase")) {
aname = "erase";
- opt_type = "luks";
+ device_type = "luks";
} else if (!strcmp(aname, "luksConfig")) {
aname = "config";
- opt_type = "luks2";
+ device_type = "luks2";
} else if (!strcmp(aname, "refresh")) {
aname = "open";
opt_refresh = 1;
- }
+ } else if (opt_type)
+ device_type = opt_type;
/* ignore user supplied type and query device type instead */
if (opt_refresh)
- opt_type = NULL;
+ device_type = NULL;
for(action = action_types; action->type; action++)
if (strcmp(action->type, aname) == 0)
@@ -3740,7 +3818,7 @@ int main(int argc, const char **argv)
_("Option --deferred is allowed only for close command."),
poptGetInvocationName(popt_context));
- if (opt_shared && (strcmp(aname, "open") || strcmp_or_null(opt_type, "plain")))
+ if (opt_shared && (strcmp(aname, "open") || strcmp_or_null(device_type, "plain")))
usage(popt_context, EXIT_FAILURE,
_("Option --shared is allowed only for open of plain device."),
poptGetInvocationName(popt_context));
@@ -3792,8 +3870,8 @@ int main(int argc, const char **argv)
_("Options --label and --subsystem are allowed only for luksFormat and config LUKS2 operations."),
poptGetInvocationName(popt_context));
- if (opt_test_passphrase && (strcmp(aname, "open") || !opt_type ||
- (strncmp(opt_type, "luks", 4) && strcmp(opt_type, "tcrypt") && strcmp(opt_type, "bitlk"))))
+ if (opt_test_passphrase && (strcmp(aname, "open") || !device_type ||
+ (strncmp(device_type, "luks", 4) && strcmp(device_type, "tcrypt") && strcmp(device_type, "bitlk"))))
usage(popt_context, EXIT_FAILURE,
_("Option --test-passphrase is allowed only for open of LUKS, TCRYPT and BITLK devices."),
poptGetInvocationName(popt_context));
@@ -3815,7 +3893,7 @@ int main(int argc, const char **argv)
if (opt_key_file)
log_err(_("Option --key-file takes precedence over specified key file argument."));
else
- opt_key_file = action_argv[1];
+ opt_key_file = strdup(action_argv[1]);
}
if (opt_keyfile_size < 0 || opt_new_keyfile_size < 0 || opt_key_size < 0)
@@ -3823,7 +3901,7 @@ int main(int argc, const char **argv)
_("Negative number for option not permitted."),
poptGetInvocationName(popt_context));
- if (total_keyfiles > 1 && (strcmp_or_null(opt_type, "tcrypt")))
+ if (total_keyfiles > 1 && (strcmp_or_null(device_type, "tcrypt")))
usage(popt_context, EXIT_FAILURE, _("Only one --key-file argument is allowed."),
poptGetInvocationName(popt_context));
@@ -3861,20 +3939,20 @@ int main(int argc, const char **argv)
poptGetInvocationName(popt_context));
if (opt_skip && (strcmp(aname, "open") ||
- (strcmp_or_null(opt_type, "plain") && strcmp(opt_type, "loopaes"))))
+ (strcmp_or_null(device_type, "plain") && strcmp(device_type, "loopaes"))))
usage(popt_context, EXIT_FAILURE,
_("Option --skip is supported only for open of plain and loopaes devices."),
poptGetInvocationName(popt_context));
if (opt_offset && ((strcmp(aname, "reencrypt") && strcmp(aname, "open") && strcmp(aname, "luksFormat")) ||
- (!strcmp(aname, "open") && strcmp_or_null(opt_type, "plain") && strcmp(opt_type, "loopaes")) ||
- (!strcmp(aname, "luksFormat") && opt_type && strncmp(opt_type, "luks", 4))))
+ (!strcmp(aname, "open") && strcmp_or_null(device_type, "plain") && strcmp(device_type, "loopaes")) ||
+ (!strcmp(aname, "luksFormat") && device_type && strncmp(device_type, "luks", 4))))
usage(popt_context, EXIT_FAILURE,
_("Option --offset is supported only for open of plain and loopaes devices, luksFormat and device reencryption."),
poptGetInvocationName(popt_context));
if ((opt_tcrypt_hidden || opt_tcrypt_system || opt_tcrypt_backup) && strcmp(aname, "tcryptDump") &&
- (strcmp(aname, "open") || !opt_type || strcmp(opt_type, "tcrypt")))
+ (strcmp(aname, "open") || !device_type || strcmp(device_type, "tcrypt")))
usage(popt_context, EXIT_FAILURE,
_("Option --tcrypt-hidden, --tcrypt-system or --tcrypt-backup is supported only for TCRYPT device."),
poptGetInvocationName(popt_context));
@@ -3884,7 +3962,7 @@ int main(int argc, const char **argv)
_("Option --tcrypt-hidden cannot be combined with --allow-discards."),
poptGetInvocationName(popt_context));
- if (opt_veracrypt && (!opt_type || strcmp(opt_type, "tcrypt")))
+ if (opt_veracrypt && (!device_type || strcmp(device_type, "tcrypt")))
usage(popt_context, EXIT_FAILURE,
_("Option --veracrypt is supported only for TCRYPT device type."),
poptGetInvocationName(popt_context));
@@ -3923,7 +4001,7 @@ int main(int argc, const char **argv)
_("Keyslot specification is required."),
poptGetInvocationName(popt_context));
- if (opt_pbkdf && crypt_parse_pbkdf(opt_pbkdf, &opt_pbkdf))
+ if (opt_pbkdf && crypt_parse_pbkdf(opt_pbkdf, &set_pbkdf))
usage(popt_context, EXIT_FAILURE,
_("Password-based key derivation function (PBKDF) can be only pbkdf2 or argon2i/argon2id."),
poptGetInvocationName(popt_context));
@@ -3934,7 +4012,7 @@ int main(int argc, const char **argv)
poptGetInvocationName(popt_context));
if (opt_sector_size && strcmp(aname, "reencrypt") && strcmp(aname, "luksFormat") &&
- (strcmp(aname, "open") || strcmp_or_null(opt_type, "plain")))
+ (strcmp(aname, "open") || strcmp_or_null(device_type, "plain")))
usage(popt_context, EXIT_FAILURE,
_("Sector size option is not supported for this command."),
poptGetInvocationName(popt_context));
@@ -3980,6 +4058,7 @@ int main(int argc, const char **argv)
if (opt_disable_locks && crypt_metadata_locking(NULL, 0)) {
log_std(_("Cannot disable metadata locking."));
+ tools_cleanup();
poptFreeContext(popt_context);
exit(EXIT_FAILURE);
}
@@ -4037,6 +4116,7 @@ int main(int argc, const char **argv)
poptGetInvocationName(popt_context));
r = run_action(action);
+ tools_cleanup();
poptFreeContext(popt_context);
return r;
}
diff --git a/src/cryptsetup.h b/src/cryptsetup.h
index 1afcf433..66446308 100644
--- a/src/cryptsetup.h
+++ b/src/cryptsetup.h
@@ -24,6 +24,7 @@
#ifndef CRYPTSETUP_H
#define CRYPTSETUP_H
+#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
@@ -97,7 +98,6 @@ int tools_get_key(const char *prompt,
void tools_passphrase_msg(int r);
int tools_is_stdin(const char *key_file);
int tools_string_to_size(struct crypt_device *cd, const char *s, uint64_t *size);
-int tools_is_cipher_null(const char *cipher);
void tools_clear_line(void);
@@ -116,6 +116,11 @@ int tools_wipe_all_signatures(const char *path);
int tools_lookup_crypt_device(struct crypt_device *cd, const char *type,
const char *data_device_path, char *name, size_t name_length);
+/* each utility is required to implement it */
+void tools_cleanup(void);
+
+#define FREE_AND_NULL(x) do { free(x); x = NULL; } while (0)
+
/* Log */
#define log_dbg(x...) clogger(NULL, CRYPT_LOG_DEBUG, __FILE__, __LINE__, x)
#define log_std(x...) clogger(NULL, CRYPT_LOG_NORMAL, __FILE__, __LINE__, x)
diff --git a/src/cryptsetup_reencrypt.c b/src/cryptsetup_reencrypt.c
index a536093b..e5f9786c 100644
--- a/src/cryptsetup_reencrypt.c
+++ b/src/cryptsetup_reencrypt.c
@@ -29,16 +29,25 @@
#define NO_UUID "cafecafe-cafe-cafe-cafe-cafecafeeeee"
-static const char *opt_cipher = NULL;
-static const char *opt_hash = NULL;
-static const char *opt_key_file = NULL;
-static const char *opt_master_key_file = NULL;
-static const char *opt_uuid = NULL;
-static const char *opt_type = "luks";
+static char *opt_cipher = NULL;
+static char *opt_hash = NULL;
+static char *opt_key_file = NULL;
+static char *opt_master_key_file = NULL;
+static char *opt_uuid = NULL;
+static char *opt_type = NULL;
+static char *opt_pbkdf = NULL;
+static char *opt_header_device = NULL;
+
+/* helper strings converted to uint64_t later */
+static char *opt_reduce_size_str = NULL;
+static char *opt_device_size_str = NULL;
+
+static uint64_t opt_reduce_size = 0;
+static uint64_t opt_device_size = 0;
+
static long opt_keyfile_size = 0;
static long opt_keyfile_offset = 0;
static int opt_iteration_time = 0;
-static const char *opt_pbkdf = NULL;
static long opt_pbkdf_memory = DEFAULT_LUKS2_MEMORY_KB;
static long opt_pbkdf_parallel = DEFAULT_LUKS2_PARALLEL_THREADS;
static long opt_pbkdf_iterations = 0;
@@ -54,16 +63,11 @@ static int opt_key_size = 0;
static int opt_new = 0;
static int opt_keep_key = 0;
static int opt_decrypt = 0;
-static const char *opt_header_device = NULL;
-
-static const char *opt_reduce_size_str = NULL;
-static uint64_t opt_reduce_size = 0;
-
-static const char *opt_device_size_str = NULL;
-static uint64_t opt_device_size = 0;
static const char **action_argv;
+static const char *set_pbkdf = NULL;
+
#define MAX_SLOT 32
#define MAX_TOKEN 32
struct reenc_ctx {
@@ -113,6 +117,20 @@ typedef enum {
CHECK_OPEN,
} header_magic;
+void tools_cleanup(void)
+{
+ FREE_AND_NULL(opt_cipher);
+ FREE_AND_NULL(opt_hash);
+ FREE_AND_NULL(opt_key_file);
+ FREE_AND_NULL(opt_master_key_file);
+ FREE_AND_NULL(opt_uuid);
+ FREE_AND_NULL(opt_type);
+ FREE_AND_NULL(opt_pbkdf);
+ FREE_AND_NULL(opt_header_device);
+ FREE_AND_NULL(opt_reduce_size_str);
+ FREE_AND_NULL(opt_device_size_str);
+}
+
static void _quiet_log(int level, const char *msg, void *usrptr)
{
if (!opt_debug)
@@ -482,7 +500,7 @@ static int set_pbkdf_params(struct crypt_device *cd, const char *dev_type)
if (!pbkdf_default)
return -EINVAL;
- pbkdf.type = opt_pbkdf ?: pbkdf_default->type;
+ pbkdf.type = set_pbkdf ?: pbkdf_default->type;
pbkdf.hash = opt_hash ?: pbkdf_default->hash;
pbkdf.time_ms = (uint32_t)opt_iteration_time ?: pbkdf_default->time_ms;
if (strcmp(pbkdf.type, CRYPT_KDF_PBKDF2)) {
@@ -1590,10 +1608,12 @@ static void help(poptContext popt_context,
if (key->shortName == '?') {
log_std("%s %s\n", PACKAGE_REENC, PACKAGE_VERSION);
poptPrintHelp(popt_context, stdout, 0);
+ tools_cleanup();
poptFreeContext(popt_context);
exit(EXIT_SUCCESS);
} else if (key->shortName == 'V') {
log_std("%s %s\n", PACKAGE_REENC, PACKAGE_VERSION);
+ tools_cleanup();
poptFreeContext(popt_context);
exit(EXIT_SUCCESS);
} else
@@ -1688,7 +1708,7 @@ int main(int argc, const char **argv)
poptGetInvocationName(popt_context));
}
- if (opt_pbkdf && crypt_parse_pbkdf(opt_pbkdf, &opt_pbkdf))
+ if (opt_pbkdf && crypt_parse_pbkdf(opt_pbkdf, &set_pbkdf))
usage(popt_context, EXIT_FAILURE,
_("Password-based key derivation function (PBKDF) can be only pbkdf2 or argon2i/argon2id."),
poptGetInvocationName(popt_context));
@@ -1764,8 +1784,7 @@ int main(int argc, const char **argv)
}
r = run_reencrypt(action_argv[0]);
-
+ tools_cleanup();
poptFreeContext(popt_context);
-
return translate_errno(r);
}
diff --git a/src/integritysetup.c b/src/integritysetup.c
index 51778da9..26d5a285 100644
--- a/src/integritysetup.c
+++ b/src/integritysetup.c
@@ -27,8 +27,19 @@
#define DEFAULT_ALG_NAME "crc32c"
#define MAX_KEY_SIZE 4096
-static const char *opt_journal_size_str = NULL;
+static char *opt_data_device = NULL;
+static char *opt_integrity = NULL; /* DEFAULT_ALG_NAME */
+static char *opt_integrity_key_file = NULL;
+static char *opt_journal_integrity = NULL; /* none */
+static char *opt_journal_integrity_key_file = NULL;
+static char *opt_journal_crypt = NULL; /* none */
+static char *opt_journal_crypt_key_file = NULL;
+
+/* helper strings converted to uint64_t later */
+static char *opt_journal_size_str = NULL;
+
static uint64_t opt_journal_size = 0;
+
static int opt_interleave_sectors = 0;
static int opt_journal_watermark = 0;
static int opt_bitmap_sectors_per_bit = 0;
@@ -37,34 +48,35 @@ static int opt_bitmap_flush_time = 0;
static int opt_tag_size = 0;
static int opt_sector_size = 0;
static int opt_buffer_sectors = 0;
-
static int opt_no_wipe = 0;
-
-static const char *opt_data_device = NULL;
-
-static const char *opt_integrity = DEFAULT_ALG_NAME;
-static const char *opt_integrity_key_file = NULL;
static int opt_integrity_key_size = 0;
-
-static const char *opt_journal_integrity = NULL; /* none */
-static const char *opt_journal_integrity_key_file = NULL;
static int opt_journal_integrity_key_size = 0;
-
-static const char *opt_journal_crypt = NULL; /* none */
-static const char *opt_journal_crypt_key_file = NULL;
static int opt_journal_crypt_key_size = 0;
-
static int opt_integrity_nojournal = 0;
static int opt_integrity_recovery = 0;
static int opt_integrity_bitmap = 0;
static int opt_integrity_legacy_padding = 0;
-
+static int opt_integrity_legacy_hmac = 0;
+static int opt_integrity_legacy_recalculate = 0;
static int opt_integrity_recalculate = 0;
static int opt_allow_discards = 0;
+static const char *integrity_alg = DEFAULT_ALG_NAME;
static const char **action_argv;
static int action_argc;
+void tools_cleanup(void)
+{
+ FREE_AND_NULL(opt_data_device);
+ FREE_AND_NULL(opt_integrity);
+ FREE_AND_NULL(opt_integrity_key_file);
+ FREE_AND_NULL(opt_journal_integrity);
+ FREE_AND_NULL(opt_journal_integrity_key_file);
+ FREE_AND_NULL(opt_journal_crypt);
+ FREE_AND_NULL(opt_journal_crypt_key_file);
+ FREE_AND_NULL(opt_journal_size_str);
+}
+
// FIXME: move this to tools and handle EINTR
static int _read_mk(const char *file, char **key, int keysize)
{
@@ -189,14 +201,12 @@ static int action_format(int arg)
int r;
size_t signatures;
- if (opt_integrity) {
- r = crypt_parse_hash_integrity_mode(opt_integrity, integrity);
+ r = crypt_parse_hash_integrity_mode(integrity_alg, integrity);
if (r < 0) {
log_err(_("No known integrity specification pattern detected."));
return r;
}
params.integrity = integrity;
- }
if (opt_journal_integrity) {
r = crypt_parse_hash_integrity_mode(opt_journal_integrity, journal_integrity);
@@ -246,6 +256,9 @@ static int action_format(int arg)
if (opt_integrity_legacy_padding)
crypt_set_compatibility(cd, CRYPT_COMPAT_LEGACY_INTEGRITY_PADDING);
+ if (opt_integrity_legacy_hmac)
+ crypt_set_compatibility(cd, CRYPT_COMPAT_LEGACY_INTEGRITY_HMAC);
+
r = crypt_format(cd, CRYPT_INTEGRITY, NULL, NULL, NULL, NULL, 0, ¶ms);
if (r < 0) /* FIXME: call wipe signatures again */
goto out;
@@ -278,14 +291,12 @@ static int action_open(int arg)
char *integrity_key = NULL;
int r;
- if (opt_integrity) {
- r = crypt_parse_hash_integrity_mode(opt_integrity, integrity);
+ r = crypt_parse_hash_integrity_mode(integrity_alg, integrity);
if (r < 0) {
log_err(_("No known integrity specification pattern detected."));
return r;
}
params.integrity = integrity;
- }
if (opt_journal_integrity) {
r = crypt_parse_hash_integrity_mode(opt_journal_integrity, journal_integrity);
@@ -313,7 +324,7 @@ static int action_open(int arg)
if (opt_integrity_bitmap)
activate_flags |= CRYPT_ACTIVATE_NO_JOURNAL_BITMAP;
- if (opt_integrity_recalculate)
+ if (opt_integrity_recalculate || opt_integrity_legacy_recalculate)
activate_flags |= CRYPT_ACTIVATE_RECALCULATE;
if (opt_allow_discards)
activate_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
@@ -329,6 +340,9 @@ static int action_open(int arg)
if (r)
goto out;
+ if (opt_integrity_legacy_recalculate)
+ crypt_set_compatibility(cd, CRYPT_COMPAT_LEGACY_INTEGRITY_RECALC);
+
r = crypt_activate_by_volume_key(cd, action_argv[1], integrity_key,
opt_integrity_key_size, activate_flags);
out:
@@ -506,10 +520,12 @@ static void help(poptContext popt_context,
log_std(_("\nDefault compiled-in dm-integrity parameters:\n"
"\tChecksum algorithm: %s\n"), DEFAULT_ALG_NAME);
+ tools_cleanup();
poptFreeContext(popt_context);
exit(EXIT_SUCCESS);
} else if (key->shortName == 'V') {
log_std("%s %s\n", PACKAGE_INTEGRITY, PACKAGE_VERSION);
+ tools_cleanup();
poptFreeContext(popt_context);
exit(EXIT_SUCCESS);
} else
@@ -576,6 +592,9 @@ int main(int argc, const char **argv)
{ "integrity-recalculate", '\0', POPT_ARG_NONE, &opt_integrity_recalculate, 0, N_("Recalculate initial tags automatically."), NULL },
{ "integrity-legacy-padding", '\0', POPT_ARG_NONE, &opt_integrity_legacy_padding, 0, N_("Use inefficient legacy padding (old kernels)"), NULL },
+ { "integrity-legacy-hmac", '\0', POPT_ARG_NONE, &opt_integrity_legacy_hmac, 0, N_("Do not protect superblock with HMAC (old kernels)"), NULL },
+ { "integrity-legacy-recalculate",'\0',POPT_ARG_NONE, &opt_integrity_legacy_recalculate, 0, N_("Allow recalculating of volumes with HMAC keys (old kernels)"), NULL },
+
{ "allow-discards", '\0', POPT_ARG_NONE, &opt_allow_discards, 0, N_("Allow discards (aka TRIM) requests for device"), NULL },
POPT_TABLEEND
};
@@ -629,6 +648,9 @@ int main(int argc, const char **argv)
aname = "close";
}
+ if (opt_integrity)
+ integrity_alg = opt_integrity;
+
for (action = action_types; action->type; action++)
if (strcmp(action->type, aname) == 0)
break;
@@ -679,9 +701,6 @@ int main(int argc, const char **argv)
(!opt_integrity_key_file && opt_integrity_key_size))
usage(popt_context, EXIT_FAILURE, _("Both key file and key size options must be specified."),
poptGetInvocationName(popt_context));
- if (!opt_integrity && opt_integrity_key_file)
- usage(popt_context, EXIT_FAILURE, _("Integrity algorithm must be specified if integrity key is used."),
- poptGetInvocationName(popt_context));
if ((opt_journal_integrity_key_file && !opt_journal_integrity_key_size) ||
(!opt_journal_integrity_key_file && opt_journal_integrity_key_size))
@@ -718,6 +737,7 @@ int main(int argc, const char **argv)
}
r = run_action(action);
+ tools_cleanup();
poptFreeContext(popt_context);
return r;
}
diff --git a/src/utils_password.c b/src/utils_password.c
index 55c1343f..dce73fa1 100644
--- a/src/utils_password.c
+++ b/src/utils_password.c
@@ -62,51 +62,86 @@ static int tools_check_pwquality(const char *password)
#elif defined ENABLE_PASSWDQC
#include <passwdqc.h>
-static int tools_check_pwquality(const char *password)
+static int tools_check_passwdqc(const char *password)
{
passwdqc_params_t params;
- char *parse_reason;
+ char *parse_reason = NULL;
const char *check_reason;
const char *config = PASSWDQC_CONFIG_FILE;
+ int r = -EINVAL;
passwdqc_params_reset(¶ms);
if (*config && passwdqc_params_load(¶ms, &parse_reason, config)) {
log_err(_("Cannot check password quality: %s"),
(parse_reason ? parse_reason : "Out of memory"));
- free(parse_reason);
- return -EINVAL;
+ goto out;
}
check_reason = passwdqc_check(¶ms.qc, password, NULL, NULL);
if (check_reason) {
log_err(_("Password quality check failed: Bad passphrase (%s)"),
check_reason);
- return -EPERM;
- }
-
- return 0;
+ r = -EPERM;
+ } else
+ r = 0;
+out:
+#if HAVE_PASSWDQC_PARAMS_FREE
+ passwdqc_params_free(¶ms);
+#endif
+ free(parse_reason);
+ return r;
}
-#else /* !(ENABLE_PWQUALITY || ENABLE_PASSWDQC) */
-static int tools_check_pwquality(const char *password)
+#endif /* ENABLE_PWQUALITY || ENABLE_PASSWDQC */
+
+/* coverity[ +tainted_string_sanitize_content : arg-0 ] */
+static int tools_check_password(const char *password)
{
+#if defined ENABLE_PWQUALITY
+ return tools_check_pwquality(password);
+#elif defined ENABLE_PASSWDQC
+ return tools_check_passwdqc(password);
+#else
return 0;
+#endif
}
-#endif /* ENABLE_PWQUALITY || ENABLE_PASSWDQC */
/* Password reading helpers */
+
+static ssize_t read_tty_eol(int fd, char *pass, size_t maxlen)
+{
+ bool eol = false;
+ size_t read_size = 0;
+ ssize_t r;
+
+ do {
+ r = read(fd, pass, maxlen - read_size);
+ if ((r == -1 && errno != EINTR) || quit)
+ return -1;
+ if (r >= 0) {
+ if (!r || pass[r-1] == '\n')
+ eol = true;
+ read_size += (size_t)r;
+ pass = pass + r;
+ }
+ } while (!eol && read_size != maxlen);
+
+ return (ssize_t)read_size;
+}
+
+/* The pass buffer is zeroed and has trailing \0 already " */
static int untimed_read(int fd, char *pass, size_t maxlen)
{
ssize_t i;
- i = read(fd, pass, maxlen);
+ i = read_tty_eol(fd, pass, maxlen);
if (i > 0) {
+ if (pass[i-1] == '\n')
pass[i-1] = '\0';
i = 0;
- } else if (i == 0) { /* EOF */
- *pass = 0;
+ } else if (i == 0) /* empty input */
i = -1;
- }
+
return i;
}
@@ -193,10 +228,9 @@ static int crypt_get_key_tty(const char *prompt,
log_err(_("Error reading passphrase from terminal."));
goto out_err;
}
- pass[key_size_max] = '\0';
if (verify) {
- pass_verify = crypt_safe_alloc(key_size_max);
+ pass_verify = crypt_safe_alloc(key_size_max + 1);
if (!pass_verify) {
log_err(_("Out of memory while reading passphrase."));
r = -ENOMEM;
@@ -276,7 +310,7 @@ int tools_get_key(const char *prompt,
/* Check pwquality for password (not keyfile) */
if (pwquality && !opt_force_password && !key_file && !r)
- r = tools_check_pwquality(*key);
+ r = tools_check_password(*key);
return r;
}
@@ -293,7 +327,7 @@ int tools_read_mk(const char *file, char **key, int keysize)
{
int fd;
- if (!keysize || !key)
+ if (keysize <= 0 || !key)
return -EINVAL;
*key = crypt_safe_alloc(keysize);
@@ -323,6 +357,9 @@ int tools_write_mk(const char *file, const char *key, int keysize)
{
int fd, r = -EINVAL;
+ if (keysize <= 0 || !key)
+ return -EINVAL;
+
fd = open(file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR);
if (fd < 0) {
log_err(_("Cannot open keyfile %s for write."), file);
diff --git a/src/utils_tools.c b/src/utils_tools.c
index 47bcfe12..32ff0b73 100644
--- a/src/utils_tools.c
+++ b/src/utils_tools.c
@@ -238,6 +238,7 @@ __attribute__ ((noreturn)) void usage(poptContext popt_context,
poptPrintUsage(popt_context, stderr, 0);
if (error)
log_err("%s: %s", more, error);
+ tools_cleanup();
poptFreeContext(popt_context);
exit(exitcode);
}
@@ -596,14 +597,6 @@ out:
return r;
}
-int tools_is_cipher_null(const char *cipher)
-{
- if (!cipher)
- return 0;
-
- return !strcmp(cipher, "cipher_null") ? 1 : 0;
-}
-
/*
* Keyfile - is standard input treated as a binary file (no EOL handling).
*/
diff --git a/src/veritysetup.c b/src/veritysetup.c
index fcc12a6b..92b8c5ea 100644
--- a/src/veritysetup.c
+++ b/src/veritysetup.c
@@ -23,29 +23,38 @@
#define PACKAGE_VERITY "veritysetup"
-static int use_superblock = 1;
-
-static const char *fec_device = NULL;
-static int fec_roots = DEFAULT_VERITY_FEC_ROOTS;
-static const char *hash_algorithm = NULL;
-static int hash_type = 1;
-static int data_block_size = DEFAULT_VERITY_DATA_BLOCK;
-static int hash_block_size = DEFAULT_VERITY_HASH_BLOCK;
+static char *opt_fec_device = NULL;
+static char *opt_hash_algorithm = NULL;
+static char *opt_salt = NULL;
+static char *opt_uuid = NULL;
+static char *opt_root_hash_signature = NULL;
+
+static int opt_use_superblock = 1;
+static int opt_fec_roots = DEFAULT_VERITY_FEC_ROOTS;
+static int opt_hash_type = 1;
+static int opt_data_block_size = DEFAULT_VERITY_DATA_BLOCK;
+static int opt_hash_block_size = DEFAULT_VERITY_HASH_BLOCK;
static uint64_t data_blocks = 0;
-static const char *salt_string = NULL;
static uint64_t hash_offset = 0;
static uint64_t fec_offset = 0;
-static const char *opt_uuid = NULL;
static int opt_restart_on_corruption = 0;
static int opt_panic_on_corruption = 0;
static int opt_ignore_corruption = 0;
static int opt_ignore_zero_blocks = 0;
static int opt_check_at_most_once = 0;
-static const char *opt_root_hash_signature = NULL;
static const char **action_argv;
static int action_argc;
+void tools_cleanup(void)
+{
+ FREE_AND_NULL(opt_fec_device);
+ FREE_AND_NULL(opt_hash_algorithm);
+ FREE_AND_NULL(opt_salt);
+ FREE_AND_NULL(opt_uuid);
+ FREE_AND_NULL(opt_root_hash_signature);
+}
+
static int _prepare_format(struct crypt_params_verity *params,
const char *data_device,
uint32_t flags)
@@ -53,16 +62,16 @@ static int _prepare_format(struct crypt_params_verity *params,
char *salt = NULL;
int len;
- params->hash_name = hash_algorithm ?: DEFAULT_VERITY_HASH;
+ params->hash_name = opt_hash_algorithm ?: DEFAULT_VERITY_HASH;
params->data_device = data_device;
- params->fec_device = fec_device;
- params->fec_roots = fec_roots;
+ params->fec_device = opt_fec_device;
+ params->fec_roots = opt_fec_roots;
- if (salt_string && !strcmp(salt_string, "-")) {
+ if (opt_salt && !strcmp(opt_salt, "-")) {
params->salt_size = 0;
params->salt = NULL;
- } else if (salt_string) {
- len = crypt_hex_to_bytes(salt_string, &salt, 0);
+ } else if (opt_salt) {
+ len = crypt_hex_to_bytes(opt_salt, &salt, 0);
if (len < 0) {
log_err(_("Invalid salt string specified."));
return -EINVAL;
@@ -74,12 +83,12 @@ static int _prepare_format(struct crypt_params_verity *params,
params->salt = NULL;
}
- params->data_block_size = data_block_size;
- params->hash_block_size = hash_block_size;
+ params->data_block_size = opt_data_block_size;
+ params->hash_block_size = opt_hash_block_size;
params->data_size = data_blocks;
params->hash_area_offset = hash_offset;
params->fec_area_offset = fec_offset;
- params->hash_type = hash_type;
+ params->hash_type = opt_hash_type;
params->flags = flags;
return 0;
@@ -102,13 +111,13 @@ static int action_format(int arg)
close(r);
}
/* Try to create FEC image if doesn't exist */
- if (fec_device) {
- r = open(fec_device, O_WRONLY | O_EXCL | O_CREAT, S_IRUSR | S_IWUSR);
+ if (opt_fec_device) {
+ r = open(opt_fec_device, O_WRONLY | O_EXCL | O_CREAT, S_IRUSR | S_IWUSR);
if (r < 0 && errno != EEXIST) {
- log_err(_("Cannot create FEC image %s for writing."), fec_device);
+ log_err(_("Cannot create FEC image %s for writing."), opt_fec_device);
return -EINVAL;
} else if (r >= 0) {
- log_dbg("Created FEC image %s.", fec_device);
+ log_dbg("Created FEC image %s.", opt_fec_device);
close(r);
}
}
@@ -116,7 +125,7 @@ static int action_format(int arg)
if ((r = crypt_init(&cd, action_argv[1])))
goto out;
- if (!use_superblock)
+ if (!opt_use_superblock)
flags |= CRYPT_VERITY_NO_HEADER;
r = _prepare_format(¶ms, action_argv[0], flags);
@@ -161,12 +170,12 @@ static int _activate(const char *dm_device,
if (opt_check_at_most_once)
activate_flags |= CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE;
- if (use_superblock) {
+ if (opt_use_superblock) {
params.flags = flags;
params.hash_area_offset = hash_offset;
params.fec_area_offset = fec_offset;
- params.fec_device = fec_device;
- params.fec_roots = fec_roots;
+ params.fec_device = opt_fec_device;
+ params.fec_roots = opt_fec_roots;
r = crypt_load(cd, CRYPT_VERITY, ¶ms);
} else {
r = _prepare_format(¶ms, data_device, flags | CRYPT_VERITY_NO_HEADER);
@@ -329,7 +338,7 @@ static int action_status(int arg)
if (vp.fec_device) {
log_std(" FEC device: %s\n", vp.fec_device);
- if ((backing_file = crypt_loop_backing_file(vp.fec_device))) {
+ if ((backing_file = crypt_loop_backing_file(opt_fec_device))) {
log_std(" FEC loop: %s\n", backing_file);
free(backing_file);
}
@@ -431,10 +440,12 @@ static void help(poptContext popt_context,
DEFAULT_VERITY_HASH, DEFAULT_VERITY_DATA_BLOCK,
DEFAULT_VERITY_HASH_BLOCK, DEFAULT_VERITY_SALT_SIZE,
1);
+ tools_cleanup();
poptFreeContext(popt_context);
exit(EXIT_SUCCESS);
} else if (key->shortName == 'V') {
log_std("%s %s\n", PACKAGE_VERITY, PACKAGE_VERSION);
+ tools_cleanup();
poptFreeContext(popt_context);
exit(EXIT_SUCCESS);
} else
@@ -455,7 +466,6 @@ static int run_action(struct action_type *action)
int main(int argc, const char **argv)
{
- static char *popt_tmp;
static const char *null_action_argv[] = {NULL};
static struct poptOption popt_help_options[] = {
{ NULL, '\0', POPT_ARG_CALLBACK, help, 0, NULL, NULL },
@@ -468,17 +478,17 @@ int main(int argc, const char **argv)
{ NULL, '\0', POPT_ARG_INCLUDE_TABLE, popt_help_options, 0, N_("Help options:"), NULL },
{ "verbose", 'v', POPT_ARG_NONE, &opt_verbose, 0, N_("Shows more detailed error messages"), NULL },
{ "debug", '\0', POPT_ARG_NONE, &opt_debug, 0, N_("Show debug messages"), NULL },
- { "no-superblock", 0, POPT_ARG_VAL, &use_superblock, 0, N_("Do not use verity superblock"), NULL },
- { "format", 0, POPT_ARG_INT, &hash_type, 0, N_("Format type (1 - normal, 0 - original Chrome OS)"), N_("number") },
- { "data-block-size", 0, POPT_ARG_INT, &data_block_size, 0, N_("Block size on the data device"), N_("bytes") },
- { "hash-block-size", 0, POPT_ARG_INT, &hash_block_size, 0, N_("Block size on the hash device"), N_("bytes") },
- { "fec-roots", 0, POPT_ARG_INT, &fec_roots, 0, N_("FEC parity bytes"), N_("bytes") },
- { "data-blocks", 0, POPT_ARG_STRING, &popt_tmp, 1, N_("The number of blocks in the data file"), N_("blocks") },
- { "fec-device", 0, POPT_ARG_STRING, &fec_device, 0, N_("Path to device with error correction data"), N_("path") },
- { "hash-offset", 0, POPT_ARG_STRING, &popt_tmp, 2, N_("Starting offset on the hash device"), N_("bytes") },
- { "fec-offset", 0, POPT_ARG_STRING, &popt_tmp, 3, N_("Starting offset on the FEC device"), N_("bytes") },
- { "hash", 'h', POPT_ARG_STRING, &hash_algorithm, 0, N_("Hash algorithm"), N_("string") },
- { "salt", 's', POPT_ARG_STRING, &salt_string, 0, N_("Salt"), N_("hex string") },
+ { "no-superblock", 0, POPT_ARG_VAL, &opt_use_superblock, 0, N_("Do not use verity superblock"), NULL },
+ { "format", 0, POPT_ARG_INT, &opt_hash_type, 0, N_("Format type (1 - normal, 0 - original Chrome OS)"), N_("number") },
+ { "data-block-size", 0, POPT_ARG_INT, &opt_data_block_size, 0, N_("Block size on the data device"), N_("bytes") },
+ { "hash-block-size", 0, POPT_ARG_INT, &opt_hash_block_size, 0, N_("Block size on the hash device"), N_("bytes") },
+ { "fec-roots", 0, POPT_ARG_INT, &opt_fec_roots, 0, N_("FEC parity bytes"), N_("bytes") },
+ { "data-blocks", 0, POPT_ARG_STRING, NULL, 1, N_("The number of blocks in the data file"), N_("blocks") },
+ { "fec-device", 0, POPT_ARG_STRING, &opt_fec_device, 0, N_("Path to device with error correction data"), N_("path") },
+ { "hash-offset", 0, POPT_ARG_STRING, NULL, 2, N_("Starting offset on the hash device"), N_("bytes") },
+ { "fec-offset", 0, POPT_ARG_STRING, NULL, 3, N_("Starting offset on the FEC device"), N_("bytes") },
+ { "hash", 'h', POPT_ARG_STRING, &opt_hash_algorithm, 0, N_("Hash algorithm"), N_("string") },
+ { "salt", 's', POPT_ARG_STRING, &opt_salt, 0, N_("Salt"), N_("hex string") },
{ "uuid", '\0', POPT_ARG_STRING, &opt_uuid, 0, N_("UUID for device to use"), NULL },
{ "root-hash-signature",'\0', POPT_ARG_STRING, &opt_root_hash_signature, 0, N_("Path to root hash signature file"), NULL },
{ "restart-on-corruption", 0,POPT_ARG_NONE,&opt_restart_on_corruption, 0, N_("Restart kernel if corruption is detected"), NULL },
@@ -506,15 +516,17 @@ int main(int argc, const char **argv)
while((r = poptGetNextOpt(popt_context)) > 0) {
unsigned long long ull_value;
- char *endp;
+ char *endp, *str = poptGetOptArg(popt_context);
errno = 0;
- ull_value = strtoull(popt_tmp, &endp, 10);
- if (*endp || !*popt_tmp || !isdigit(*popt_tmp) ||
+ ull_value = strtoull(str, &endp, 10);
+ if (*endp || !*str || !isdigit(*str) ||
(errno == ERANGE && ull_value == ULLONG_MAX) ||
(errno != 0 && ull_value == 0))
r = POPT_ERROR_BADNUMBER;
+ free(str);
+
switch(r) {
case 1:
data_blocks = ull_value;
@@ -577,7 +589,7 @@ int main(int argc, const char **argv)
poptGetInvocationName(popt_context));
}
- if (data_block_size < 0 || hash_block_size < 0 || hash_type < 0) {
+ if (opt_data_block_size < 0 || opt_hash_block_size < 0 || opt_hash_type < 0) {
usage(popt_context, EXIT_FAILURE,
_("Negative number for option not permitted."),
poptGetInvocationName(popt_context));
@@ -610,6 +622,7 @@ int main(int argc, const char **argv)
}
r = run_action(action);
+ tools_cleanup();
poptFreeContext(popt_context);
return r;
}
Attachment:
signature.asc
Description: PGP signature