From f34ce81f2501d6057a0c23f85fe9fdefb949b982 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Wed, 17 Jan 2018 22:07:23 +0100 Subject: [PATCH] Introduce new 64bit *keyfile_device_offset functions. The keyfile interface was designed, well, for keyfiles. Unfortunately, a keyfile can be placed on a device and the size_t offset can overflow. We have to introduce new set of fucntions that allows 64bit offsets even on 32bit systems: - crypt_resume_by_keyfile_device_offset - crypt_keyslot_add_by_keyfile_device_offset - crypt_activate_by_keyfile_device_offset - crypt_keyfile_device_read The new functions have added _device_ in name. Old functions are just internall wrappers around these. Also cryptsetup --keyfile-offset and --new-keyfile-offset must now process 64bit offsets. For more info see issue 359. --- configure.ac | 4 +- lib/libcryptsetup.h | 73 +++++++++++++++++++++++++----- lib/libcryptsetup.sym | 4 ++ lib/setup.c | 101 +++++++++++++++++++++++++++++------------- lib/utils.c | 37 +++++++++++----- src/cryptsetup.c | 31 +++++++------ src/cryptsetup.h | 2 +- src/utils_password.c | 10 +++-- tests/api-test.c | 6 ++- tests/compat-test | 9 ++++ 10 files changed, 202 insertions(+), 75 deletions(-) diff --git a/configure.ac b/configure.ac index 843d9e23..fc3a3eb2 100644 --- a/configure.ac +++ b/configure.ac @@ -1,9 +1,9 @@ AC_PREREQ([2.67]) -AC_INIT([cryptsetup],[2.0.0]) +AC_INIT([cryptsetup],[2.0.1-git]) dnl library version from ..[-] LIBCRYPTSETUP_VERSION=$(echo $PACKAGE_VERSION | cut -f1 -d-) -LIBCRYPTSETUP_VERSION_INFO=12:0:0 +LIBCRYPTSETUP_VERSION_INFO=13:0:1 AM_SILENT_RULES([yes]) AC_CONFIG_SRCDIR(src/cryptsetup.c) diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h index 41b1f891..d8329dae 100644 --- a/lib/libcryptsetup.h +++ b/lib/libcryptsetup.h @@ -696,14 +696,25 @@ int crypt_resume_by_passphrase(struct crypt_device *cd, * * @return unlocked key slot number or negative errno otherwise. */ +int crypt_resume_by_keyfile_device_offset(struct crypt_device *cd, + const char *name, + int keyslot, + const char *keyfile, + size_t keyfile_size, + uint64_t keyfile_offset); + +/** + * Backward compatible crypt_resume_by_keyfile_device_offset() (with size_t offset). + */ int crypt_resume_by_keyfile_offset(struct crypt_device *cd, const char *name, int keyslot, const char *keyfile, size_t keyfile_size, size_t keyfile_offset); + /** - * Backward compatible crypt_resume_by_keyfile_offset() (without offset). + * Backward compatible crypt_resume_by_keyfile_device_offset() (without offset). */ int crypt_resume_by_keyfile(struct crypt_device *cd, const char *name, @@ -785,6 +796,18 @@ int crypt_keyslot_change_by_passphrase(struct crypt_device *cd, * * @return allocated key slot number or negative errno otherwise. */ +int crypt_keyslot_add_by_keyfile_device_offset(struct crypt_device *cd, + int keyslot, + const char *keyfile, + size_t keyfile_size, + uint64_t keyfile_offset, + const char *new_keyfile, + size_t new_keyfile_size, + uint64_t new_keyfile_offset); + +/** + * Backward compatible crypt_keyslot_add_by_keyfile_device_offset() (with size_t offset). + */ int crypt_keyslot_add_by_keyfile_offset(struct crypt_device *cd, int keyslot, const char *keyfile, @@ -793,8 +816,9 @@ int crypt_keyslot_add_by_keyfile_offset(struct crypt_device *cd, const char *new_keyfile, size_t new_keyfile_size, size_t new_keyfile_offset); + /** - * Backward compatible crypt_keyslot_add_by_keyfile_offset() (without offset). + * Backward compatible crypt_keyslot_add_by_keyfile_device_offset() (without offset). */ int crypt_keyslot_add_by_keyfile(struct crypt_device *cd, int keyslot, @@ -1030,6 +1054,17 @@ int crypt_activate_by_passphrase(struct crypt_device *cd, * * @return unlocked key slot number or negative errno otherwise. */ +int crypt_activate_by_keyfile_device_offset(struct crypt_device *cd, + const char *name, + int keyslot, + const char *keyfile, + size_t keyfile_size, + uint64_t keyfile_offset, + uint32_t flags); + +/** + * Backward compatible crypt_activate_by_keyfile_device_offset() (with size_t offset). + */ int crypt_activate_by_keyfile_offset(struct crypt_device *cd, const char *name, int keyslot, @@ -1037,8 +1072,9 @@ int crypt_activate_by_keyfile_offset(struct crypt_device *cd, size_t keyfile_size, size_t keyfile_offset, uint32_t flags); + /** - * Backward compatible crypt_activate_by_keyfile_offset() (without offset). + * Backward compatible crypt_activate_by_keyfile_device_offset() (without offset). */ int crypt_activate_by_keyfile(struct crypt_device *cd, const char *name, @@ -1050,7 +1086,6 @@ int crypt_activate_by_keyfile(struct crypt_device *cd, /** * Activate device using provided volume key. * - * * @param cd crypt device handle * @param name name of device to create, if @e NULL only check volume key * @param volume_key provided volume key (or @e NULL to use internal) @@ -1077,7 +1112,6 @@ int crypt_activate_by_volume_key(struct crypt_device *cd, /** * Activate device using passphrase stored in kernel keyring. * - * * @param cd crypt device handle * @param name name of device to create, if @e NULL only check passphrase in keyring * @param key_description kernel keyring key description library should look @@ -1386,7 +1420,6 @@ typedef enum { /** * Get information about particular key slot. * - * * @param cd crypt device handle * @param keyslot requested keyslot to check or CRYPT_ANY_SLOT * @@ -1483,7 +1516,6 @@ int crypt_header_backup(struct crypt_device *cd, /** * Restore header and keyslots from backup file. * - * * @param cd crypt device handle * @param requested_type @link crypt-type @endlink or @e NULL for all known * @param backup_file file to restore header from @@ -1526,15 +1558,34 @@ void crypt_set_debug_level(int level); /** * Read keyfile * + * @param cd crypt device handle + * @param keyfile keyfile to read + * @param key buffer for key + * @param key_size_read size of read key + * @param keyfile_offset keyfile offset + * @param keyfile_size_max maximal size of keyfile to read + * @param flags keyfile read flags + * + * @return @e 0 on success or negative errno value otherwise. + */ +int crypt_keyfile_device_read(struct crypt_device *cd, + const char *keyfile, + char **key, size_t *key_size_read, + uint64_t keyfile_offset, + size_t keyfile_size_max, + uint32_t flags); + +/** + * Backward compatible crypt_keyfile_device_read() (with size_t offset). */ int crypt_keyfile_read(struct crypt_device *cd, const char *keyfile, char **key, size_t *key_size_read, size_t keyfile_offset, size_t keyfile_size_max, - uint32_t flags -); -/** No on-disk header (only hashes) */ + uint32_t flags); + +/** Read key only to the first end of line (\\n). */ #define CRYPT_KEYFILE_STOP_EOL (1 << 0) /** @} */ @@ -1600,7 +1651,7 @@ int crypt_wipe(struct crypt_device *cd, * @{ */ -/** iterate through all tokens */ +/** Iterate through all tokens */ #define CRYPT_ANY_TOKEN -1 /** diff --git a/lib/libcryptsetup.sym b/lib/libcryptsetup.sym index 60e8bac3..83e871be 100644 --- a/lib/libcryptsetup.sym +++ b/lib/libcryptsetup.sym @@ -22,12 +22,14 @@ CRYPTSETUP_2.0 { crypt_resume_by_passphrase; crypt_resume_by_keyfile; crypt_resume_by_keyfile_offset; + crypt_resume_by_keyfile_device_offset; crypt_free; crypt_keyslot_add_by_passphrase; crypt_keyslot_change_by_passphrase; crypt_keyslot_add_by_keyfile; crypt_keyslot_add_by_keyfile_offset; + crypt_keyslot_add_by_keyfile_device_offset; crypt_keyslot_add_by_volume_key; crypt_keyslot_add_by_key; @@ -49,6 +51,7 @@ CRYPTSETUP_2.0 { crypt_activate_by_passphrase; crypt_activate_by_keyfile; crypt_activate_by_keyfile_offset; + crypt_activate_by_keyfile_device_offset; crypt_activate_by_volume_key; crypt_activate_by_keyring; crypt_deactivate; @@ -92,6 +95,7 @@ CRYPTSETUP_2.0 { crypt_header_restore; crypt_keyfile_read; + crypt_keyfile_device_read; crypt_wipe; local: diff --git a/lib/setup.c b/lib/setup.c index f68d8a05..2181302f 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -2467,12 +2467,12 @@ out: return r < 0 ? r : keyslot; } -int crypt_resume_by_keyfile_offset(struct crypt_device *cd, - const char *name, - int keyslot, - const char *keyfile, - size_t keyfile_size, - size_t keyfile_offset) +int crypt_resume_by_keyfile_device_offset(struct crypt_device *cd, + const char *name, + int keyslot, + const char *keyfile, + size_t keyfile_size, + uint64_t keyfile_offset) { struct volume_key *vk = NULL; char *passphrase_read = NULL; @@ -2498,9 +2498,9 @@ int crypt_resume_by_keyfile_offset(struct crypt_device *cd, return -EINVAL; } - r = crypt_keyfile_read(cd, keyfile, - &passphrase_read, &passphrase_size_read, - keyfile_offset, keyfile_size, 0); + r = crypt_keyfile_device_read(cd, keyfile, + &passphrase_read, &passphrase_size_read, + keyfile_offset, keyfile_size, 0); if (r < 0) goto out; @@ -2537,10 +2537,21 @@ int crypt_resume_by_keyfile(struct crypt_device *cd, const char *keyfile, size_t keyfile_size) { - return crypt_resume_by_keyfile_offset(cd, name, keyslot, + return crypt_resume_by_keyfile_device_offset(cd, name, keyslot, keyfile, keyfile_size, 0); } +int crypt_resume_by_keyfile_offset(struct crypt_device *cd, + const char *name, + int keyslot, + const char *keyfile, + size_t keyfile_size, + size_t keyfile_offset) +{ + return crypt_resume_by_keyfile_device_offset(cd, name, keyslot, + keyfile, keyfile_size, keyfile_offset); +} + /* * Keyslot manipulation */ @@ -2726,14 +2737,14 @@ out: return keyslot_new; } -int crypt_keyslot_add_by_keyfile_offset(struct crypt_device *cd, +int crypt_keyslot_add_by_keyfile_device_offset(struct crypt_device *cd, int keyslot, const char *keyfile, size_t keyfile_size, - size_t keyfile_offset, + uint64_t keyfile_offset, const char *new_keyfile, size_t new_keyfile_size, - size_t new_keyfile_offset) + uint64_t new_keyfile_offset) { int digest, r, active_slots; size_t passwordLen, new_passwordLen; @@ -2767,7 +2778,7 @@ int crypt_keyslot_add_by_keyfile_offset(struct crypt_device *cd, return -EINVAL; } } else { - r = crypt_keyfile_read(cd, keyfile, + r = crypt_keyfile_device_read(cd, keyfile, &password, &passwordLen, keyfile_offset, keyfile_size, 0); if (r < 0) @@ -2783,7 +2794,7 @@ int crypt_keyslot_add_by_keyfile_offset(struct crypt_device *cd, if (r < 0) goto out; - r = crypt_keyfile_read(cd, new_keyfile, + r = crypt_keyfile_device_read(cd, new_keyfile, &new_password, &new_passwordLen, new_keyfile_offset, new_keyfile_size, 0); if (r < 0) @@ -2821,11 +2832,25 @@ int crypt_keyslot_add_by_keyfile(struct crypt_device *cd, const char *new_keyfile, size_t new_keyfile_size) { - return crypt_keyslot_add_by_keyfile_offset(cd, keyslot, + return crypt_keyslot_add_by_keyfile_device_offset(cd, keyslot, keyfile, keyfile_size, 0, new_keyfile, new_keyfile_size, 0); } +int crypt_keyslot_add_by_keyfile_offset(struct crypt_device *cd, + int keyslot, + const char *keyfile, + size_t keyfile_size, + size_t keyfile_offset, + const char *new_keyfile, + size_t new_keyfile_size, + size_t new_keyfile_offset) +{ + return crypt_keyslot_add_by_keyfile_device_offset(cd, keyslot, + keyfile, keyfile_size, keyfile_offset, + new_keyfile, new_keyfile_size, new_keyfile_offset); +} + int crypt_keyslot_add_by_volume_key(struct crypt_device *cd, int keyslot, const char *volume_key, @@ -3033,12 +3058,12 @@ int crypt_activate_by_passphrase(struct crypt_device *cd, return _activate_by_passphrase(cd, name, keyslot, passphrase, passphrase_size, flags); } -int crypt_activate_by_keyfile_offset(struct crypt_device *cd, +int crypt_activate_by_keyfile_device_offset(struct crypt_device *cd, const char *name, int keyslot, const char *keyfile, size_t keyfile_size, - size_t keyfile_offset, + uint64_t keyfile_offset, uint32_t flags) { struct volume_key *vk = NULL; @@ -3061,9 +3086,9 @@ int crypt_activate_by_keyfile_offset(struct crypt_device *cd, if (!name) return -EINVAL; - r = crypt_keyfile_read(cd, keyfile, - &passphrase_read, &passphrase_size_read, - keyfile_offset, keyfile_size, 0); + r = crypt_keyfile_device_read(cd, keyfile, + &passphrase_read, &passphrase_size_read, + keyfile_offset, keyfile_size, 0); if (r < 0) goto out; @@ -3075,9 +3100,9 @@ int crypt_activate_by_keyfile_offset(struct crypt_device *cd, r = PLAIN_activate(cd, name, vk, cd->u.plain.hdr.size, flags); } else if (isLUKS1(cd->type)) { - r = crypt_keyfile_read(cd, keyfile, - &passphrase_read, &passphrase_size_read, - keyfile_offset, keyfile_size, 0); + r = crypt_keyfile_device_read(cd, keyfile, + &passphrase_read, &passphrase_size_read, + keyfile_offset, keyfile_size, 0); if (r < 0) goto out; r = LUKS_open_key_with_hdr(keyslot, passphrase_read, @@ -3093,9 +3118,9 @@ int crypt_activate_by_keyfile_offset(struct crypt_device *cd, } r = keyslot; } else if (isLUKS2(cd->type)) { - r = crypt_keyfile_read(cd, keyfile, - &passphrase_read, &passphrase_size_read, - keyfile_offset, keyfile_size, 0); + r = crypt_keyfile_device_read(cd, keyfile, + &passphrase_read, &passphrase_size_read, + keyfile_offset, keyfile_size, 0); if (r < 0) goto out; @@ -3120,9 +3145,9 @@ int crypt_activate_by_keyfile_offset(struct crypt_device *cd, } r = keyslot; } else if (isLOOPAES(cd->type)) { - r = crypt_keyfile_read(cd, keyfile, - &passphrase_read, &passphrase_size_read, - keyfile_offset, keyfile_size, 0); + r = crypt_keyfile_device_read(cd, keyfile, + &passphrase_read, &passphrase_size_read, + keyfile_offset, keyfile_size, 0); if (r < 0) goto out; r = LOOPAES_parse_keyfile(cd, &vk, cd->u.loopaes.hdr.hash, &key_count, @@ -3152,8 +3177,20 @@ int crypt_activate_by_keyfile(struct crypt_device *cd, size_t keyfile_size, uint32_t flags) { - return crypt_activate_by_keyfile_offset(cd, name, keyslot, keyfile, - keyfile_size, 0, flags); + return crypt_activate_by_keyfile_device_offset(cd, name, keyslot, keyfile, + keyfile_size, 0, flags); +} + +int crypt_activate_by_keyfile_offset(struct crypt_device *cd, + const char *name, + int keyslot, + const char *keyfile, + size_t keyfile_size, + size_t keyfile_offset, + uint32_t flags) +{ + return crypt_activate_by_keyfile_device_offset(cd, name, keyslot, keyfile, + keyfile_size, keyfile_offset, flags); } int crypt_activate_by_volume_key(struct crypt_device *cd, diff --git a/lib/utils.c b/lib/utils.c index 5042ec05..ac0cfd37 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -359,28 +359,32 @@ int crypt_memlock_dec(struct crypt_device *ctx) * or when it reaches EOF before the requested number of bytes have been * discarded. */ -static int keyfile_seek(int fd, size_t bytes) +static int keyfile_seek(int fd, uint64_t bytes) { char tmp[BUFSIZ]; size_t next_read; ssize_t bytes_r; - off_t r; + off64_t r; - r = lseek(fd, bytes, SEEK_CUR); + r = lseek64(fd, bytes, SEEK_CUR); if (r > 0) return 0; if (r < 0 && errno != ESPIPE) return -1; + if (bytes > SIZE_MAX) + return -1; + while (bytes > 0) { /* figure out how much to read */ - next_read = bytes > sizeof(tmp) ? sizeof(tmp) : bytes; + next_read = bytes > sizeof(tmp) ? sizeof(tmp) : (size_t)bytes; bytes_r = read(fd, tmp, next_read); if (bytes_r < 0) { if (errno == EINTR) continue; + crypt_memzero(tmp, sizeof(tmp)); /* read error */ return -1; } @@ -392,18 +396,20 @@ static int keyfile_seek(int fd, size_t bytes) bytes -= bytes_r; } + crypt_memzero(tmp, sizeof(tmp)); return bytes == 0 ? 0 : -1; } -int crypt_keyfile_read(struct crypt_device *cd, const char *keyfile, - char **key, size_t *key_size_read, - size_t keyfile_offset, size_t keyfile_size_max, - uint32_t flags) +int crypt_keyfile_device_read(struct crypt_device *cd, const char *keyfile, + char **key, size_t *key_size_read, + uint64_t keyfile_offset, size_t keyfile_size_max, + uint32_t flags) { int fd, regular_file, char_to_read = 0, char_read = 0, unlimited_read = 0; int r = -EINVAL, newline; char *pass = NULL; - size_t buflen, i, file_read_size; + size_t buflen, i; + uint64_t file_read_size; struct stat st; if (!key || !key_size_read) @@ -441,7 +447,7 @@ int crypt_keyfile_read(struct crypt_device *cd, const char *keyfile, } if (S_ISREG(st.st_mode)) { regular_file = 1; - file_read_size = (size_t)st.st_size; + file_read_size = (uint64_t)st.st_size; if (keyfile_offset > file_read_size) { log_err(cd, _("Cannot seek to requested keyfile offset.\n")); @@ -450,7 +456,7 @@ int crypt_keyfile_read(struct crypt_device *cd, const char *keyfile, file_read_size -= keyfile_offset; /* known keyfile size, alloc it in one step */ - if (file_read_size >= keyfile_size_max) + if (file_read_size >= (uint64_t)keyfile_size_max) buflen = keyfile_size_max; else if (file_read_size) buflen = file_read_size; @@ -538,3 +544,12 @@ out_err: crypt_safe_free(pass); return r; } + +int crypt_keyfile_read(struct crypt_device *cd, const char *keyfile, + char **key, size_t *key_size_read, + size_t keyfile_offset, size_t keyfile_size_max, + uint32_t flags) +{ + return crypt_keyfile_device_read(cd, keyfile, key, key_size_read, + keyfile_offset, keyfile_size_max, flags); +} diff --git a/src/cryptsetup.c b/src/cryptsetup.c index 9cc537ba..28585a6e 100644 --- a/src/cryptsetup.c +++ b/src/cryptsetup.c @@ -41,8 +41,8 @@ static const char *opt_type = "luks"; static int opt_key_size = 0; static long opt_keyfile_size = 0; static long opt_new_keyfile_size = 0; -static long opt_keyfile_offset = 0; -static long opt_new_keyfile_offset = 0; +static uint64_t opt_keyfile_offset = 0; +static uint64_t opt_new_keyfile_offset = 0; static int opt_key_slot = CRYPT_ANY_SLOT; static int opt_token = CRYPT_ANY_TOKEN; static int opt_token_only = 0; @@ -220,7 +220,7 @@ static int action_open_plain(void) * The opt_keyfile_offset is applied always. */ key_size_max = params.hash ? (size_t)opt_keyfile_size : key_size; - r = crypt_activate_by_keyfile_offset(cd, action_argv[1], + r = crypt_activate_by_keyfile_device_offset(cd, action_argv[1], CRYPT_ANY_SLOT, opt_key_file, key_size_max, opt_keyfile_offset, activate_flags); } else { @@ -270,7 +270,7 @@ static int action_open_loopaes(void) if (r < 0) goto out; - r = crypt_activate_by_keyfile_offset(cd, action_argv[1], CRYPT_ANY_SLOT, + r = crypt_activate_by_keyfile_device_offset(cd, action_argv[1], CRYPT_ANY_SLOT, opt_key_file, opt_keyfile_size, opt_keyfile_offset, activate_flags); out: @@ -1150,7 +1150,7 @@ out: static int verify_keyslot(struct crypt_device *cd, int key_slot, char *msg_last, char *msg_pass, - const char *key_file, int keyfile_offset, + const char *key_file, uint64_t keyfile_offset, int keyfile_size) { crypt_keyslot_info ki; @@ -1335,7 +1335,7 @@ static int action_luksAddKey(void) password_new, password_new_size); } else if (opt_key_file && !tools_is_stdin(opt_key_file) && opt_new_key_file && !tools_is_stdin(opt_new_key_file)) { - r = crypt_keyslot_add_by_keyfile_offset(cd, opt_key_slot, + r = crypt_keyslot_add_by_keyfile_device_offset(cd, opt_key_slot, opt_key_file, opt_keyfile_size, opt_keyfile_offset, opt_new_key_file, opt_new_keyfile_size, opt_new_keyfile_offset); } else { @@ -2027,14 +2027,14 @@ 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, 5, N_("Read the key from a file."), NULL }, + { "key-file", 'd', POPT_ARG_STRING, &opt_key_file, 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_LONG, &opt_keyfile_offset, 0, N_("Number of bytes to skip in keyfile"), N_("bytes") }, + { "keyfile-offset", '\0', POPT_ARG_STRING, &popt_tmp, 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_LONG, &opt_new_keyfile_offset, 0, N_("Number of bytes to skip in 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") }, { "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") }, { "offset", 'o', POPT_ARG_STRING, &popt_tmp, 2, N_("The start offset in the backend device"), N_("SECTORS") }, @@ -2103,7 +2103,7 @@ int main(int argc, const char **argv) unsigned long long ull_value; char *endp, *kf; - if (r == 5) { + if (r == 6) { kf = poptGetOptArg(popt_context); if (tools_is_stdin(kf)) opt_keyfile_stdin = kf; @@ -2115,7 +2115,7 @@ int main(int argc, const char **argv) errno = 0; ull_value = strtoull(popt_tmp, &endp, 0); - if (*endp || !*popt_tmp || + if (*endp || !*popt_tmp || !isdigit(*popt_tmp) || (errno == ERANGE && ull_value == ULLONG_MAX) || (errno != 0 && ull_value == 0)) r = POPT_ERROR_BADNUMBER; @@ -2131,6 +2131,12 @@ int main(int argc, const char **argv) opt_skip = ull_value; opt_skip_valid = 1; break; + case 4: + opt_keyfile_offset = ull_value; + break; + case 5: + opt_new_keyfile_offset = ull_value; + break; } if (r < 0) @@ -2283,8 +2289,7 @@ int main(int argc, const char **argv) opt_key_file = action_argv[1]; } - if (opt_keyfile_size < 0 || opt_new_keyfile_size < 0 || opt_key_size < 0 || - opt_keyfile_offset < 0 || opt_new_keyfile_offset < 0) + if (opt_keyfile_size < 0 || opt_new_keyfile_size < 0 || opt_key_size < 0) usage(popt_context, EXIT_FAILURE, _("Negative number for option not permitted."), poptGetInvocationName(popt_context)); diff --git a/src/cryptsetup.h b/src/cryptsetup.h index 40bc050a..765f1b1a 100644 --- a/src/cryptsetup.h +++ b/src/cryptsetup.h @@ -83,7 +83,7 @@ int tools_signals_blocked(void); int tools_get_key(const char *prompt, char **key, size_t *key_size, - size_t keyfile_offset, size_t keyfile_size_max, + uint64_t keyfile_offset, size_t keyfile_size_max, const char *key_file, int timeout, int verify, int pwquality, struct crypt_device *cd); diff --git a/src/utils_password.c b/src/utils_password.c index e8c17eb6..4a59bf30 100644 --- a/src/utils_password.c +++ b/src/utils_password.c @@ -251,7 +251,7 @@ out_err: */ int tools_get_key(const char *prompt, char **key, size_t *key_size, - size_t keyfile_offset, size_t keyfile_size_max, + uint64_t keyfile_offset, size_t keyfile_size_max, const char *key_file, int timeout, int verify, int pwquality, struct crypt_device *cd) @@ -278,12 +278,14 @@ int tools_get_key(const char *prompt, } else { log_dbg("STDIN descriptor passphrase entry requested."); /* No keyfile means STDIN with EOL handling (\n will end input)). */ - r = crypt_keyfile_read(cd, NULL, key, key_size, keyfile_offset, keyfile_size_max, - key_file ? 0 : CRYPT_KEYFILE_STOP_EOL); + r = crypt_keyfile_device_read(cd, NULL, key, key_size, + keyfile_offset, keyfile_size_max, + key_file ? 0 : CRYPT_KEYFILE_STOP_EOL); } } else { log_dbg("File descriptor passphrase entry requested."); - r = crypt_keyfile_read(cd, key_file, key, key_size, keyfile_offset, keyfile_size_max, 0); + r = crypt_keyfile_device_read(cd, key_file, key, key_size, + keyfile_offset, keyfile_size_max, 0); } if (block && !quit) diff --git a/tests/api-test.c b/tests/api-test.c index 6fa72656..f3d550a8 100644 --- a/tests/api-test.c +++ b/tests/api-test.c @@ -567,8 +567,11 @@ static void AddDevicePlain(void) EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); OK_(crypt_deactivate(cd, CDEVICE_1)); FAIL_(crypt_activate_by_keyfile_offset(cd, NULL, CRYPT_ANY_SLOT, KEYFILE1, 0, strlen(KEY1) + 1, 0), "cannot seek"); + FAIL_(crypt_activate_by_keyfile_device_offset(cd, NULL, CRYPT_ANY_SLOT, KEYFILE1, 0, strlen(KEY1) + 1, 0), "cannot seek"); EQ_(0, crypt_activate_by_keyfile_offset(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, 0, 0, 0)); OK_(crypt_deactivate(cd, CDEVICE_1)); + EQ_(0, crypt_activate_by_keyfile_device_offset(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, 0, 0, 0)); + OK_(crypt_deactivate(cd, CDEVICE_1)); _remove_keyfiles(); crypt_free(cd); @@ -689,7 +692,8 @@ static void SuspendDevice(void) OK_(crypt_suspend(cd, CDEVICE_1)); FAIL_(crypt_resume_by_keyfile(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1 "blah", 0), "wrong keyfile"); FAIL_(crypt_resume_by_keyfile_offset(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, 1, 0), "wrong key"); - OK_(crypt_resume_by_keyfile_offset(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, 0, 0)); + FAIL_(crypt_resume_by_keyfile_device_offset(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, 1, 0), "wrong key"); + OK_(crypt_resume_by_keyfile_device_offset(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, 0, 0)); FAIL_(crypt_resume_by_keyfile(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEYFILE1, 0), "not suspended"); OK_(crypt_deactivate(cd, CDEVICE_1)); crypt_free(cd); diff --git a/tests/compat-test b/tests/compat-test index 0e107bf9..657aeae2 100755 --- a/tests/compat-test +++ b/tests/compat-test @@ -588,6 +588,15 @@ $CRYPTSETUP luksClose $DEV_NAME || fail $CRYPTSETUP luksChangeKey $LOOPDEV $FAST_PBKDF_OPT -d $KEY2 --keyfile-offset 1 $KEY2 --new-keyfile-offset 0 || fail $CRYPTSETUP luksOpen -d $KEY2 $LOOPDEV $DEV_NAME || fail $CRYPTSETUP luksClose $DEV_NAME || fail +# large device with keyfile +echo -e '0 10000000 error'\\n'10000000 1000000 zero' | dmsetup create $DEV_NAME2 || fail +$CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT $LOOPDEV /dev/mapper/$DEV_NAME2 -l 13 --keyfile-offset 5120000000 || fail +$CRYPTSETUP --key-file=/dev/mapper/$DEV_NAME2 -l 13 --keyfile-offset 5119999999 luksOpen $LOOPDEV $DEV_NAME 2>/dev/null && fail +$CRYPTSETUP --key-file=/dev/mapper/$DEV_NAME2 -l 13 --keyfile-offset 5120000000 luksOpen $LOOPDEV $DEV_NAME || fail +$CRYPTSETUP luksClose $DEV_NAME || fail +$CRYPTSETUP luksChangeKey $LOOPDEV $FAST_PBKDF_OPT -d /dev/mapper/$DEV_NAME2 \ + --keyfile-offset 5120000000 -l 13 /dev/mapper/$DEV_NAME2 --new-keyfile-offset 5120000001 --new-keyfile-size 15 || fail +dmsetup remove $DEV_NAME2 prepare "[25] Create shared segments" wipe echo $PWD1 | $CRYPTSETUP create $DEV_NAME $LOOPDEV --hash sha1 --offset 0 --size 256 || fail