"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "lib/setup.c" between
cryptsetup-2.3.6.tar.xz and cryptsetup-2.4.0.tar.xz

About: cryptsetup is a utility used to conveniently setup disk encryption based on the dm-crypt kernel module. These include plain dm-crypt volumes, LUKS volumes, loop-AES and TrueCrypt compatible format.

setup.c  (cryptsetup-2.3.6.tar.xz):setup.c  (cryptsetup-2.4.0.tar.xz)
skipping to change at line 32 skipping to change at line 32
*/ */
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <sys/utsname.h> #include <sys/utsname.h>
#include <errno.h> #include <errno.h>
#include "libcryptsetup.h" #include "libcryptsetup.h"
#include "luks.h" #include "luks1/luks.h"
#include "luks2.h" #include "luks2/luks2.h"
#include "loopaes.h" #include "loopaes/loopaes.h"
#include "verity.h" #include "verity/verity.h"
#include "tcrypt.h" #include "tcrypt/tcrypt.h"
#include "integrity.h" #include "integrity/integrity.h"
#include "bitlk.h" #include "bitlk/bitlk.h"
#include "utils_device_locking.h" #include "utils_device_locking.h"
#include "internal.h" #include "internal.h"
#define CRYPT_CD_UNRESTRICTED (1 << 0) #define CRYPT_CD_UNRESTRICTED (1 << 0)
#define CRYPT_CD_QUIET (1 << 1) #define CRYPT_CD_QUIET (1 << 1)
struct crypt_device { struct crypt_device {
char *type; char *type;
struct device *device; struct device *device;
skipping to change at line 67 skipping to change at line 67
unsigned key_in_keyring:1; unsigned key_in_keyring:1;
uint64_t data_offset; uint64_t data_offset;
uint64_t metadata_size; /* Used in LUKS2 format */ uint64_t metadata_size; /* Used in LUKS2 format */
uint64_t keyslots_size; /* Used in LUKS2 format */ uint64_t keyslots_size; /* Used in LUKS2 format */
/* Workaround for OOM during parallel activation (like in systemd) */ /* Workaround for OOM during parallel activation (like in systemd) */
bool memory_hard_pbkdf_lock_enabled; bool memory_hard_pbkdf_lock_enabled;
struct crypt_lock_handle *pbkdf_memory_hard_lock; struct crypt_lock_handle *pbkdf_memory_hard_lock;
// FIXME: private binary headers and access it properly
// through sub-library (LUKS1, TCRYPT)
union { union {
struct { /* used in CRYPT_LUKS1 */ struct { /* used in CRYPT_LUKS1 */
struct luks_phdr hdr; struct luks_phdr hdr;
char *cipher_spec; char *cipher_spec;
} luks1; } luks1;
struct { /* used in CRYPT_LUKS2 */ struct { /* used in CRYPT_LUKS2 */
struct luks2_hdr hdr; struct luks2_hdr hdr;
char cipher[MAX_CIPHER_LEN]; /* only for compatibility */ char cipher[MAX_CIPHER_LEN]; /* only for compatibility */
char cipher_mode[MAX_CIPHER_LEN]; /* only for compatibility */ char cipher_mode[MAX_CIPHER_LEN]; /* only for compatibility */
char *keyslot_cipher; char *keyslot_cipher;
unsigned int keyslot_key_size; unsigned int keyslot_key_size;
struct luks2_reenc_context *rh; struct luks2_reencrypt *rh;
} luks2; } luks2;
struct { /* used in CRYPT_PLAIN */ struct { /* used in CRYPT_PLAIN */
struct crypt_params_plain hdr; struct crypt_params_plain hdr;
char *cipher_spec; char *cipher_spec;
char *cipher; char *cipher;
const char *cipher_mode; const char *cipher_mode;
unsigned int key_size; unsigned int key_size;
} plain; } plain;
struct { /* used in CRYPT_LOOPAES */ struct { /* used in CRYPT_LOOPAES */
struct crypt_params_loopaes hdr; struct crypt_params_loopaes hdr;
skipping to change at line 140 skipping to change at line 137
void *log_usrptr; void *log_usrptr;
int (*confirm)(const char *msg, void *usrptr); int (*confirm)(const char *msg, void *usrptr);
void *confirm_usrptr; void *confirm_usrptr;
}; };
/* Just to suppress redundant messages about crypto backend */ /* Just to suppress redundant messages about crypto backend */
static int _crypto_logged = 0; static int _crypto_logged = 0;
/* Log helper */ /* Log helper */
static void (*_default_log)(int level, const char *msg, void *usrptr) = NULL; static void (*_default_log)(int level, const char *msg, void *usrptr) = NULL;
static void *_default_log_usrptr = NULL;
static int _debug_level = 0; static int _debug_level = 0;
/* Library can do metadata locking */ /* Library can do metadata locking */
static int _metadata_locking = 1; static int _metadata_locking = 1;
/* Library scope detection for kernel keyring support */ /* Library scope detection for kernel keyring support */
static int _kernel_keyring_supported; static int _kernel_keyring_supported;
/* Library allowed to use kernel keyring for loading VK in kernel crypto layer * / /* Library allowed to use kernel keyring for loading VK in kernel crypto layer * /
static int _vk_via_keyring = 1; static int _vk_via_keyring = 1;
skipping to change at line 172 skipping to change at line 170
{ {
if (!msg) if (!msg)
return; return;
if (level < _debug_level) if (level < _debug_level)
return; return;
if (cd && cd->log) if (cd && cd->log)
cd->log(level, msg, cd->log_usrptr); cd->log(level, msg, cd->log_usrptr);
else if (_default_log) else if (_default_log)
_default_log(level, msg, NULL); _default_log(level, msg, _default_log_usrptr);
/* Default to stdout/stderr if there is no callback. */ /* Default to stdout/stderr if there is no callback. */
else else
fprintf(level == CRYPT_LOG_ERROR ? stderr : stdout, "%s", msg); fprintf(level == CRYPT_LOG_ERROR ? stderr : stdout, "%s", msg);
} }
__attribute__((format(printf, 5, 6))) __attribute__((format(printf, 3, 4)))
void logger(struct crypt_device *cd, int level, const char *file, void crypt_logf(struct crypt_device *cd, int level, const char *format, ...)
int line, const char *format, ...)
{ {
va_list argp; va_list argp;
char target[LOG_MAX_LEN + 2]; char target[LOG_MAX_LEN + 2];
int len; int len;
va_start(argp, format); va_start(argp, format);
len = vsnprintf(&target[0], LOG_MAX_LEN, format, argp); len = vsnprintf(&target[0], LOG_MAX_LEN, format, argp);
if (len > 0 && len < LOG_MAX_LEN) { if (len > 0 && len < LOG_MAX_LEN) {
/* All verbose and error messages in tools end with EOL. */ /* All verbose and error messages in tools end with EOL. */
skipping to change at line 421 skipping to change at line 418
/* keyslot helpers */ /* keyslot helpers */
static int keyslot_verify_or_find_empty(struct crypt_device *cd, int *keyslot) static int keyslot_verify_or_find_empty(struct crypt_device *cd, int *keyslot)
{ {
crypt_keyslot_info ki; crypt_keyslot_info ki;
if (*keyslot == CRYPT_ANY_SLOT) { if (*keyslot == CRYPT_ANY_SLOT) {
if (isLUKS1(cd->type)) if (isLUKS1(cd->type))
*keyslot = LUKS_keyslot_find_empty(&cd->u.luks1.hdr); *keyslot = LUKS_keyslot_find_empty(&cd->u.luks1.hdr);
else else
*keyslot = LUKS2_keyslot_find_empty(&cd->u.luks2.hdr); *keyslot = LUKS2_keyslot_find_empty(cd, &cd->u.luks2.hdr, 0);
if (*keyslot < 0) { if (*keyslot < 0) {
log_err(cd, _("All key slots full.")); log_err(cd, _("All key slots full."));
return -EINVAL; return -EINVAL;
} }
} }
if (isLUKS1(cd->type)) if (isLUKS1(cd->type))
ki = LUKS_keyslot_info(&cd->u.luks1.hdr, *keyslot); ki = LUKS_keyslot_info(&cd->u.luks1.hdr, *keyslot);
else else
ki = LUKS2_keyslot_info(&cd->u.luks2.hdr, *keyslot); ki = LUKS2_keyslot_info(&cd->u.luks2.hdr, *keyslot);
switch (ki) { switch (ki) {
case CRYPT_SLOT_INVALID: case CRYPT_SLOT_INVALID:
log_err(cd, _("Key slot %d is invalid, please select betw een 0 and %d."), log_err(cd, _("Key slot %d is invalid, please select betw een 0 and %d."),
*keyslot, LUKS_NUMKEYS - 1); *keyslot, crypt_keyslot_max(cd->type) - 1);
return -EINVAL; return -EINVAL;
case CRYPT_SLOT_INACTIVE: case CRYPT_SLOT_INACTIVE:
break; break;
default: default:
log_err(cd, _("Key slot %d is full, please select another one."), log_err(cd, _("Key slot %d is full, please select another one."),
*keyslot); *keyslot);
return -EINVAL; return -EINVAL;
} }
log_dbg(cd, "Selected keyslot %d.", *keyslot); log_dbg(cd, "Selected keyslot %d.", *keyslot);
skipping to change at line 554 skipping to change at line 551
if (!cd || !cd->confirm) if (!cd || !cd->confirm)
return 1; return 1;
else else
return cd->confirm(msg, cd->confirm_usrptr); return cd->confirm(msg, cd->confirm_usrptr);
} }
void crypt_set_log_callback(struct crypt_device *cd, void crypt_set_log_callback(struct crypt_device *cd,
void (*log)(int level, const char *msg, void *usrptr), void (*log)(int level, const char *msg, void *usrptr),
void *usrptr) void *usrptr)
{ {
if (!cd) if (!cd) {
_default_log = log; _default_log = log;
else { _default_log_usrptr = usrptr;
} else {
cd->log = log; cd->log = log;
cd->log_usrptr = usrptr; cd->log_usrptr = usrptr;
} }
} }
void crypt_set_confirm_callback(struct crypt_device *cd, void crypt_set_confirm_callback(struct crypt_device *cd,
int (*confirm)(const char *msg, void *usrptr), int (*confirm)(const char *msg, void *usrptr),
void *usrptr) void *usrptr)
{ {
if (cd) { if (cd) {
skipping to change at line 596 skipping to change at line 594
#if !HAVE_DECL_O_CLOEXEC #if !HAVE_DECL_O_CLOEXEC
log_dbg(NULL, "Running without O_CLOEXEC."); log_dbg(NULL, "Running without O_CLOEXEC.");
#endif #endif
if (!(h = malloc(sizeof(struct crypt_device)))) if (!(h = malloc(sizeof(struct crypt_device))))
return -ENOMEM; return -ENOMEM;
memset(h, 0, sizeof(*h)); memset(h, 0, sizeof(*h));
r = device_alloc(NULL, &h->device, device); r = device_alloc(NULL, &h->device, device);
if (r < 0) if (r < 0) {
goto bad; free(h);
return r;
}
dm_backend_init(NULL); dm_backend_init(NULL);
h->rng_type = crypt_random_default_key_rng(); h->rng_type = crypt_random_default_key_rng();
*cd = h; *cd = h;
return 0; return 0;
bad:
device_free(NULL, h->device);
free(h);
return r;
} }
static int crypt_check_data_device_size(struct crypt_device *cd) static int crypt_check_data_device_size(struct crypt_device *cd)
{ {
int r; int r;
uint64_t size, size_min; uint64_t size, size_min;
/* Check data device size, require at least header or one sector */ /* Check data device size, require at least header or one sector */
size_min = crypt_get_data_offset(cd) << SECTOR_SHIFT ?: SECTOR_SIZE; size_min = crypt_get_data_offset(cd) << SECTOR_SHIFT ?: SECTOR_SIZE;
skipping to change at line 648 skipping to change at line 644
if (r < 0) if (r < 0)
return r; return r;
if (!cd->metadata_device) { if (!cd->metadata_device) {
cd->metadata_device = cd->device; cd->metadata_device = cd->device;
} else } else
device_free(cd, cd->device); device_free(cd, cd->device);
cd->device = dev; cd->device = dev;
return crypt_check_data_device_size(cd); r = crypt_check_data_device_size(cd);
if (!r && isLUKS2(cd->type))
device_set_block_size(crypt_data_device(cd), LUKS2_get_sector_siz
e(&cd->u.luks2.hdr));
return r;
} }
int crypt_set_data_device(struct crypt_device *cd, const char *device) int crypt_set_data_device(struct crypt_device *cd, const char *device)
{ {
/* metadata device must be set */ /* metadata device must be set */
if (!cd || !cd->device || !device) if (!cd || !cd->device || !device)
return -EINVAL; return -EINVAL;
log_dbg(cd, "Setting ciphertext data device to %s.", device ?: "(none)"); log_dbg(cd, "Setting ciphertext data device to %s.", device ?: "(none)");
if (!isLUKS1(cd->type) && !isLUKS2(cd->type) && !isVERITY(cd->type) && if (!isLUKS1(cd->type) && !isLUKS2(cd->type) && !isVERITY(cd->type) &&
!isINTEGRITY(cd->type) && !isTCRYPT(cd->type)) { !isINTEGRITY(cd->type) && !isTCRYPT(cd->type)) {
log_err(cd, _("This operation is not supported for this device ty pe.")); log_err(cd, _("This operation is not supported for this device ty pe."));
return -EINVAL; return -EINVAL;
} }
if (isLUKS2(cd->type) && crypt_get_reenc_context(cd)) { if (isLUKS2(cd->type) && crypt_get_luks2_reencrypt(cd)) {
log_err(cd, _("Illegal operation with reencryption in-progress.") ); log_err(cd, _("Illegal operation with reencryption in-progress.") );
return -EINVAL; return -EINVAL;
} }
return _crypt_set_data_device(cd, device); return _crypt_set_data_device(cd, device);
} }
int crypt_init_data_device(struct crypt_device **cd, const char *device, const c har *data_device) int crypt_init_data_device(struct crypt_device **cd, const char *device, const c har *data_device)
{ {
int r; int r;
skipping to change at line 775 skipping to change at line 775
version = LUKS2_hdr_version_unlocked(cd, NULL); version = LUKS2_hdr_version_unlocked(cd, NULL);
if ((isLUKS1(requested_type) && version == 2) || if ((isLUKS1(requested_type) && version == 2) ||
(isLUKS2(requested_type) && version == 1)) (isLUKS2(requested_type) && version == 1))
return -EINVAL; return -EINVAL;
if (requested_type) if (requested_type)
version = 0; version = 0;
if (isLUKS1(requested_type) || version == 1) { if (isLUKS1(requested_type) || version == 1) {
if (cd->type && isLUKS2(cd->type)) { if (isLUKS2(cd->type)) {
log_dbg(cd, "Context is already initialized to type %s", cd->type); log_dbg(cd, "Context is already initialized to type %s", cd->type);
return -EINVAL; return -EINVAL;
} }
if (verify_pbkdf_params(cd, &cd->pbkdf)) { if (verify_pbkdf_params(cd, &cd->pbkdf)) {
r = init_pbkdf_type(cd, NULL, CRYPT_LUKS1); r = init_pbkdf_type(cd, NULL, CRYPT_LUKS1);
if (r) if (r)
return r; return r;
} }
skipping to change at line 815 skipping to change at line 815
if (asprintf(&cipher_spec, "%s-%s", hdr.cipherName, hdr.cipherMod e) < 0) { if (asprintf(&cipher_spec, "%s-%s", hdr.cipherName, hdr.cipherMod e) < 0) {
r = -ENOMEM; r = -ENOMEM;
goto out; goto out;
} }
free(cd->u.luks1.cipher_spec); free(cd->u.luks1.cipher_spec);
cd->u.luks1.cipher_spec = cipher_spec; cd->u.luks1.cipher_spec = cipher_spec;
memcpy(&cd->u.luks1.hdr, &hdr, sizeof(hdr)); memcpy(&cd->u.luks1.hdr, &hdr, sizeof(hdr));
} else if (isLUKS2(requested_type) || version == 2 || version == 0) { } else if (isLUKS2(requested_type) || version == 2 || version == 0) {
if (cd->type && isLUKS1(cd->type)) { if (isLUKS1(cd->type)) {
log_dbg(cd, "Context is already initialized to type %s", cd->type); log_dbg(cd, "Context is already initialized to type %s", cd->type);
return -EINVAL; return -EINVAL;
} }
/* /*
* Current LUKS2 repair just overrides blkid probes * Current LUKS2 repair just overrides blkid probes
* and perform auto-recovery if possible. This is safe * and perform auto-recovery if possible. This is safe
* unless future LUKS2 repair code do something more * unless future LUKS2 repair code do something more
* sophisticated. In such case we would need to check * sophisticated. In such case we would need to check
* for LUKS2 requirements and decide if it's safe to * for LUKS2 requirements and decide if it's safe to
* perform repair. * perform repair.
*/ */
r = _crypt_load_luks2(cd, cd->type != NULL, repair); r = _crypt_load_luks2(cd, cd->type != NULL, repair);
if (!r)
device_set_block_size(crypt_data_device(cd), LUKS2_get_se
ctor_size(&cd->u.luks2.hdr));
} else { } else {
if (version > 2) if (version > 2)
log_err(cd, _("Unsupported LUKS version %d."), version); log_err(cd, _("Unsupported LUKS version %d."), version);
r = -EINVAL; r = -EINVAL;
} }
out: out:
crypt_safe_memzero(&hdr, sizeof(hdr)); crypt_safe_memzero(&hdr, sizeof(hdr));
return r; return r;
} }
skipping to change at line 889 skipping to change at line 891
if (params && params->flags & CRYPT_VERITY_NO_HEADER) if (params && params->flags & CRYPT_VERITY_NO_HEADER)
return -EINVAL; return -EINVAL;
if (params) if (params)
sb_offset = params->hash_area_offset; sb_offset = params->hash_area_offset;
r = VERITY_read_sb(cd, sb_offset, &cd->u.verity.uuid, &cd->u.verity.hdr); r = VERITY_read_sb(cd, sb_offset, &cd->u.verity.uuid, &cd->u.verity.hdr);
if (r < 0) if (r < 0)
return r; return r;
//FIXME: use crypt_free
if (!cd->type && !(cd->type = strdup(CRYPT_VERITY))) { if (!cd->type && !(cd->type = strdup(CRYPT_VERITY))) {
free(CONST_CAST(void*)cd->u.verity.hdr.hash_name); free(CONST_CAST(void*)cd->u.verity.hdr.hash_name);
free(CONST_CAST(void*)cd->u.verity.hdr.salt); free(CONST_CAST(void*)cd->u.verity.hdr.salt);
free(cd->u.verity.uuid); free(cd->u.verity.uuid);
crypt_safe_memzero(&cd->u.verity.hdr, sizeof(cd->u.verity.hdr)); crypt_safe_memzero(&cd->u.verity.hdr, sizeof(cd->u.verity.hdr));
return -ENOMEM; return -ENOMEM;
} }
if (params) if (params)
cd->u.verity.hdr.flags = params->flags; cd->u.verity.hdr.flags = params->flags;
skipping to change at line 974 skipping to change at line 975
if (!cd->type && !(cd->type = strdup(CRYPT_INTEGRITY))) { if (!cd->type && !(cd->type = strdup(CRYPT_INTEGRITY))) {
free(CONST_CAST(void*)cd->u.integrity.params.integrity); free(CONST_CAST(void*)cd->u.integrity.params.integrity);
return -ENOMEM; return -ENOMEM;
} }
return 0; return 0;
} }
static int _crypt_load_bitlk(struct crypt_device *cd, static int _crypt_load_bitlk(struct crypt_device *cd,
struct bitlk_metadata *params) struct bitlk_metadata *params __attribute__((unused) ))
{ {
int r; int r;
r = init_crypto(cd); r = init_crypto(cd);
if (r < 0) if (r < 0)
return r; return r;
r = BITLK_read_sb(cd, &cd->u.bitlk.params); r = BITLK_read_sb(cd, &cd->u.bitlk.params);
if (r < 0) if (r < 0)
return r; return r;
if (asprintf(&cd->u.bitlk.cipher_spec, "%s-%s", if (asprintf(&cd->u.bitlk.cipher_spec, "%s-%s",
cd->u.bitlk.params.cipher, cd->u.bitlk.params.cipher_mode) < 0) { cd->u.bitlk.params.cipher, cd->u.bitlk.params.cipher_mode) < 0) {
cd->u.bitlk.cipher_spec = NULL; cd->u.bitlk.cipher_spec = NULL;
return -ENOMEM; return -ENOMEM;
} }
if (!cd->type && !(cd->type = strdup(CRYPT_BITLK))) if (!cd->type && !(cd->type = strdup(CRYPT_BITLK)))
return -ENOMEM; return -ENOMEM;
device_set_block_size(crypt_data_device(cd), cd->u.bitlk.params.sector_si
ze);
return 0; return 0;
} }
int crypt_load(struct crypt_device *cd, int crypt_load(struct crypt_device *cd,
const char *requested_type, const char *requested_type,
void *params) void *params)
{ {
int r; int r;
if (!cd) if (!cd)
skipping to change at line 1115 skipping to change at line 1118
return NULL; return NULL;
} }
static void crypt_free_type(struct crypt_device *cd) static void crypt_free_type(struct crypt_device *cd)
{ {
if (isPLAIN(cd->type)) { if (isPLAIN(cd->type)) {
free(CONST_CAST(void*)cd->u.plain.hdr.hash); free(CONST_CAST(void*)cd->u.plain.hdr.hash);
free(cd->u.plain.cipher); free(cd->u.plain.cipher);
free(cd->u.plain.cipher_spec); free(cd->u.plain.cipher_spec);
} else if (isLUKS2(cd->type)) { } else if (isLUKS2(cd->type)) {
LUKS2_reenc_context_free(cd, cd->u.luks2.rh); LUKS2_reencrypt_free(cd, cd->u.luks2.rh);
LUKS2_hdr_free(cd, &cd->u.luks2.hdr); LUKS2_hdr_free(cd, &cd->u.luks2.hdr);
free(cd->u.luks2.keyslot_cipher); free(cd->u.luks2.keyslot_cipher);
} else if (isLUKS1(cd->type)) { } else if (isLUKS1(cd->type)) {
free(cd->u.luks1.cipher_spec); free(cd->u.luks1.cipher_spec);
} else if (isLOOPAES(cd->type)) { } else if (isLOOPAES(cd->type)) {
free(CONST_CAST(void*)cd->u.loopaes.hdr.hash); free(CONST_CAST(void*)cd->u.loopaes.hdr.hash);
free(cd->u.loopaes.cipher); free(cd->u.loopaes.cipher);
free(cd->u.loopaes.cipher_spec); free(cd->u.loopaes.cipher_spec);
} else if (isVERITY(cd->type)) { } else if (isVERITY(cd->type)) {
free(CONST_CAST(void*)cd->u.verity.hdr.hash_name); free(CONST_CAST(void*)cd->u.verity.hdr.hash_name);
skipping to change at line 1559 skipping to change at line 1562
return -EINVAL; return -EINVAL;
} }
if (sector_size > SECTOR_SIZE && !device_size(cd->device, &dev_size)) { if (sector_size > SECTOR_SIZE && !device_size(cd->device, &dev_size)) {
if (params && params->offset) if (params && params->offset)
dev_size -= (params->offset * SECTOR_SIZE); dev_size -= (params->offset * SECTOR_SIZE);
if (dev_size % sector_size) { if (dev_size % sector_size) {
log_err(cd, _("Device size is not aligned to requested se ctor size.")); log_err(cd, _("Device size is not aligned to requested se ctor size."));
return -EINVAL; return -EINVAL;
} }
device_set_block_size(crypt_data_device(cd), sector_size);
} }
if (!(cd->type = strdup(CRYPT_PLAIN))) if (!(cd->type = strdup(CRYPT_PLAIN)))
return -ENOMEM; return -ENOMEM;
cd->u.plain.key_size = volume_key_size; cd->u.plain.key_size = volume_key_size;
cd->volume_key = crypt_alloc_volume_key(volume_key_size, NULL); cd->volume_key = crypt_alloc_volume_key(volume_key_size, NULL);
if (!cd->volume_key) if (!cd->volume_key)
return -ENOMEM; return -ENOMEM;
skipping to change at line 1709 skipping to change at line 1713
return r; return r;
} }
static int _crypt_format_luks2(struct crypt_device *cd, static int _crypt_format_luks2(struct crypt_device *cd,
const char *cipher, const char *cipher,
const char *cipher_mode, const char *cipher_mode,
const char *uuid, const char *uuid,
const char *volume_key, const char *volume_key,
size_t volume_key_size, size_t volume_key_size,
struct crypt_params_luks2 *params) struct crypt_params_luks2 *params,
bool sector_size_autodetect)
{ {
int r, integrity_key_size = 0; int r, integrity_key_size = 0;
unsigned long required_alignment = DEFAULT_DISK_ALIGNMENT; unsigned long required_alignment = DEFAULT_DISK_ALIGNMENT;
unsigned long alignment_offset = 0; unsigned long alignment_offset = 0;
unsigned int sector_size = params ? params->sector_size : SECTOR_SIZE; unsigned int sector_size;
const char *integrity = params ? params->integrity : NULL; const char *integrity = params ? params->integrity : NULL;
uint64_t dev_size; uint64_t dev_size;
uint32_t dmc_flags; uint32_t dmc_flags;
cd->u.luks2.hdr.jobj = NULL; cd->u.luks2.hdr.jobj = NULL;
cd->u.luks2.keyslot_cipher = NULL; cd->u.luks2.keyslot_cipher = NULL;
if (!cipher || !cipher_mode) if (!cipher || !cipher_mode)
return -EINVAL; return -EINVAL;
skipping to change at line 1736 skipping to change at line 1741
log_err(cd, _("Can't format LUKS without device.")); log_err(cd, _("Can't format LUKS without device."));
return -EINVAL; return -EINVAL;
} }
if (params && cd->data_offset && params->data_alignment && if (params && cd->data_offset && params->data_alignment &&
(cd->data_offset % params->data_alignment)) { (cd->data_offset % params->data_alignment)) {
log_err(cd, _("Requested data alignment is not compatible with da ta offset.")); log_err(cd, _("Requested data alignment is not compatible with da ta offset."));
return -EINVAL; return -EINVAL;
} }
if (params && params->sector_size)
sector_size_autodetect = false;
if (sector_size_autodetect) {
sector_size = device_optimal_encryption_sector_size(cd, crypt_dat
a_device(cd));
log_dbg(cd, "Auto-detected optimal encryption sector size for dev
ice %s is %d bytes.",
device_path(crypt_data_device(cd)), sector_size);
} else
sector_size = params ? params->sector_size : SECTOR_SIZE;
if (sector_size < SECTOR_SIZE || sector_size > MAX_SECTOR_SIZE || if (sector_size < SECTOR_SIZE || sector_size > MAX_SECTOR_SIZE ||
NOTPOW2(sector_size)) { NOTPOW2(sector_size)) {
log_err(cd, _("Unsupported encryption sector size.")); log_err(cd, _("Unsupported encryption sector size."));
return -EINVAL; return -EINVAL;
} }
if (sector_size != SECTOR_SIZE && !dm_flags(cd, DM_CRYPT, &dmc_flags) && if (sector_size != SECTOR_SIZE && !dm_flags(cd, DM_CRYPT, &dmc_flags) &&
!(dmc_flags & DM_SECTOR_SIZE_SUPPORTED)) !(dmc_flags & DM_SECTOR_SIZE_SUPPORTED)) {
log_std(cd, _("WARNING: The device activation will fail, dm-crypt if (sector_size_autodetect) {
is missing " log_dbg(cd, "dm-crypt does not support encryption sector
"support for requested encryption sector size.\n")) size option. Reverting to 512 bytes.");
; sector_size = SECTOR_SIZE;
} else
log_std(cd, _("WARNING: The device activation will fail,
dm-crypt is missing "
"support for requested encryption sector si
ze.\n"));
}
if (integrity) { if (integrity) {
if (params->integrity_params) { if (params->integrity_params) {
/* Standalone dm-integrity must not be used */ /* Standalone dm-integrity must not be used */
if (params->integrity_params->integrity || if (params->integrity_params->integrity ||
params->integrity_params->integrity_key_size) params->integrity_params->integrity_key_size)
return -EINVAL; return -EINVAL;
/* FIXME: journal encryption and MAC is here not yet supp orted */ /* FIXME: journal encryption and MAC is here not yet supp orted */
if (params->integrity_params->journal_crypt || if (params->integrity_params->journal_crypt ||
params->integrity_params->journal_integrity) params->integrity_params->journal_integrity)
skipping to change at line 1816 skipping to change at line 1836
if (!cd->data_offset) if (!cd->data_offset)
cd->data_offset = params->data_alignment; cd->data_offset = params->data_alignment;
required_alignment = params->data_alignment * SECTOR_SIZE; required_alignment = params->data_alignment * SECTOR_SIZE;
} else if (params && params->data_alignment) { } else if (params && params->data_alignment) {
required_alignment = params->data_alignment * SECTOR_SIZE; required_alignment = params->data_alignment * SECTOR_SIZE;
} else } else
device_topology_alignment(cd, cd->device, device_topology_alignment(cd, cd->device,
&required_alignment, &required_alignment,
&alignment_offset, DEFAULT_DISK_ALIGNMENT) ; &alignment_offset, DEFAULT_DISK_ALIGNMENT) ;
r = device_size(crypt_data_device(cd), &dev_size);
if (r < 0)
goto out;
if (sector_size_autodetect) {
if (cd->data_offset && MISALIGNED(cd->data_offset, sector_size))
{
log_dbg(cd, "Data offset not aligned to sector size. Reve
rting to 512 bytes.");
sector_size = SECTOR_SIZE;
} else if (MISALIGNED(dev_size - (uint64_t)required_alignment - (
uint64_t)alignment_offset, sector_size)) {
/* underflow does not affect misalignment checks */
log_dbg(cd, "Device size is not aligned to sector size. R
everting to 512 bytes.");
sector_size = SECTOR_SIZE;
}
}
/* FIXME: allow this later also for normal ciphers (check AF_ALG availabi lity. */ /* FIXME: allow this later also for normal ciphers (check AF_ALG availabi lity. */
if (integrity && !integrity_key_size) { if (integrity && !integrity_key_size) {
r = crypt_cipher_check_kernel(cipher, cipher_mode, integrity, vol ume_key_size); r = crypt_cipher_check_kernel(cipher, cipher_mode, integrity, vol ume_key_size);
if (r < 0) { if (r < 0) {
log_err(cd, _("Cipher %s-%s (key size %zd bits) is not av ailable."), log_err(cd, _("Cipher %s-%s (key size %zd bits) is not av ailable."),
cipher, cipher_mode, volume_key_size * 8); cipher, cipher_mode, volume_key_size * 8);
goto out; goto out;
} }
} }
skipping to change at line 1845 skipping to change at line 1880
cipher, cipher_mode, cipher, cipher_mode,
integrity, uuid, integrity, uuid,
sector_size, sector_size,
cd->data_offset * SECTOR_SIZE, cd->data_offset * SECTOR_SIZE,
alignment_offset, alignment_offset,
required_alignment, required_alignment,
cd->metadata_size, cd->keyslots_size); cd->metadata_size, cd->keyslots_size);
if (r < 0) if (r < 0)
goto out; goto out;
r = device_size(crypt_data_device(cd), &dev_size);
if (r < 0)
goto out;
if (dev_size < (crypt_get_data_offset(cd) * SECTOR_SIZE)) if (dev_size < (crypt_get_data_offset(cd) * SECTOR_SIZE))
log_std(cd, _("WARNING: Data offset is outside of currently avail able data device.\n")); log_std(cd, _("WARNING: Data offset is outside of currently avail able data device.\n"));
if (cd->metadata_size && (cd->metadata_size != LUKS2_metadata_size(cd->u. luks2.hdr.jobj))) if (cd->metadata_size && (cd->metadata_size != LUKS2_metadata_size(&cd->u .luks2.hdr)))
log_std(cd, _("WARNING: LUKS2 metadata size changed to %" PRIu64 " bytes.\n"), log_std(cd, _("WARNING: LUKS2 metadata size changed to %" PRIu64 " bytes.\n"),
LUKS2_metadata_size(cd->u.luks2.hdr.jobj)); LUKS2_metadata_size(&cd->u.luks2.hdr));
if (cd->keyslots_size && (cd->keyslots_size != LUKS2_keyslots_size(cd->u. luks2.hdr.jobj))) if (cd->keyslots_size && (cd->keyslots_size != LUKS2_keyslots_size(&cd->u .luks2.hdr)))
log_std(cd, _("WARNING: LUKS2 keyslots area size changed to %" PR Iu64 " bytes.\n"), log_std(cd, _("WARNING: LUKS2 keyslots area size changed to %" PR Iu64 " bytes.\n"),
LUKS2_keyslots_size(cd->u.luks2.hdr.jobj)); LUKS2_keyslots_size(&cd->u.luks2.hdr));
if (!integrity && sector_size > SECTOR_SIZE) { if (!integrity && sector_size > SECTOR_SIZE) {
dev_size -= (crypt_get_data_offset(cd) * SECTOR_SIZE); dev_size -= (crypt_get_data_offset(cd) * SECTOR_SIZE);
if (dev_size % sector_size) { if (dev_size % sector_size) {
log_err(cd, _("Device size is not aligned to requested se ctor size.")); log_err(cd, _("Device size is not aligned to requested se ctor size."));
r = -EINVAL; r = -EINVAL;
goto out; goto out;
} }
} }
if (params && (params->label || params->subsystem)) { if (params && (params->label || params->subsystem)) {
r = LUKS2_hdr_labels(cd, &cd->u.luks2.hdr, r = LUKS2_hdr_labels(cd, &cd->u.luks2.hdr,
params->label, params->subsystem, 0); params->label, params->subsystem, 0);
if (r < 0) if (r < 0)
goto out; goto out;
} }
device_set_block_size(crypt_data_device(cd), sector_size);
r = LUKS2_wipe_header_areas(cd, &cd->u.luks2.hdr, cd->metadata_device != NULL); r = LUKS2_wipe_header_areas(cd, &cd->u.luks2.hdr, cd->metadata_device != NULL);
if (r < 0) { if (r < 0) {
log_err(cd, _("Cannot wipe header on device %s."), log_err(cd, _("Cannot wipe header on device %s."),
mdata_device_path(cd)); mdata_device_path(cd));
if (dev_size < LUKS2_hdr_and_areas_size(cd->u.luks2.hdr.jobj)) if (dev_size < LUKS2_hdr_and_areas_size(&cd->u.luks2.hdr))
log_err(cd, _("Device %s is too small."), device_path(cry pt_metadata_device(cd))); log_err(cd, _("Device %s is too small."), device_path(cry pt_metadata_device(cd)));
goto out; goto out;
} }
/* Wipe integrity superblock and create integrity superblock */ /* Wipe integrity superblock and create integrity superblock */
if (crypt_get_integrity_tag_size(cd)) { if (crypt_get_integrity_tag_size(cd)) {
r = crypt_wipe_device(cd, crypt_data_device(cd), CRYPT_WIPE_ZERO, r = crypt_wipe_device(cd, crypt_data_device(cd), CRYPT_WIPE_ZERO,
crypt_get_data_offset(cd) * SECTOR_SIZE, crypt_get_data_offset(cd) * SECTOR_SIZE,
8 * SECTOR_SIZE, 8 * SECTOR_SIZE, NULL, NUL L); 8 * SECTOR_SIZE, 8 * SECTOR_SIZE, NULL, NUL L);
if (r < 0) { if (r < 0) {
skipping to change at line 2058 skipping to change at line 2091
} }
cd->u.verity.root_hash_size = hash_size; cd->u.verity.root_hash_size = hash_size;
if (params->fec_device) { if (params->fec_device) {
fec_device_path = strdup(params->fec_device); fec_device_path = strdup(params->fec_device);
if (!fec_device_path) if (!fec_device_path)
return -ENOMEM; return -ENOMEM;
r = device_alloc(cd, &fec_device, params->fec_device); r = device_alloc(cd, &fec_device, params->fec_device);
if (r < 0) { if (r < 0) {
r = -ENOMEM; r = -ENOMEM;
goto err; goto out;
} }
hash_blocks_size = VERITY_hash_blocks(cd, params) * params->hash_ block_size; hash_blocks_size = VERITY_hash_blocks(cd, params) * params->hash_ block_size;
if (device_is_identical(crypt_metadata_device(cd), fec_device) > 0 && if (device_is_identical(crypt_metadata_device(cd), fec_device) > 0 &&
(params->hash_area_offset + hash_blocks_size) > params->fec_a rea_offset) { (params->hash_area_offset + hash_blocks_size) > params->fec_a rea_offset) {
log_err(cd, _("Hash area overlaps with FEC area.")); log_err(cd, _("Hash area overlaps with FEC area."));
r = -EINVAL; r = -EINVAL;
goto err; goto out;
} }
if (device_is_identical(crypt_data_device(cd), fec_device) > 0 && if (device_is_identical(crypt_data_device(cd), fec_device) > 0 &&
(cd->u.verity.hdr.data_size * params->data_block_size) > para ms->fec_area_offset) { (cd->u.verity.hdr.data_size * params->data_block_size) > para ms->fec_area_offset) {
log_err(cd, _("Data area overlaps with FEC area.")); log_err(cd, _("Data area overlaps with FEC area."));
r = -EINVAL; r = -EINVAL;
goto err; goto out;
} }
} }
root_hash = malloc(cd->u.verity.root_hash_size); root_hash = malloc(cd->u.verity.root_hash_size);
hash_name = strdup(params->hash_name); hash_name = strdup(params->hash_name);
salt = malloc(params->salt_size); salt = malloc(params->salt_size);
if (!root_hash || !hash_name || !salt) { if (!root_hash || !hash_name || !salt) {
r = -ENOMEM; r = -ENOMEM;
goto err; goto out;
} }
cd->u.verity.hdr.flags = params->flags; cd->u.verity.hdr.flags = params->flags;
cd->u.verity.root_hash = root_hash; cd->u.verity.root_hash = root_hash;
cd->u.verity.hdr.hash_name = hash_name; cd->u.verity.hdr.hash_name = hash_name;
cd->u.verity.hdr.data_device = NULL; cd->u.verity.hdr.data_device = NULL;
cd->u.verity.fec_device = fec_device; cd->u.verity.fec_device = fec_device;
cd->u.verity.hdr.fec_device = fec_device_path; cd->u.verity.hdr.fec_device = fec_device_path;
cd->u.verity.hdr.fec_roots = params->fec_roots; cd->u.verity.hdr.fec_roots = params->fec_roots;
cd->u.verity.hdr.data_block_size = params->data_block_size; cd->u.verity.hdr.data_block_size = params->data_block_size;
skipping to change at line 2107 skipping to change at line 2140
cd->u.verity.hdr.hash_type = params->hash_type; cd->u.verity.hdr.hash_type = params->hash_type;
cd->u.verity.hdr.flags = params->flags; cd->u.verity.hdr.flags = params->flags;
cd->u.verity.hdr.salt_size = params->salt_size; cd->u.verity.hdr.salt_size = params->salt_size;
cd->u.verity.hdr.salt = salt; cd->u.verity.hdr.salt = salt;
if (params->salt) if (params->salt)
memcpy(salt, params->salt, params->salt_size); memcpy(salt, params->salt, params->salt_size);
else else
r = crypt_random_get(cd, salt, params->salt_size, CRYPT_RND_SALT) ; r = crypt_random_get(cd, salt, params->salt_size, CRYPT_RND_SALT) ;
if (r) if (r)
goto err; goto out;
if (params->flags & CRYPT_VERITY_CREATE_HASH) { if (params->flags & CRYPT_VERITY_CREATE_HASH) {
r = VERITY_create(cd, &cd->u.verity.hdr, r = VERITY_create(cd, &cd->u.verity.hdr,
cd->u.verity.root_hash, cd->u.verity.root_hash_ size); cd->u.verity.root_hash, cd->u.verity.root_hash_ size);
if (!r && params->fec_device) if (!r && params->fec_device)
r = VERITY_FEC_process(cd, &cd->u.verity.hdr, cd->u.verit y.fec_device, 0, NULL); r = VERITY_FEC_process(cd, &cd->u.verity.hdr, cd->u.verit y.fec_device, 0, NULL);
if (r) if (r)
goto err; goto out;
} }
if (!(params->flags & CRYPT_VERITY_NO_HEADER)) { if (!(params->flags & CRYPT_VERITY_NO_HEADER)) {
if (uuid) { if (uuid) {
if (!(cd->u.verity.uuid = strdup(uuid))) if (!(cd->u.verity.uuid = strdup(uuid)))
r = -ENOMEM; r = -ENOMEM;
} else } else
r = VERITY_UUID_generate(cd, &cd->u.verity.uuid); r = VERITY_UUID_generate(cd, &cd->u.verity.uuid);
if (!r) if (!r)
r = VERITY_write_sb(cd, cd->u.verity.hdr.hash_area_offset , r = VERITY_write_sb(cd, cd->u.verity.hdr.hash_area_offset ,
cd->u.verity.uuid, cd->u.verity.uuid,
&cd->u.verity.hdr); &cd->u.verity.hdr);
} }
err: out:
if (r) { if (r) {
device_free(cd, fec_device); device_free(cd, fec_device);
free(root_hash); free(root_hash);
free(hash_name); free(hash_name);
free(fec_device_path); free(fec_device_path);
free(salt); free(salt);
} }
return r; return r;
} }
skipping to change at line 2188 skipping to change at line 2221
params->journal_crypt_ key); params->journal_crypt_ key);
if (!journal_crypt_key) if (!journal_crypt_key)
return -ENOMEM; return -ENOMEM;
} }
if (params->journal_integrity_key) { if (params->journal_integrity_key) {
journal_mac_key = crypt_alloc_volume_key(params->journal_integrit y_key_size, journal_mac_key = crypt_alloc_volume_key(params->journal_integrit y_key_size,
params->journal_integrit y_key); params->journal_integrit y_key);
if (!journal_mac_key) { if (!journal_mac_key) {
r = -ENOMEM; r = -ENOMEM;
goto err; goto out;
} }
} }
if (params->integrity && !(integrity = strdup(params->integrity))) { if (params->integrity && !(integrity = strdup(params->integrity))) {
r = -ENOMEM; r = -ENOMEM;
goto err; goto out;
} }
if (params->journal_integrity && !(journal_integrity = strdup(params->jou rnal_integrity))) { if (params->journal_integrity && !(journal_integrity = strdup(params->jou rnal_integrity))) {
r = -ENOMEM; r = -ENOMEM;
goto err; goto out;
} }
if (params->journal_crypt && !(journal_crypt = strdup(params->journal_cry pt))) { if (params->journal_crypt && !(journal_crypt = strdup(params->journal_cry pt))) {
r = -ENOMEM; r = -ENOMEM;
goto err; goto out;
} }
integrity_tag_size = INTEGRITY_hash_tag_size(integrity); integrity_tag_size = INTEGRITY_hash_tag_size(integrity);
if (integrity_tag_size > 0 && params->tag_size && integrity_tag_size != p arams->tag_size) if (integrity_tag_size > 0 && params->tag_size && integrity_tag_size != p arams->tag_size)
log_std(cd, _("WARNING: Requested tag size %d bytes differs from %s size output (%d bytes).\n"), log_std(cd, _("WARNING: Requested tag size %d bytes differs from %s size output (%d bytes).\n"),
params->tag_size, integrity, integrity_tag_size); params->tag_size, integrity, integrity_tag_size);
if (params->tag_size) if (params->tag_size)
integrity_tag_size = params->tag_size; integrity_tag_size = params->tag_size;
skipping to change at line 2230 skipping to change at line 2263
cd->u.integrity.params.sector_size = params->sector_size; cd->u.integrity.params.sector_size = params->sector_size;
cd->u.integrity.params.tag_size = integrity_tag_size; cd->u.integrity.params.tag_size = integrity_tag_size;
cd->u.integrity.params.integrity = integrity; cd->u.integrity.params.integrity = integrity;
cd->u.integrity.params.journal_integrity = journal_integrity; cd->u.integrity.params.journal_integrity = journal_integrity;
cd->u.integrity.params.journal_crypt = journal_crypt; cd->u.integrity.params.journal_crypt = journal_crypt;
r = INTEGRITY_format(cd, params, cd->u.integrity.journal_crypt_key, cd->u .integrity.journal_mac_key); r = INTEGRITY_format(cd, params, cd->u.integrity.journal_crypt_key, cd->u .integrity.journal_mac_key);
if (r) if (r)
log_err(cd, _("Cannot format integrity for device %s."), log_err(cd, _("Cannot format integrity for device %s."),
mdata_device_path(cd)); mdata_device_path(cd));
err: out:
if (r) { if (r) {
crypt_free_volume_key(journal_crypt_key); crypt_free_volume_key(journal_crypt_key);
crypt_free_volume_key(journal_mac_key); crypt_free_volume_key(journal_mac_key);
free(integrity); free(integrity);
free(journal_integrity); free(journal_integrity);
free(journal_crypt); free(journal_crypt);
} }
return r; return r;
} }
int crypt_format(struct crypt_device *cd, static int _crypt_format(struct crypt_device *cd,
const char *type, const char *type,
const char *cipher, const char *cipher,
const char *cipher_mode, const char *cipher_mode,
const char *uuid, const char *uuid,
const char *volume_key, const char *volume_key,
size_t volume_key_size, size_t volume_key_size,
void *params) void *params,
bool sector_size_autodetect)
{ {
int r; int r;
if (!cd || !type) if (!cd || !type)
return -EINVAL; return -EINVAL;
if (cd->type) { if (cd->type) {
log_dbg(cd, "Context already formatted as %s.", cd->type); log_dbg(cd, "Context already formatted as %s.", cd->type);
return -EINVAL; return -EINVAL;
} }
skipping to change at line 2277 skipping to change at line 2311
return r; return r;
if (isPLAIN(type)) if (isPLAIN(type))
r = _crypt_format_plain(cd, cipher, cipher_mode, r = _crypt_format_plain(cd, cipher, cipher_mode,
uuid, volume_key_size, params); uuid, volume_key_size, params);
else if (isLUKS1(type)) else if (isLUKS1(type))
r = _crypt_format_luks1(cd, cipher, cipher_mode, r = _crypt_format_luks1(cd, cipher, cipher_mode,
uuid, volume_key, volume_key_size, params ); uuid, volume_key, volume_key_size, params );
else if (isLUKS2(type)) else if (isLUKS2(type))
r = _crypt_format_luks2(cd, cipher, cipher_mode, r = _crypt_format_luks2(cd, cipher, cipher_mode,
uuid, volume_key, volume_key_size, params ); uuid, volume_key, volume_key_size, params , sector_size_autodetect);
else if (isLOOPAES(type)) else if (isLOOPAES(type))
r = _crypt_format_loopaes(cd, cipher, uuid, volume_key_size, para ms); r = _crypt_format_loopaes(cd, cipher, uuid, volume_key_size, para ms);
else if (isVERITY(type)) else if (isVERITY(type))
r = _crypt_format_verity(cd, uuid, params); r = _crypt_format_verity(cd, uuid, params);
else if (isINTEGRITY(type)) else if (isINTEGRITY(type))
r = _crypt_format_integrity(cd, uuid, params); r = _crypt_format_integrity(cd, uuid, params);
else { else {
log_err(cd, _("Unknown crypt device type %s requested."), type); log_err(cd, _("Unknown crypt device type %s requested."), type);
r = -EINVAL; r = -EINVAL;
} }
if (r < 0) { if (r < 0) {
crypt_set_null_type(cd); crypt_set_null_type(cd);
crypt_free_volume_key(cd->volume_key); crypt_free_volume_key(cd->volume_key);
cd->volume_key = NULL; cd->volume_key = NULL;
} }
return r; return r;
} }
CRYPT_SYMBOL_EXPORT_NEW(int, crypt_format, 2, 4,
/* crypt_format parameters follows */
struct crypt_device *cd,
const char *type,
const char *cipher,
const char *cipher_mode,
const char *uuid,
const char *volume_key,
size_t volume_key_size,
void *params)
{
return _crypt_format(cd, type, cipher, cipher_mode, uuid, volume_key, vol
ume_key_size, params, true);
}
CRYPT_SYMBOL_EXPORT_OLD(int, crypt_format, 2, 0,
/* crypt_format parameters follows */
struct crypt_device *cd,
const char *type,
const char *cipher,
const char *cipher_mode,
const char *uuid,
const char *volume_key,
size_t volume_key_size,
void *params)
{
return _crypt_format(cd, type, cipher, cipher_mode, uuid, volume_key, vol
ume_key_size, params, false);
}
int crypt_repair(struct crypt_device *cd, int crypt_repair(struct crypt_device *cd,
const char *requested_type, const char *requested_type,
void *params __attribute__((unused))) void *params __attribute__((unused)))
{ {
int r; int r;
if (!cd) if (!cd)
return -EINVAL; return -EINVAL;
log_dbg(cd, "Trying to repair %s crypt type from device %s.", log_dbg(cd, "Trying to repair %s crypt type from device %s.",
skipping to change at line 2610 skipping to change at line 2672
const char *name, const char *name,
const char *iname, const char *iname,
const char *ipath, const char *ipath,
struct crypt_dm_active_device *sdmd, struct crypt_dm_active_device *sdmd,
struct crypt_dm_active_device *sdmdi) struct crypt_dm_active_device *sdmdi)
{ {
int r; int r;
struct crypt_dm_active_device tdmd, tdmdi = {}; struct crypt_dm_active_device tdmd, tdmdi = {};
struct dm_target *src, *srci, *tgt = &tdmd.segment, *tgti = &tdmdi.segmen t; struct dm_target *src, *srci, *tgt = &tdmd.segment, *tgti = &tdmdi.segmen t;
struct device *data_device = NULL; struct device *data_device = NULL;
bool clear = false;
if (!cd || !cd->type || !name || !iname || !(sdmd->flags & CRYPT_ACTIVATE _REFRESH)) if (!cd || !cd->type || !name || !iname || !(sdmd->flags & CRYPT_ACTIVATE _REFRESH))
return -EINVAL; return -EINVAL;
r = dm_query_device(cd, name, DM_ACTIVE_DEVICE | DM_ACTIVE_CRYPT_CIPHER | r = dm_query_device(cd, name, DM_ACTIVE_DEVICE | DM_ACTIVE_CRYPT_CIPHER |
DM_ACTIVE_UUID | DM_ACTIVE_CRYPT_KEYSIZE | DM_ACTIVE_UUID | DM_ACTIVE_CRYPT_KEYSIZE |
DM_ACTIVE_CRYPT_KEY, &tdmd); DM_ACTIVE_CRYPT_KEY, &tdmd);
if (r < 0) { if (r < 0) {
log_err(cd, _("Device %s is not active."), name); log_err(cd, _("Device %s is not active."), name);
return -EINVAL; return -EINVAL;
} }
if (!single_segment(&tdmd) || tgt->type != DM_CRYPT || !tgt->u.crypt.tag_ size) { if (!single_segment(&tdmd) || tgt->type != DM_CRYPT || !tgt->u.crypt.tag_ size) {
r = -ENOTSUP;
log_err(cd, _("Unsupported parameters on device %s."), name); log_err(cd, _("Unsupported parameters on device %s."), name);
r = -ENOTSUP;
goto out; goto out;
} }
r = dm_query_device(cd, iname, DM_ACTIVE_DEVICE | DM_ACTIVE_UUID, &tdmdi) ; r = dm_query_device(cd, iname, DM_ACTIVE_DEVICE | DM_ACTIVE_UUID, &tdmdi) ;
if (r < 0) { if (r < 0) {
log_err(cd, _("Device %s is not active."), iname); log_err(cd, _("Device %s is not active."), iname);
r = -EINVAL; r = -EINVAL;
goto out; goto out;
} }
if (!single_segment(&tdmdi) || tgti->type != DM_INTEGRITY) { if (!single_segment(&tdmdi) || tgti->type != DM_INTEGRITY) {
r = -ENOTSUP;
log_err(cd, _("Unsupported parameters on device %s."), iname); log_err(cd, _("Unsupported parameters on device %s."), iname);
r = -ENOTSUP;
goto out; goto out;
} }
r = crypt_compare_dm_devices(cd, sdmdi, &tdmdi); r = crypt_compare_dm_devices(cd, sdmdi, &tdmdi);
if (r) { if (r) {
log_err(cd, _("Mismatching parameters on device %s."), iname); log_err(cd, _("Mismatching parameters on device %s."), iname);
goto out; goto out;
} }
src = &sdmd->segment; src = &sdmd->segment;
skipping to change at line 2706 skipping to change at line 2769
tdmd.flags = sdmd->flags; tdmd.flags = sdmd->flags;
tdmd.size = sdmd->size; tdmd.size = sdmd->size;
if ((r = dm_reload_device(cd, iname, sdmdi, 0, 0))) { if ((r = dm_reload_device(cd, iname, sdmdi, 0, 0))) {
log_err(cd, _("Failed to reload device %s."), iname); log_err(cd, _("Failed to reload device %s."), iname);
goto out; goto out;
} }
if ((r = dm_reload_device(cd, name, &tdmd, 0, 0))) { if ((r = dm_reload_device(cd, name, &tdmd, 0, 0))) {
log_err(cd, _("Failed to reload device %s."), name); log_err(cd, _("Failed to reload device %s."), name);
goto err_clear; clear = true;
goto out;
} }
if ((r = dm_suspend_device(cd, name, 0))) { if ((r = dm_suspend_device(cd, name, 0))) {
log_err(cd, _("Failed to suspend device %s."), name); log_err(cd, _("Failed to suspend device %s."), name);
goto err_clear; clear = true;
goto out;
} }
if ((r = dm_suspend_device(cd, iname, 0))) { if ((r = dm_suspend_device(cd, iname, 0))) {
log_err(cd, _("Failed to suspend device %s."), iname); log_err(cd, _("Failed to suspend device %s."), iname);
goto err_clear; clear = true;
goto out;
} }
if ((r = dm_resume_device(cd, iname, act2dmflags(sdmdi->flags)))) { if ((r = dm_resume_device(cd, iname, act2dmflags(sdmdi->flags)))) {
log_err(cd, _("Failed to resume device %s."), iname); log_err(cd, _("Failed to resume device %s."), iname);
goto err_clear; clear = true;
goto out;
} }
r = dm_resume_device(cd, name, act2dmflags(tdmd.flags)); r = dm_resume_device(cd, name, act2dmflags(tdmd.flags));
if (!r) if (!r)
goto out; goto out;
/* /*
* This is worst case scenario. We have active underlying dm-integrity de vice with * This is worst case scenario. We have active underlying dm-integrity de vice with
* new table but dm-crypt resume failed for some reason. Tear everything down and * new table but dm-crypt resume failed for some reason. Tear everything down and
* burn it for good. * burn it for good.
*/ */
log_err(cd, _("Fatal error while reloading device %s (on top of device %s )."), name, iname); log_err(cd, _("Fatal error while reloading device %s (on top of device %s )."), name, iname);
if (dm_error_device(cd, name)) if (dm_error_device(cd, name))
log_err(cd, _("Failed to switch device %s to dm-error."), name); log_err(cd, _("Failed to switch device %s to dm-error."), name);
if (dm_error_device(cd, iname)) if (dm_error_device(cd, iname))
log_err(cd, _("Failed to switch device %s to dm-error."), iname); log_err(cd, _("Failed to switch device %s to dm-error."), iname);
goto out;
err_clear:
dm_clear_device(cd, name);
dm_clear_device(cd, iname);
if (dm_status_suspended(cd, name) > 0)
dm_resume_device(cd, name, 0);
if (dm_status_suspended(cd, iname) > 0)
dm_resume_device(cd, iname, 0);
out: out:
if (clear) {
dm_clear_device(cd, name);
dm_clear_device(cd, iname);
if (dm_status_suspended(cd, name) > 0)
dm_resume_device(cd, name, 0);
if (dm_status_suspended(cd, iname) > 0)
dm_resume_device(cd, iname, 0);
}
dm_targets_free(cd, &tdmd); dm_targets_free(cd, &tdmd);
dm_targets_free(cd, &tdmdi); dm_targets_free(cd, &tdmdi);
free(CONST_CAST(void*)tdmdi.uuid); free(CONST_CAST(void*)tdmdi.uuid);
free(CONST_CAST(void*)tdmd.uuid); free(CONST_CAST(void*)tdmd.uuid);
device_free(cd, data_device); device_free(cd, data_device);
return r; return r;
} }
int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size) int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
skipping to change at line 2994 skipping to change at line 3061
r = LUKS_hdr_restore(backup_file, &cd->u.luks1.hdr, cd); r = LUKS_hdr_restore(backup_file, &cd->u.luks1.hdr, cd);
else else
r = -EINVAL; r = -EINVAL;
if (!r) if (!r)
r = _crypt_load_luks(cd, version == 1 ? CRYPT_LUKS1 : CRYPT_LUKS2 , 1, 1); r = _crypt_load_luks(cd, version == 1 ? CRYPT_LUKS1 : CRYPT_LUKS2 , 1, 1);
return r; return r;
} }
int crypt_header_is_detached(struct crypt_device *cd)
{
int r;
if (!cd || !isLUKS(cd->type))
return -EINVAL;
r = device_is_identical(crypt_data_device(cd), crypt_metadata_device(cd))
;
if (r < 0) {
log_dbg(cd, "Failed to compare data and metadata devices path.");
return r;
}
return r ? 0 : 1;
}
void crypt_free(struct crypt_device *cd) void crypt_free(struct crypt_device *cd)
{ {
if (!cd) if (!cd)
return; return;
log_dbg(cd, "Releasing crypt device %s context.", mdata_device_path(cd)); log_dbg(cd, "Releasing crypt device %s context.", mdata_device_path(cd));
dm_backend_exit(cd); dm_backend_exit(cd);
crypt_free_volume_key(cd->volume_key); crypt_free_volume_key(cd->volume_key);
skipping to change at line 3401 skipping to change at line 3484
} }
int crypt_keyslot_change_by_passphrase(struct crypt_device *cd, int crypt_keyslot_change_by_passphrase(struct crypt_device *cd,
int keyslot_old, int keyslot_old,
int keyslot_new, int keyslot_new,
const char *passphrase, const char *passphrase,
size_t passphrase_size, size_t passphrase_size,
const char *new_passphrase, const char *new_passphrase,
size_t new_passphrase_size) size_t new_passphrase_size)
{ {
int digest = -1, r; int digest = -1, r, keyslot_new_orig = keyslot_new;
struct luks2_keyslot_params params; struct luks2_keyslot_params params;
struct volume_key *vk = NULL; struct volume_key *vk = NULL;
if (!passphrase || !new_passphrase) if (!passphrase || !new_passphrase)
return -EINVAL; return -EINVAL;
log_dbg(cd, "Changing passphrase from old keyslot %d to new %d.", log_dbg(cd, "Changing passphrase from old keyslot %d to new %d.",
keyslot_old, keyslot_new); keyslot_old, keyslot_new);
if ((r = onlyLUKS(cd))) if ((r = onlyLUKS(cd)))
skipping to change at line 3440 skipping to change at line 3523
if (keyslot_old != CRYPT_ANY_SLOT && keyslot_old != r) { if (keyslot_old != CRYPT_ANY_SLOT && keyslot_old != r) {
log_dbg(cd, "Keyslot mismatch."); log_dbg(cd, "Keyslot mismatch.");
goto out; goto out;
} }
keyslot_old = r; keyslot_old = r;
if (keyslot_new == CRYPT_ANY_SLOT) { if (keyslot_new == CRYPT_ANY_SLOT) {
if (isLUKS1(cd->type)) if (isLUKS1(cd->type))
keyslot_new = LUKS_keyslot_find_empty(&cd->u.luks1.hdr); keyslot_new = LUKS_keyslot_find_empty(&cd->u.luks1.hdr);
else if (isLUKS2(cd->type)) else if (isLUKS2(cd->type))
keyslot_new = LUKS2_keyslot_find_empty(&cd->u.luks2.hdr); keyslot_new = LUKS2_keyslot_find_empty(cd, &cd->u.luks2.h dr, vk->keylength);
if (keyslot_new < 0) if (keyslot_new < 0)
keyslot_new = keyslot_old; keyslot_new = keyslot_old;
} }
log_dbg(cd, "Key change, old slot %d, new slot %d.", keyslot_old, keyslot _new); log_dbg(cd, "Key change, old slot %d, new slot %d.", keyslot_old, keyslot _new);
if (isLUKS1(cd->type)) { if (isLUKS1(cd->type)) {
if (keyslot_old == keyslot_new) { if (keyslot_old == keyslot_new) {
log_dbg(cd, "Key slot %d is going to be overwritten.", ke yslot_old); log_dbg(cd, "Key slot %d is going to be overwritten.", ke yslot_old);
(void)crypt_keyslot_destroy(cd, keyslot_old); (void)crypt_keyslot_destroy(cd, keyslot_old);
} }
skipping to change at line 3479 skipping to change at line 3562
if (r) { if (r) {
/* (void)crypt_keyslot_destroy(cd, keyslot_old); */ /* (void)crypt_keyslot_destroy(cd, keyslot_old); */
r = -EINVAL; r = -EINVAL;
goto out; goto out;
} }
} }
r = LUKS2_keyslot_store(cd, &cd->u.luks2.hdr, r = LUKS2_keyslot_store(cd, &cd->u.luks2.hdr,
keyslot_new, new_passphrase, keyslot_new, new_passphrase,
new_passphrase_size, vk, &params); new_passphrase_size, vk, &params);
if (r < 0)
goto out;
/* Swap old & new so the final keyslot number remains */
if (keyslot_new_orig == CRYPT_ANY_SLOT && keyslot_old != keyslot_
new) {
r = LUKS2_keyslot_swap(cd, &cd->u.luks2.hdr, keyslot_old,
keyslot_new);
if (r < 0)
goto out;
/* Swap slot id */
r = keyslot_old;
keyslot_old = keyslot_new;
keyslot_new = r;
}
} else } else
r = -EINVAL; r = -EINVAL;
if (r >= 0 && keyslot_old != keyslot_new) if (r >= 0 && keyslot_old != keyslot_new)
r = crypt_keyslot_destroy(cd, keyslot_old); r = crypt_keyslot_destroy(cd, keyslot_old);
if (r < 0) if (r < 0)
log_err(cd, _("Failed to swap new key slot.")); log_err(cd, _("Failed to swap new key slot."));
out: out:
crypt_free_volume_key(vk); crypt_free_volume_key(vk);
skipping to change at line 3791 skipping to change at line 3888
return _kernel_keyring_supported; return _kernel_keyring_supported;
} }
static int dmcrypt_keyring_bug(void) static int dmcrypt_keyring_bug(void)
{ {
uint64_t kversion; uint64_t kversion;
if (kernel_version(&kversion)) if (kernel_version(&kversion))
return 1; return 1;
return kversion < version(4,15,0,0); return kversion < compact_version(4,15,0,0);
} }
int create_or_reload_device(struct crypt_device *cd, const char *name, int create_or_reload_device(struct crypt_device *cd, const char *name,
const char *type, struct crypt_dm_active_device *dmd) const char *type, struct crypt_dm_active_device *dmd)
{ {
int r; int r;
enum devcheck device_check; enum devcheck device_check;
struct dm_target *tgt; struct dm_target *tgt;
if (!type || !name || !single_segment(dmd)) if (!type || !name || !single_segment(dmd))
skipping to change at line 3931 skipping to change at line 4028
static int _open_all_keys(struct crypt_device *cd, static int _open_all_keys(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
int keyslot, int keyslot,
const char *passphrase, const char *passphrase,
size_t passphrase_size, size_t passphrase_size,
uint32_t flags, uint32_t flags,
struct volume_key **vks) struct volume_key **vks)
{ {
int r, segment; int r, segment;
struct volume_key *_vks = NULL; struct volume_key *_vks = NULL;
crypt_reencrypt_info ri = LUKS2_reenc_status(hdr); crypt_reencrypt_info ri = LUKS2_reencrypt_status(hdr);
segment = (flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) ? CRYPT_ANY_SEGMENT : CRYPT_DEFAULT_SEGMENT; segment = (flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) ? CRYPT_ANY_SEGMENT : CRYPT_DEFAULT_SEGMENT;
switch (ri) { switch (ri) {
case CRYPT_REENCRYPT_NONE: case CRYPT_REENCRYPT_NONE:
r = LUKS2_keyslot_open(cd, keyslot, segment, passphrase, passphra se_size, &_vks); r = LUKS2_keyslot_open(cd, keyslot, segment, passphrase, passphra se_size, &_vks);
break; break;
case CRYPT_REENCRYPT_CLEAN: case CRYPT_REENCRYPT_CLEAN:
case CRYPT_REENCRYPT_CRASH: case CRYPT_REENCRYPT_CRASH:
if (segment == CRYPT_ANY_SEGMENT) if (segment == CRYPT_ANY_SEGMENT)
skipping to change at line 3987 skipping to change at line 4084
bool dynamic_size; bool dynamic_size;
crypt_reencrypt_info ri; crypt_reencrypt_info ri;
uint64_t minimal_size, device_size; uint64_t minimal_size, device_size;
struct volume_key *vks = NULL; struct volume_key *vks = NULL;
int r = 0; int r = 0;
struct crypt_lock_handle *reencrypt_lock = NULL; struct crypt_lock_handle *reencrypt_lock = NULL;
if (crypt_use_keyring_for_vk(cd)) if (crypt_use_keyring_for_vk(cd))
flags |= CRYPT_ACTIVATE_KEYRING_KEY; flags |= CRYPT_ACTIVATE_KEYRING_KEY;
r = crypt_reencrypt_lock(cd, &reencrypt_lock); r = LUKS2_reencrypt_lock(cd, &reencrypt_lock);
if (r) { if (r) {
if (r == -EBUSY) if (r == -EBUSY)
log_err(cd, _("Reencryption in-progress. Cannot activate device.")); log_err(cd, _("Reencryption in-progress. Cannot activate device."));
else else
log_err(cd, _("Failed to get reencryption lock.")); log_err(cd, _("Failed to get reencryption lock."));
return r; return r;
} }
if ((r = crypt_load(cd, CRYPT_LUKS2, NULL))) if ((r = crypt_load(cd, CRYPT_LUKS2, NULL)))
goto err; goto out;
ri = LUKS2_reenc_status(hdr); ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_CRASH) { if (ri == CRYPT_REENCRYPT_CRASH) {
r = LUKS2_reencrypt_locked_recovery_by_passphrase(cd, keyslot, r = LUKS2_reencrypt_locked_recovery_by_passphrase(cd, keyslot,
keyslot, passphrase, passphrase_size, flags, &vks ); keyslot, passphrase, passphrase_size, flags, &vks );
if (r < 0) { if (r < 0) {
log_err(cd, _("LUKS2 reencryption recovery failed.")); log_err(cd, _("LUKS2 reencryption recovery failed."));
goto err; goto out;
} }
keyslot = r; keyslot = r;
ri = LUKS2_reenc_status(hdr); ri = LUKS2_reencrypt_status(hdr);
} }
/* recovery finished reencryption or it's already finished */ /* recovery finished reencryption or it's already finished */
if (ri == CRYPT_REENCRYPT_NONE) { if (ri == CRYPT_REENCRYPT_NONE) {
crypt_drop_keyring_key(cd, vks); crypt_drop_keyring_key(cd, vks);
crypt_free_volume_key(vks); crypt_free_volume_key(vks);
crypt_reencrypt_unlock(cd, reencrypt_lock); LUKS2_reencrypt_unlock(cd, reencrypt_lock);
return _open_and_activate(cd, keyslot, name, passphrase, passphra se_size, flags); return _open_and_activate(cd, keyslot, name, passphrase, passphra se_size, flags);
} }
if (ri > CRYPT_REENCRYPT_CLEAN) { if (ri > CRYPT_REENCRYPT_CLEAN) {
r = -EINVAL; r = -EINVAL;
goto err; goto out;
} }
if (LUKS2_get_data_size(hdr, &minimal_size, &dynamic_size)) if (LUKS2_get_data_size(hdr, &minimal_size, &dynamic_size))
goto err; goto out;
if (!vks) { if (!vks) {
r = _open_all_keys(cd, hdr, keyslot, passphrase, passphrase_size, flags, &vks); r = _open_all_keys(cd, hdr, keyslot, passphrase, passphrase_size, flags, &vks);
if (r >= 0) if (r >= 0)
keyslot = r; keyslot = r;
} }
log_dbg(cd, "Entering clean reencryption state mode."); log_dbg(cd, "Entering clean reencryption state mode.");
if (r >= 0) if (r >= 0)
r = luks2_check_device_size(cd, hdr, minimal_size, &device_size, true, dynamic_size); r = LUKS2_reencrypt_check_device_size(cd, hdr, minimal_size, &dev ice_size, true, dynamic_size);
if (r >= 0) if (r >= 0)
r = LUKS2_activate_multi(cd, name, vks, device_size >> SECTOR_SHI FT, flags); r = LUKS2_activate_multi(cd, name, vks, device_size >> SECTOR_SHI FT, flags);
err: out:
crypt_reencrypt_unlock(cd, reencrypt_lock); LUKS2_reencrypt_unlock(cd, reencrypt_lock);
if (r < 0) if (r < 0)
crypt_drop_keyring_key(cd, vks); crypt_drop_keyring_key(cd, vks);
crypt_free_volume_key(vks); crypt_free_volume_key(vks);
return r < 0 ? r : keyslot; return r < 0 ? r : keyslot;
} }
/* /*
* Activation/deactivation of a device * Activation/deactivation of a device
*/ */
skipping to change at line 4065 skipping to change at line 4162
int keyslot, int keyslot,
const char *name, const char *name,
const char *passphrase, const char *passphrase,
size_t passphrase_size, size_t passphrase_size,
uint32_t flags) uint32_t flags)
{ {
crypt_reencrypt_info ri; crypt_reencrypt_info ri;
int r; int r;
struct luks2_hdr *hdr = &cd->u.luks2.hdr; struct luks2_hdr *hdr = &cd->u.luks2.hdr;
ri = LUKS2_reenc_status(hdr); ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_INVALID) if (ri == CRYPT_REENCRYPT_INVALID)
return -EINVAL; return -EINVAL;
if (ri > CRYPT_REENCRYPT_NONE) { if (ri > CRYPT_REENCRYPT_NONE) {
if (name) if (name)
r = _open_and_activate_reencrypt_device(cd, hdr, keyslot, name, passphrase, r = _open_and_activate_reencrypt_device(cd, hdr, keyslot, name, passphrase,
passphrase_size, flags); passphrase_size, flags);
else else
r = _open_all_keys(cd, hdr, keyslot, passphrase, r = _open_all_keys(cd, hdr, keyslot, passphrase,
passphrase_size, flags, NULL); passphrase_size, flags, NULL);
skipping to change at line 4132 skipping to change at line 4229
passphrase_size, &cd->u.luks1.hdr, &vk , cd); passphrase_size, &cd->u.luks1.hdr, &vk , cd);
if (r >= 0) { if (r >= 0) {
keyslot = r; keyslot = r;
if (name) if (name)
r = LUKS1_activate(cd, name, vk, flags); r = LUKS1_activate(cd, name, vk, flags);
} }
} else if (isLUKS2(cd->type)) { } else if (isLUKS2(cd->type)) {
r = _open_and_activate_luks2(cd, keyslot, name, passphrase, passp hrase_size, flags); r = _open_and_activate_luks2(cd, keyslot, name, passphrase, passp hrase_size, flags);
keyslot = r; keyslot = r;
} else if (isBITLK(cd->type)) { } else if (isBITLK(cd->type)) {
r = BITLK_activate(cd, name, passphrase, passphrase_size, r = BITLK_activate_by_passphrase(cd, name, passphrase, passphrase
&cd->u.bitlk.params, flags); _size,
&cd->u.bitlk.params, flags);
keyslot = 0; keyslot = 0;
} else { } else {
log_err(cd, _("Device type is not properly initialized.")); log_err(cd, _("Device type is not properly initialized."));
r = -EINVAL; r = -EINVAL;
} }
out: out:
if (r < 0) if (r < 0)
crypt_drop_keyring_key(cd, vk); crypt_drop_keyring_key(cd, vk);
crypt_free_volume_key(vk); crypt_free_volume_key(vk);
skipping to change at line 4397 skipping to change at line 4494
return 0; return 0;
if (volume_key) { if (volume_key) {
vk = crypt_alloc_volume_key(volume_key_size, volume_key); vk = crypt_alloc_volume_key(volume_key_size, volume_key);
if (!vk) if (!vk)
return -ENOMEM; return -ENOMEM;
} }
r = INTEGRITY_activate(cd, name, &cd->u.integrity.params, vk, r = INTEGRITY_activate(cd, name, &cd->u.integrity.params, vk,
cd->u.integrity.journal_crypt_key, cd->u.integrity.journal_crypt_key,
cd->u.integrity.journal_mac_key, flags, cd->u.integrity.journal_mac_key, flags,
cd->u.integrity.sb_flags); cd->u.integrity.sb_flags);
} else if (isBITLK(cd->type)) {
r = BITLK_activate_by_volume_key(cd, name, volume_key, volume_key
_size,
&cd->u.bitlk.params, flags);
} else { } else {
log_err(cd, _("Device type is not properly initialized.")); log_err(cd, _("Device type is not properly initialized."));
r = -EINVAL; r = -EINVAL;
} }
if (r < 0) if (r < 0)
crypt_drop_keyring_key(cd, vk); crypt_drop_keyring_key(cd, vk);
crypt_free_volume_key(vk); crypt_free_volume_key(vk);
return r; return r;
skipping to change at line 4491 skipping to change at line 4591
{ {
struct crypt_device *fake_cd = NULL; struct crypt_device *fake_cd = NULL;
struct luks2_hdr *hdr2 = NULL; struct luks2_hdr *hdr2 = NULL;
struct crypt_dm_active_device dmd = {}; struct crypt_dm_active_device dmd = {};
int r; int r;
uint32_t get_flags = DM_ACTIVE_DEVICE | DM_ACTIVE_UUID | DM_ACTIVE_HOLDER S; uint32_t get_flags = DM_ACTIVE_DEVICE | DM_ACTIVE_UUID | DM_ACTIVE_HOLDER S;
if (!name) if (!name)
return -EINVAL; return -EINVAL;
if ((flags & CRYPT_DEACTIVATE_DEFERRED) && (flags & CRYPT_DEACTIVATE_DEFE
RRED_CANCEL))
return -EINVAL;
log_dbg(cd, "Deactivating volume %s.", name); log_dbg(cd, "Deactivating volume %s.", name);
if (!cd) { if (!cd) {
r = crypt_init_by_name(&fake_cd, name); r = crypt_init_by_name(&fake_cd, name);
if (r < 0) if (r < 0)
return r; return r;
cd = fake_cd; cd = fake_cd;
} }
/* skip holders detection and early abort when some flags raised */ /* skip holders detection and early abort when some flags raised */
if (flags & (CRYPT_DEACTIVATE_FORCE | CRYPT_DEACTIVATE_DEFERRED)) if (flags & (CRYPT_DEACTIVATE_FORCE | CRYPT_DEACTIVATE_DEFERRED | CRYPT_D EACTIVATE_DEFERRED_CANCEL))
get_flags &= ~DM_ACTIVE_HOLDERS; get_flags &= ~DM_ACTIVE_HOLDERS;
switch (crypt_status(cd, name)) { switch (crypt_status(cd, name)) {
case CRYPT_ACTIVE: case CRYPT_ACTIVE:
case CRYPT_BUSY: case CRYPT_BUSY:
if (flags & CRYPT_DEACTIVATE_DEFERRED_CANCEL) {
r = dm_cancel_deferred_removal(name);
if (r < 0)
log_err(cd, _("Could not cancel deferred
remove from device %s."), name);
break;
}
r = dm_query_device(cd, name, get_flags, &dmd); r = dm_query_device(cd, name, get_flags, &dmd);
if (r >= 0) { if (r >= 0) {
if (dmd.holders) { if (dmd.holders) {
log_err(cd, _("Device %s is still in use. "), name); log_err(cd, _("Device %s is still in use. "), name);
r = -EBUSY; r = -EBUSY;
break; break;
} }
} }
if (isLUKS2(cd->type)) if (isLUKS2(cd->type))
skipping to change at line 4614 skipping to change at line 4724
} }
uint64_t crypt_get_active_integrity_failures(struct crypt_device *cd, const char *name) uint64_t crypt_get_active_integrity_failures(struct crypt_device *cd, const char *name)
{ {
struct crypt_dm_active_device dmd; struct crypt_dm_active_device dmd;
uint64_t failures = 0; uint64_t failures = 0;
if (!name) if (!name)
return 0; return 0;
/* FIXME: LUKS2 / dm-crypt does not provide this count. */ /* LUKS2 / dm-crypt does not provide this count. */
if (dm_query_device(cd, name, 0, &dmd) < 0) if (dm_query_device(cd, name, 0, &dmd) < 0)
return 0; return 0;
if (single_segment(&dmd) && dmd.segment.type == DM_INTEGRITY) if (single_segment(&dmd) && dmd.segment.type == DM_INTEGRITY)
(void)dm_status_integrity_failures(cd, name, &failures); (void)dm_status_integrity_failures(cd, name, &failures);
dm_targets_free(cd, &dmd); dm_targets_free(cd, &dmd);
return failures; return failures;
} }
skipping to change at line 4677 skipping to change at line 4787
} else if (isTCRYPT(cd->type)) { } else if (isTCRYPT(cd->type)) {
r = TCRYPT_get_volume_key(cd, &cd->u.tcrypt.hdr, &cd->u.tcrypt.pa rams, &vk); r = TCRYPT_get_volume_key(cd, &cd->u.tcrypt.hdr, &cd->u.tcrypt.pa rams, &vk);
} else if (isVERITY(cd->type)) { } else if (isVERITY(cd->type)) {
/* volume_key == root hash */ /* volume_key == root hash */
if (cd->u.verity.root_hash) { if (cd->u.verity.root_hash) {
memcpy(volume_key, cd->u.verity.root_hash, cd->u.verity.r oot_hash_size); memcpy(volume_key, cd->u.verity.root_hash, cd->u.verity.r oot_hash_size);
*volume_key_size = cd->u.verity.root_hash_size; *volume_key_size = cd->u.verity.root_hash_size;
r = 0; r = 0;
} else } else
log_err(cd, _("Cannot retrieve root hash for verity devic e.")); log_err(cd, _("Cannot retrieve root hash for verity devic e."));
} else if (isBITLK(cd->type)) {
r = BITLK_get_volume_key(cd, passphrase, passphrase_size, &cd->u.
bitlk.params, &vk);
} else } else
log_err(cd, _("This operation is not supported for %s crypt devic e."), cd->type ?: "(none)"); log_err(cd, _("This operation is not supported for %s crypt devic e."), cd->type ?: "(none)");
if (r >= 0 && vk) { if (r >= 0 && vk) {
memcpy(volume_key, vk->key, vk->keylength); memcpy(volume_key, vk->key, vk->keylength);
*volume_key_size = vk->keylength; *volume_key_size = vk->keylength;
} }
crypt_free_volume_key(vk); crypt_free_volume_key(vk);
return r; return r;
skipping to change at line 4887 skipping to change at line 4999
return TCRYPT_dump(cd, &cd->u.tcrypt.hdr, &cd->u.tcrypt.params); return TCRYPT_dump(cd, &cd->u.tcrypt.hdr, &cd->u.tcrypt.params);
else if (isINTEGRITY(cd->type)) else if (isINTEGRITY(cd->type))
return INTEGRITY_dump(cd, crypt_data_device(cd), 0); return INTEGRITY_dump(cd, crypt_data_device(cd), 0);
else if (isBITLK(cd->type)) else if (isBITLK(cd->type))
return BITLK_dump(cd, crypt_data_device(cd), &cd->u.bitlk.params) ; return BITLK_dump(cd, crypt_data_device(cd), &cd->u.bitlk.params) ;
log_err(cd, _("Dump operation is not supported for this device type.")); log_err(cd, _("Dump operation is not supported for this device type."));
return -EINVAL; return -EINVAL;
} }
int crypt_dump_json(struct crypt_device *cd, const char **json, uint32_t flags)
{
if (!cd || flags)
return -EINVAL;
if (isLUKS2(cd->type))
return LUKS2_hdr_dump_json(cd, &cd->u.luks2.hdr, json);
log_err(cd, _("Dump operation is not supported for this device type."));
return -EINVAL;
}
/* internal only */ /* internal only */
const char *crypt_get_cipher_spec(struct crypt_device *cd) const char *crypt_get_cipher_spec(struct crypt_device *cd)
{ {
if (!cd) if (!cd)
return NULL; return NULL;
else if (isLUKS2(cd->type)) else if (isLUKS2(cd->type))
return LUKS2_get_cipher(&cd->u.luks2.hdr, CRYPT_DEFAULT_SEGMENT); return LUKS2_get_cipher(&cd->u.luks2.hdr, CRYPT_DEFAULT_SEGMENT);
else if (isLUKS1(cd->type)) else if (isLUKS1(cd->type))
return cd->u.luks1.cipher_spec; return cd->u.luks1.cipher_spec;
else if (isPLAIN(cd->type)) else if (isPLAIN(cd->type))
skipping to change at line 5140 skipping to change at line 5263
return -EINVAL; return -EINVAL;
} }
int crypt_keyslot_set_encryption(struct crypt_device *cd, int crypt_keyslot_set_encryption(struct crypt_device *cd,
const char *cipher, const char *cipher,
size_t key_size) size_t key_size)
{ {
char *tmp; char *tmp;
if (!cd || !cipher || ! key_size || !isLUKS2(cd->type)) if (!cd || !cipher || !key_size || !isLUKS2(cd->type))
return -EINVAL; return -EINVAL;
if (LUKS2_keyslot_cipher_incompatible(cd, cipher)) if (LUKS2_keyslot_cipher_incompatible(cd, cipher))
return -EINVAL; return -EINVAL;
tmp = strdup(cipher); if (!(tmp = strdup(cipher)))
return -ENOMEM;
free(cd->u.luks2.keyslot_cipher); free(cd->u.luks2.keyslot_cipher);
cd->u.luks2.keyslot_cipher = tmp; cd->u.luks2.keyslot_cipher = tmp;
if (!cd->u.luks2.keyslot_cipher)
return -ENOMEM;
cd->u.luks2.keyslot_key_size = key_size; cd->u.luks2.keyslot_key_size = key_size;
return 0; return 0;
} }
const char *crypt_keyslot_get_encryption(struct crypt_device *cd, int keyslot, s ize_t *key_size) const char *crypt_keyslot_get_encryption(struct crypt_device *cd, int keyslot, s ize_t *key_size)
{ {
const char *cipher; const char *cipher;
if (!cd || !isLUKS(cd->type) || !key_size) if (!cd || !isLUKS(cd->type) || !key_size)
skipping to change at line 5259 skipping to change at line 5382
if (!cd) if (!cd)
return -EINVAL; return -EINVAL;
if (!cd->type) { if (!cd->type) {
msize = cd->metadata_size; msize = cd->metadata_size;
ksize = cd->keyslots_size; ksize = cd->keyslots_size;
} else if (isLUKS1(cd->type)) { } else if (isLUKS1(cd->type)) {
msize = LUKS_ALIGN_KEYSLOTS; msize = LUKS_ALIGN_KEYSLOTS;
ksize = LUKS_device_sectors(&cd->u.luks1.hdr) * SECTOR_SIZE - msi ze; ksize = LUKS_device_sectors(&cd->u.luks1.hdr) * SECTOR_SIZE - msi ze;
} else if (isLUKS2(cd->type)) { } else if (isLUKS2(cd->type)) {
msize = LUKS2_metadata_size(cd->u.luks2.hdr.jobj); msize = LUKS2_metadata_size(&cd->u.luks2.hdr);
ksize = LUKS2_keyslots_size(cd->u.luks2.hdr.jobj); ksize = LUKS2_keyslots_size(&cd->u.luks2.hdr);
} else } else
return -EINVAL; return -EINVAL;
if (metadata_size) if (metadata_size)
*metadata_size = msize; *metadata_size = msize;
if (keyslots_size) if (keyslots_size)
*keyslots_size = ksize; *keyslots_size = ksize;
return 0; return 0;
} }
skipping to change at line 5330 skipping to change at line 5453
if (isLUKS1(cd->type)) if (isLUKS1(cd->type))
return LUKS_keyslot_info(&cd->u.luks1.hdr, keyslot); return LUKS_keyslot_info(&cd->u.luks1.hdr, keyslot);
else if(isLUKS2(cd->type)) else if(isLUKS2(cd->type))
return LUKS2_keyslot_info(&cd->u.luks2.hdr, keyslot); return LUKS2_keyslot_info(&cd->u.luks2.hdr, keyslot);
return CRYPT_SLOT_INVALID; return CRYPT_SLOT_INVALID;
} }
int crypt_keyslot_max(const char *type) int crypt_keyslot_max(const char *type)
{ {
if (type && isLUKS1(type)) if (isLUKS1(type))
return LUKS_NUMKEYS; return LUKS_NUMKEYS;
if (type && isLUKS2(type)) if (isLUKS2(type))
return LUKS2_KEYSLOTS_MAX; return LUKS2_KEYSLOTS_MAX;
return -EINVAL; return -EINVAL;
} }
int crypt_keyslot_area(struct crypt_device *cd, int crypt_keyslot_area(struct crypt_device *cd,
int keyslot, int keyslot,
uint64_t *offset, uint64_t *offset,
uint64_t *length) uint64_t *length)
{ {
skipping to change at line 5534 skipping to change at line 5657
if (isVERITY(cd->type)) if (isVERITY(cd->type))
return &cd->u.verity; return &cd->u.verity;
if (isTCRYPT(cd->type)) if (isTCRYPT(cd->type))
return &cd->u.tcrypt; return &cd->u.tcrypt;
return NULL; return NULL;
} }
/* internal only */ /* internal only */
struct luks2_reenc_context *crypt_get_reenc_context(struct crypt_device *cd) struct luks2_reencrypt *crypt_get_luks2_reencrypt(struct crypt_device *cd)
{ {
return cd->u.luks2.rh; return cd->u.luks2.rh;
} }
/* internal only */ /* internal only */
void crypt_set_reenc_context(struct crypt_device *cd, struct luks2_reenc_context *rh) void crypt_set_luks2_reencrypt(struct crypt_device *cd, struct luks2_reencrypt * rh)
{ {
cd->u.luks2.rh = rh; cd->u.luks2.rh = rh;
} }
/* /*
* Token handling * Token handling
*/ */
int crypt_activate_by_token(struct crypt_device *cd, int crypt_activate_by_token_pin(struct crypt_device *cd, const char *name,
const char *name, int token, void *usrptr, uint32_t flags) const char *type, int token, const char *pin, size_t pin_size,
void *usrptr, uint32_t flags)
{ {
int r; int r;
log_dbg(cd, "%s volume %s using token %d.", log_dbg(cd, "%s volume %s using token (%s type) %d.",
name ? "Activating" : "Checking", name ?: "passphrase", token); name ? "Activating" : "Checking", name ?: "passphrase",
type ?: "any", token);
if ((r = _onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED, 0))) if ((r = _onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED, 0)))
return r; return r;
if ((flags & CRYPT_ACTIVATE_KEYRING_KEY) && !crypt_use_keyring_for_vk(cd) ) if ((flags & CRYPT_ACTIVATE_KEYRING_KEY) && !crypt_use_keyring_for_vk(cd) )
return -EINVAL; return -EINVAL;
if ((flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) && name) if ((flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) && name)
return -EINVAL; return -EINVAL;
if (token == CRYPT_ANY_TOKEN) r = _activate_check_status(cd, name, flags & CRYPT_ACTIVATE_REFRESH);
return LUKS2_token_open_and_activate_any(cd, &cd->u.luks2.hdr, na if (r < 0)
me, flags); return r;
return LUKS2_token_open_and_activate(cd, &cd->u.luks2.hdr, token, name, f return LUKS2_token_open_and_activate(cd, &cd->u.luks2.hdr, token, name, t
lags, usrptr); ype, pin, pin_size, flags, usrptr);
}
int crypt_activate_by_token(struct crypt_device *cd,
const char *name, int token, void *usrptr, uint32_t flags)
{
return crypt_activate_by_token_pin(cd, name, NULL, token, NULL, 0, usrptr
, flags);
} }
int crypt_token_json_get(struct crypt_device *cd, int token, const char **json) int crypt_token_json_get(struct crypt_device *cd, int token, const char **json)
{ {
int r; int r;
if (!json) if (!json)
return -EINVAL; return -EINVAL;
log_dbg(cd, "Requesting JSON for token %d.", token); log_dbg(cd, "Requesting JSON for token %d.", token);
skipping to change at line 5606 skipping to change at line 5738
} }
crypt_token_info crypt_token_status(struct crypt_device *cd, int token, const ch ar **type) crypt_token_info crypt_token_status(struct crypt_device *cd, int token, const ch ar **type)
{ {
if (_onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED, 0)) if (_onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED, 0))
return CRYPT_TOKEN_INVALID; return CRYPT_TOKEN_INVALID;
return LUKS2_token_status(cd, &cd->u.luks2.hdr, token, type); return LUKS2_token_status(cd, &cd->u.luks2.hdr, token, type);
} }
int crypt_token_max(const char *type)
{
if (isLUKS2(type))
return LUKS2_TOKENS_MAX;
return -EINVAL;
}
int crypt_token_luks2_keyring_get(struct crypt_device *cd, int crypt_token_luks2_keyring_get(struct crypt_device *cd,
int token, int token,
struct crypt_token_params_luks2_keyring *params) struct crypt_token_params_luks2_keyring *params)
{ {
crypt_token_info token_info; crypt_token_info token_info;
const char *type; const char *type;
int r; int r;
if (!params) if (!params)
return -EINVAL; return -EINVAL;
skipping to change at line 5641 skipping to change at line 5781
if (!strcmp(type, LUKS2_TOKEN_KEYRING)) if (!strcmp(type, LUKS2_TOKEN_KEYRING))
break; break;
/* Fall through */ /* Fall through */
case CRYPT_TOKEN_INTERNAL_UNKNOWN: case CRYPT_TOKEN_INTERNAL_UNKNOWN:
case CRYPT_TOKEN_EXTERNAL: case CRYPT_TOKEN_EXTERNAL:
case CRYPT_TOKEN_EXTERNAL_UNKNOWN: case CRYPT_TOKEN_EXTERNAL_UNKNOWN:
log_dbg(cd, "Token %d has unexpected type %s.", token, type); log_dbg(cd, "Token %d has unexpected type %s.", token, type);
return -EINVAL; return -EINVAL;
} }
return LUKS2_builtin_token_get(cd, &cd->u.luks2.hdr, token, LUKS2_TOKEN_K EYRING, params); return LUKS2_token_keyring_get(cd, &cd->u.luks2.hdr, token, params);
} }
int crypt_token_luks2_keyring_set(struct crypt_device *cd, int crypt_token_luks2_keyring_set(struct crypt_device *cd,
int token, int token,
const struct crypt_token_params_luks2_keyring *params) const struct crypt_token_params_luks2_keyring *params)
{ {
int r; int r;
char json[4096];
if (!params) if (!params)
return -EINVAL; return -EINVAL;
log_dbg(cd, "Creating new LUKS2 keyring token (%d).", token); log_dbg(cd, "Creating new LUKS2 keyring token (%d).", token);
if ((r = onlyLUKS2(cd))) if ((r = onlyLUKS2(cd)))
return r; return r;
return LUKS2_builtin_token_create(cd, &cd->u.luks2.hdr, token, LUKS2_TOKE r = LUKS2_token_keyring_json(json, sizeof(json), params);
N_KEYRING, params, 1); if (r < 0)
return r;
return LUKS2_token_create(cd, &cd->u.luks2.hdr, token, json, 1);
} }
int crypt_token_assign_keyslot(struct crypt_device *cd, int token, int keyslot) int crypt_token_assign_keyslot(struct crypt_device *cd, int token, int keyslot)
{ {
int r; int r;
if ((r = onlyLUKS2(cd))) if ((r = onlyLUKS2(cd)))
return r; return r;
return LUKS2_token_assign(cd, &cd->u.luks2.hdr, keyslot, token, 1, 1); return LUKS2_token_assign(cd, &cd->u.luks2.hdr, keyslot, token, 1, 1);
skipping to change at line 5697 skipping to change at line 5842
return LUKS2_token_is_assigned(cd, &cd->u.luks2.hdr, keyslot, token); return LUKS2_token_is_assigned(cd, &cd->u.luks2.hdr, keyslot, token);
} }
/* Internal only */ /* Internal only */
int crypt_metadata_locking_enabled(void) int crypt_metadata_locking_enabled(void)
{ {
return _metadata_locking; return _metadata_locking;
} }
int crypt_metadata_locking(struct crypt_device *cd, int enable) int crypt_metadata_locking(struct crypt_device *cd __attribute__((unused)), int enable)
{ {
if (enable && !_metadata_locking) if (enable && !_metadata_locking)
return -EPERM; return -EPERM;
_metadata_locking = enable ? 1 : 0; _metadata_locking = enable ? 1 : 0;
return 0; return 0;
} }
int crypt_persistent_flags_set(struct crypt_device *cd, crypt_flags_type type, u int32_t flags) int crypt_persistent_flags_set(struct crypt_device *cd, crypt_flags_type type, u int32_t flags)
{ {
skipping to change at line 5910 skipping to change at line 6055
if (!_vk_via_keyring || !kernel_keyring_support()) if (!_vk_via_keyring || !kernel_keyring_support())
return 0; return 0;
if (dm_flags(cd, DM_CRYPT, &dmc_flags)) if (dm_flags(cd, DM_CRYPT, &dmc_flags))
return dmcrypt_keyring_bug() ? 0 : 1; return dmcrypt_keyring_bug() ? 0 : 1;
return (dmc_flags & DM_KERNEL_KEYRING_SUPPORTED); return (dmc_flags & DM_KERNEL_KEYRING_SUPPORTED);
} }
int crypt_volume_key_keyring(struct crypt_device *cd, int enable) int crypt_volume_key_keyring(struct crypt_device *cd __attribute__((unused)), in t enable)
{ {
_vk_via_keyring = enable ? 1 : 0; _vk_via_keyring = enable ? 1 : 0;
return 0; return 0;
} }
/* internal only */ /* internal only */
int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk) int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk)
{ {
int r; int r;
const char *type_name = key_type_name(LOGON_KEY); const char *type_name = key_type_name(LOGON_KEY);
skipping to change at line 6062 skipping to change at line 6207
crypt_reencrypt_info crypt_reencrypt_status(struct crypt_device *cd, crypt_reencrypt_info crypt_reencrypt_status(struct crypt_device *cd,
struct crypt_params_reencrypt *params) struct crypt_params_reencrypt *params)
{ {
if (!cd || !isLUKS2(cd->type)) if (!cd || !isLUKS2(cd->type))
return CRYPT_REENCRYPT_NONE; return CRYPT_REENCRYPT_NONE;
if (_onlyLUKS2(cd, CRYPT_CD_QUIET, CRYPT_REQUIREMENT_ONLINE_REENCRYPT)) if (_onlyLUKS2(cd, CRYPT_CD_QUIET, CRYPT_REQUIREMENT_ONLINE_REENCRYPT))
return CRYPT_REENCRYPT_INVALID; return CRYPT_REENCRYPT_INVALID;
return LUKS2_reencrypt_status(cd, params); return LUKS2_reencrypt_get_params(&cd->u.luks2.hdr, params);
} }
static void __attribute__((destructor)) libcryptsetup_exit(void) static void __attribute__((destructor)) libcryptsetup_exit(void)
{ {
crypt_token_unload_external_all(NULL);
crypt_backend_destroy(); crypt_backend_destroy();
crypt_random_exit(); crypt_random_exit();
} }
 End of changes. 106 change blocks. 
124 lines changed or deleted 290 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)