diff --git a/lib/luks1/keymanage.c b/lib/luks1/keymanage.c index b2ecef66..933450d3 100644 --- a/lib/luks1/keymanage.c +++ b/lib/luks1/keymanage.c @@ -3,7 +3,7 @@ * * Copyright (C) 2004-2006, Clemens Fruhwirth * Copyright (C) 2009-2012, Red Hat, Inc. All rights reserved. - * Copyright (C) 2013, Milan Broz + * Copyright (C) 2013-2014, Milan Broz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -147,22 +147,20 @@ static const char *dbg_slot_state(crypt_keyslot_info ki) } } -int LUKS_hdr_backup( - const char *backup_file, - struct luks_phdr *hdr, - struct crypt_device *ctx) +int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx) { struct device *device = crypt_metadata_device(ctx); + struct luks_phdr hdr; int r = 0, devfd = -1; ssize_t hdr_size; ssize_t buffer_size; char *buffer = NULL; - r = LUKS_read_phdr(hdr, 1, 0, ctx); + r = LUKS_read_phdr(&hdr, 1, 0, ctx); if (r) return r; - hdr_size = LUKS_device_sectors(hdr->keyBytes) << SECTOR_SHIFT; + hdr_size = LUKS_device_sectors(hdr.keyBytes) << SECTOR_SHIFT; buffer_size = size_round_up(hdr_size, crypt_getpagesize()); buffer = crypt_safe_alloc(buffer_size); @@ -172,7 +170,7 @@ int LUKS_hdr_backup( } log_dbg("Storing backup of header (%zu bytes) and keyslot area (%zu bytes).", - sizeof(*hdr), hdr_size - LUKS_ALIGN_KEYSLOTS); + sizeof(hdr), hdr_size - LUKS_ALIGN_KEYSLOTS); log_dbg("Output backup file size: %zu bytes.", buffer_size); @@ -190,8 +188,8 @@ int LUKS_hdr_backup( close(devfd); /* Wipe unused area, so backup cannot contain old signatures */ - if (hdr->keyblock[0].keyMaterialOffset * SECTOR_SIZE == LUKS_ALIGN_KEYSLOTS) - memset(buffer + sizeof(*hdr), 0, LUKS_ALIGN_KEYSLOTS - sizeof(*hdr)); + if (hdr.keyblock[0].keyMaterialOffset * SECTOR_SIZE == LUKS_ALIGN_KEYSLOTS) + memset(buffer + sizeof(hdr), 0, LUKS_ALIGN_KEYSLOTS - sizeof(hdr)); devfd = open(backup_file, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR); if (devfd == -1) { @@ -213,6 +211,7 @@ int LUKS_hdr_backup( out: if (devfd != -1) close(devfd); + memset(&hdr, 0, sizeof(hdr)); crypt_safe_free(buffer); return r; } diff --git a/lib/luks1/luks.h b/lib/luks1/luks.h index 6d6c74cf..7aef82f9 100644 --- a/lib/luks1/luks.h +++ b/lib/luks1/luks.h @@ -130,7 +130,6 @@ int LUKS_hdr_uuid_set( int LUKS_hdr_backup( const char *backup_file, - struct luks_phdr *hdr, struct crypt_device *ctx); int LUKS_hdr_restore( diff --git a/lib/setup.c b/lib/setup.c index 9d63280f..21247115 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -78,6 +78,13 @@ struct crypt_device { struct crypt_params_tcrypt params; struct tcrypt_phdr hdr; } tcrypt; + struct { /* used if initialized without header by name */ + char *active_name; + /* buffers, must refresh from kernel on every query */ + char cipher[MAX_CIPHER_LEN]; + char cipher_mode[MAX_CIPHER_LEN]; + unsigned int key_size; + } none; } u; /* callbacks definitions */ @@ -273,6 +280,15 @@ static int onlyLUKS(struct crypt_device *cd) return r; } +static void crypt_set_null_type(struct crypt_device *cd) +{ + if (!cd->type) + return; + + free(cd->type); + cd->type = NULL; + cd->u.none.active_name = NULL; +} /* keyslot helpers */ static int keyslot_verify_or_find_empty(struct crypt_device *cd, int *keyslot) @@ -753,8 +769,7 @@ static int _init_by_name_crypt(struct crypt_device *cd, const char *name) r = _crypt_load_luks1(cd, 0, 0); if (r < 0) { log_dbg("LUKS device header does not match active device."); - free(cd->type); - cd->type = NULL; + crypt_set_null_type(cd); r = 0; goto out; } @@ -763,14 +778,12 @@ static int _init_by_name_crypt(struct crypt_device *cd, const char *name) if (r < 0) { log_dbg("LUKS device header uuid: %s mismatches DM returned uuid %s", cd->u.luks1.hdr.uuid, dmd.uuid); - free(cd->type); - cd->type = NULL; + crypt_set_null_type(cd); r = 0; } } else { log_dbg("LUKS device header not available."); - free(cd->type); - cd->type = NULL; + crypt_set_null_type(cd); r = 0; } } else if (isTCRYPT(cd->type)) { @@ -904,7 +917,11 @@ out: if (r < 0) { crypt_free(*cd); *cd = NULL; + } else if (!(*cd)->type && name) { + /* For anonymous device (no header found) remember initialized name */ + (*cd)->u.none.active_name = strdup(name); } + device_free(dmd.data_device); free(CONST_CAST(void*)dmd.uuid); return r; @@ -1222,8 +1239,7 @@ int crypt_format(struct crypt_device *cd, } if (r < 0) { - free(cd->type); - cd->type = NULL; + crypt_set_null_type(cd); crypt_free_volume_key(cd->volume_key); cd->volume_key = NULL; } @@ -1291,10 +1307,8 @@ int crypt_repair(struct crypt_device *cd, /* cd->type and header must be set in context */ r = crypt_check_data_device_size(cd); - if (r < 0) { - free(cd->type); - cd->type = NULL; - } + if (r < 0) + crypt_set_null_type(cd); return r; } @@ -1383,6 +1397,9 @@ int crypt_header_backup(struct crypt_device *cd, if ((requested_type && !isLUKS(requested_type)) || !backup_file) return -EINVAL; + if (cd->type && !isLUKS(cd->type)) + return -EINVAL; + r = init_crypto(cd); if (r < 0) return r; @@ -1390,13 +1407,15 @@ int crypt_header_backup(struct crypt_device *cd, log_dbg("Requested header backup of device %s (%s) to " "file %s.", mdata_device_path(cd), requested_type, backup_file); - return LUKS_hdr_backup(backup_file, &cd->u.luks1.hdr, cd); + r = LUKS_hdr_backup(backup_file, cd); + return r; } int crypt_header_restore(struct crypt_device *cd, const char *requested_type, const char *backup_file) { + struct luks_phdr hdr; int r; if (requested_type && !isLUKS(requested_type)) @@ -1412,7 +1431,10 @@ int crypt_header_restore(struct crypt_device *cd, log_dbg("Requested header restore to device %s (%s) from " "file %s.", mdata_device_path(cd), requested_type, backup_file); - return LUKS_hdr_restore(backup_file, &cd->u.luks1.hdr, cd); + r = LUKS_hdr_restore(backup_file, isLUKS(cd->type) ? &cd->u.luks1.hdr : &hdr, cd); + + memset(&hdr, 0, sizeof(hdr)); + return r; } void crypt_free(struct crypt_device *cd) @@ -1438,6 +1460,8 @@ void crypt_free(struct crypt_device *cd) free(CONST_CAST(void*)cd->u.verity.hdr.salt); free(cd->u.verity.root_hash); free(cd->u.verity.uuid); + } else if (!cd->type) { + free(cd->u.none.active_name); } free(cd->type); @@ -2426,6 +2450,31 @@ int crypt_dump(struct crypt_device *cd) return -EINVAL; } + +static int _init_by_name_crypt_none(struct crypt_device *cd) +{ + struct crypt_dm_active_device dmd = {}; + int r; + + if (cd->type || !cd->u.none.active_name) + return -EINVAL; + + r = dm_query_device(cd, cd->u.none.active_name, + DM_ACTIVE_CRYPT_CIPHER | + DM_ACTIVE_CRYPT_KEYSIZE, &dmd); + if (!r) + r = crypt_parse_name_and_mode(dmd.u.crypt.cipher, + cd->u.none.cipher, NULL, + cd->u.none.cipher_mode); + + if (!r) + cd->u.none.key_size = dmd.u.crypt.vk->keylength; + + crypt_free_volume_key(dmd.u.crypt.vk); + free(CONST_CAST(void*)dmd.u.crypt.cipher); + return r; +} + const char *crypt_get_cipher(struct crypt_device *cd) { if (isPLAIN(cd->type)) @@ -2440,6 +2489,9 @@ const char *crypt_get_cipher(struct crypt_device *cd) if (isTCRYPT(cd->type)) return cd->u.tcrypt.params.cipher; + if (!cd->type && !_init_by_name_crypt_none(cd)) + return cd->u.none.cipher; + return NULL; } @@ -2457,6 +2509,9 @@ const char *crypt_get_cipher_mode(struct crypt_device *cd) if (isTCRYPT(cd->type)) return cd->u.tcrypt.params.mode; + if (!cd->type && !_init_by_name_crypt_none(cd)) + return cd->u.none.cipher_mode; + return NULL; } @@ -2498,6 +2553,9 @@ int crypt_get_volume_key_size(struct crypt_device *cd) if (isTCRYPT(cd->type)) return cd->u.tcrypt.params.key_size; + if (!cd->type && !_init_by_name_crypt_none(cd)) + return cd->u.none.key_size; + return 0; } diff --git a/src/cryptsetup.c b/src/cryptsetup.c index 2aa3c556..89cb17b0 100644 --- a/src/cryptsetup.c +++ b/src/cryptsetup.c @@ -418,10 +418,10 @@ static int action_status(void) ci == CRYPT_BUSY ? " and is in use" : ""); r = crypt_init_by_name_and_header(&cd, action_argv[0], opt_header_device); - if (r < 0 || !crypt_get_type(cd)) + if (r < 0) goto out; - log_std(" type: %s\n", crypt_get_type(cd)); + log_std(" type: %s\n", crypt_get_type(cd) ?: "n/a"); r = crypt_get_active_device(cd, action_argv[0], &cad); if (r < 0) diff --git a/tests/api-test.c b/tests/api-test.c index 65de602e..53f338c1 100644 --- a/tests/api-test.c +++ b/tests/api-test.c @@ -2,7 +2,7 @@ * cryptsetup library API check functions * * Copyright (C) 2009-2013 Red Hat, Inc. All rights reserved. - * Copyright (C) 2009-2013, Milan Broz + * Copyright (C) 2009-2014, Milan Broz * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -1095,6 +1095,14 @@ static void AddDeviceLuks(void) OK_(crypt_init_by_name_and_header(&cd, CDEVICE_1, DMDIR H_DEVICE)); FAIL_(crypt_format(cd, CRYPT_LUKS1, cipher, cipher_mode, NULL, key, key_size, ¶ms), "Context is already formated"); EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + crypt_free(cd); + // check active status without header + OK_(crypt_init_by_name_and_header(&cd, CDEVICE_1, NULL)); + EQ_(crypt_status(cd, CDEVICE_1), CRYPT_ACTIVE); + OK_(!!crypt_get_type(cd)); + OK_(strcmp(cipher, crypt_get_cipher(cd))); + OK_(strcmp(cipher_mode, crypt_get_cipher_mode(cd))); + EQ_((int)key_size, crypt_get_volume_key_size(cd)); OK_(crypt_deactivate(cd, CDEVICE_1)); crypt_free(cd); diff --git a/tests/compat-test b/tests/compat-test index 86ec8e44..d99661ae 100755 --- a/tests/compat-test +++ b/tests/compat-test @@ -533,6 +533,8 @@ echo $PWD1 | $CRYPTSETUP luksFormat -i1 $LOOPDEV --header $HEADER_IMG --align-pa echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV --header $HEADER_IMG $DEV_NAME || fail $CRYPTSETUP -q resize $DEV_NAME --size 100 --header $HEADER_IMG || fail $CRYPTSETUP -q status $DEV_NAME --header $HEADER_IMG | grep "size:" | grep -q "100 sectors" || fail +$CRYPTSETUP -q status $DEV_NAME | grep "type:" | grep -q "n/a" || fail +$CRYPTSETUP -q status $DEV_NAME | grep "size:" | grep -q "100 sectors" || fail $CRYPTSETUP luksSuspend $DEV_NAME --header $HEADER_IMG || fail echo $PWD1 | $CRYPTSETUP luksResume $DEV_NAME --header $HEADER_IMG || fail $CRYPTSETUP luksClose $DEV_NAME || fail