mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-12 03:10:08 +01:00
Extend LUKS2 decryption with datashift API tests.
This commit is contained in:
@@ -414,6 +414,9 @@ static int _setup(void)
|
||||
_system("dmsetup create " DEVICE_EMPTY_name " --table \"0 10000 zero\"", 1);
|
||||
_system("dmsetup create " DEVICE_ERROR_name " --table \"0 10000 error\"", 1);
|
||||
|
||||
if (t_set_readahead(DEVICE_ERROR, 0))
|
||||
printf("cannot set read ahead on device %s\n", DEVICE_ERROR);
|
||||
|
||||
_system(" [ ! -e " IMAGE1 " ] && xz -dk " IMAGE1 ".xz", 1);
|
||||
fd = loop_attach(&DEVICE_1, IMAGE1, 0, 0, &ro);
|
||||
close(fd);
|
||||
@@ -4566,7 +4569,78 @@ static void Luks2Reencryption(void)
|
||||
OK_(crypt_activate_by_volume_key(cd, NULL, key, key_size, 0));
|
||||
OK_(crypt_keyslot_destroy(cd, 9));
|
||||
OK_(crypt_activate_by_volume_key(cd, NULL, key, key_size, 0));
|
||||
crypt_free(cd);
|
||||
CRYPT_FREE(cd);
|
||||
|
||||
_cleanup_dmdevices();
|
||||
OK_(create_dmdevice_over_loop(L_DEVICE_OK, 2 * r_header_size));
|
||||
OK_(create_dmdevice_over_loop(H_DEVICE, r_header_size));
|
||||
|
||||
rparams = (struct crypt_params_reencrypt) {
|
||||
.mode = CRYPT_REENCRYPT_DECRYPT,
|
||||
.direction = CRYPT_REENCRYPT_FORWARD,
|
||||
.resilience = "datashift-checksum",
|
||||
.hash = "sha256",
|
||||
.data_shift = r_header_size,
|
||||
.flags = CRYPT_REENCRYPT_INITIALIZE_ONLY | CRYPT_REENCRYPT_MOVE_FIRST_SEGMENT
|
||||
};
|
||||
|
||||
OK_(crypt_init(&cd, DMDIR L_DEVICE_OK));
|
||||
OK_(set_fast_pbkdf(cd));
|
||||
OK_(crypt_format(cd, CRYPT_LUKS2, "aes", "xts-plain64", NULL, NULL, 64, NULL));
|
||||
EQ_(0, crypt_keyslot_add_by_volume_key(cd, 0, NULL, 64, PASSPHRASE, strlen(PASSPHRASE)));
|
||||
OK_(crypt_header_backup(cd, CRYPT_LUKS2, BACKUP_FILE));
|
||||
CRYPT_FREE(cd);
|
||||
|
||||
params2.data_device = DMDIR L_DEVICE_OK;
|
||||
params2.sector_size = 512;
|
||||
|
||||
/* create detached LUKS2 header (with data_offset == 0) */
|
||||
OK_(crypt_init(&cd, DMDIR H_DEVICE));
|
||||
OK_(crypt_format(cd, CRYPT_LUKS2, "aes", "xts-plain64", NULL, NULL, 64, ¶ms2));
|
||||
EQ_(crypt_get_data_offset(cd), 0);
|
||||
OK_(set_fast_pbkdf(cd));
|
||||
EQ_(0, crypt_keyslot_add_by_volume_key(cd, 0, NULL, 64, PASSPHRASE, strlen(PASSPHRASE)));
|
||||
CRYPT_FREE(cd);
|
||||
|
||||
/* initiate LUKS2 decryption with datashift on bogus LUKS2 header (data_offset == 0) */
|
||||
OK_(crypt_init_data_device(&cd, DMDIR H_DEVICE, DMDIR L_DEVICE_OK));
|
||||
OK_(crypt_load(cd, CRYPT_LUKS2, NULL));
|
||||
FAIL_(crypt_reencrypt_init_by_passphrase(cd, NULL, PASSPHRASE, strlen(PASSPHRASE), 0, CRYPT_ANY_SLOT, NULL, NULL, &rparams), "Illegal data offset");
|
||||
/* reencryption must not initalize */
|
||||
EQ_(crypt_reencrypt_status(cd, NULL), CRYPT_REENCRYPT_NONE);
|
||||
CRYPT_FREE(cd);
|
||||
/* original data device must stay untouched */
|
||||
OK_(crypt_init(&cd, DMDIR L_DEVICE_OK));
|
||||
OK_(crypt_load(cd, CRYPT_LUKS2, NULL));
|
||||
EQ_(crypt_reencrypt_status(cd, NULL), CRYPT_REENCRYPT_NONE);
|
||||
CRYPT_FREE(cd);
|
||||
|
||||
OK_(chmod(BACKUP_FILE, S_IRUSR|S_IWUSR));
|
||||
OK_(crypt_init_data_device(&cd, BACKUP_FILE, DMDIR L_DEVICE_OK));
|
||||
OK_(crypt_load(cd, CRYPT_LUKS2, NULL));
|
||||
|
||||
/* simulate read error at first segment beyond data offset*/
|
||||
OK_(dmdevice_error_io(L_DEVICE_OK, DMDIR L_DEVICE_OK, DEVICE_ERROR, 0, r_header_size, 8, ERR_RD));
|
||||
|
||||
FAIL_(crypt_reencrypt_init_by_passphrase(cd, NULL, PASSPHRASE, strlen(PASSPHRASE), 0, CRYPT_ANY_SLOT, NULL, NULL, &rparams), "Could not read first data segment");
|
||||
CRYPT_FREE(cd);
|
||||
|
||||
/* Device must not be in reencryption */
|
||||
OK_(crypt_init_data_device(&cd, BACKUP_FILE, DMDIR L_DEVICE_OK));
|
||||
OK_(crypt_load(cd, CRYPT_LUKS2, NULL));
|
||||
EQ_(crypt_reencrypt_status(cd, NULL), CRYPT_REENCRYPT_NONE);
|
||||
|
||||
/* simulate write error in original LUKS2 header area */
|
||||
OK_(dmdevice_error_io(L_DEVICE_OK, DMDIR L_DEVICE_OK, DEVICE_ERROR, 0, 0, 8, ERR_WR));
|
||||
|
||||
FAIL_(crypt_reencrypt_init_by_passphrase(cd, NULL, PASSPHRASE, strlen(PASSPHRASE), 0, CRYPT_ANY_SLOT, NULL, NULL, &rparams), "Could not write first data segment");
|
||||
CRYPT_FREE(cd);
|
||||
|
||||
/* Device must not be in reencryption */
|
||||
OK_(crypt_init_data_device(&cd, BACKUP_FILE, DMDIR L_DEVICE_OK));
|
||||
OK_(crypt_load(cd, CRYPT_LUKS2, NULL));
|
||||
EQ_(crypt_reencrypt_status(cd, NULL), CRYPT_REENCRYPT_NONE);
|
||||
CRYPT_FREE(cd);
|
||||
|
||||
_cleanup_dmdevices();
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ int t_dm_check_versions(void);
|
||||
int t_dm_crypt_keyring_support(void);
|
||||
int t_dm_crypt_cpu_switch_support(void);
|
||||
int t_dm_crypt_discard_support(void);
|
||||
int t_set_readahead(const char *device, unsigned value);
|
||||
|
||||
int fips_mode(void);
|
||||
|
||||
@@ -132,4 +133,14 @@ int loop_detach(const char *loop);
|
||||
int t_device_size_by_devno(dev_t devno, uint64_t *retval);
|
||||
int t_get_devno(const char *dev, dev_t *devno);
|
||||
|
||||
typedef enum { ERR_RD = 0, ERR_WR, ERR_RW, ERR_REMOVE } error_io_info;
|
||||
|
||||
int dmdevice_error_io(const char *dm_name,
|
||||
const char *dm_device,
|
||||
const char *error_device,
|
||||
uint64_t data_offset,
|
||||
uint64_t offset,
|
||||
uint64_t length,
|
||||
error_io_info ei);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
@@ -161,6 +162,20 @@ int t_device_size(const char *device, uint64_t *size)
|
||||
return r;
|
||||
}
|
||||
|
||||
int t_set_readahead(const char *device, unsigned value)
|
||||
{
|
||||
int devfd, r = 0;
|
||||
|
||||
devfd = open(device, O_RDONLY);
|
||||
if(devfd == -1)
|
||||
return -EINVAL;
|
||||
|
||||
if (ioctl(devfd, BLKRASET, value) < 0)
|
||||
r = -EINVAL;
|
||||
close(devfd);
|
||||
return r;
|
||||
}
|
||||
|
||||
int fips_mode(void)
|
||||
{
|
||||
int fd;
|
||||
@@ -207,6 +222,139 @@ int create_dmdevice_over_loop(const char *dm_name, const uint64_t size)
|
||||
return r;
|
||||
}
|
||||
|
||||
__attribute__((format(printf, 3, 4)))
|
||||
static int _snprintf(char **r_ptr, size_t *r_remains, const char *format, ...)
|
||||
{
|
||||
int len;
|
||||
va_list argp;
|
||||
|
||||
assert(r_remains);
|
||||
assert(r_ptr);
|
||||
|
||||
va_start(argp, format);
|
||||
|
||||
len = vsnprintf(*r_ptr, *r_remains, format, argp);
|
||||
if (len < 0 || (size_t)len >= *r_remains)
|
||||
return -EINVAL;
|
||||
|
||||
*r_ptr += len;
|
||||
*r_remains -= len;
|
||||
|
||||
va_end(argp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dmdevice_error_io(const char *dm_name,
|
||||
const char *dm_device,
|
||||
const char *error_device,
|
||||
uint64_t data_offset,
|
||||
uint64_t offset,
|
||||
uint64_t length,
|
||||
error_io_info ei)
|
||||
{
|
||||
char str[256], cmd[384];
|
||||
int r;
|
||||
uint64_t dev_size;
|
||||
size_t remains;
|
||||
char *ptr;
|
||||
|
||||
if (t_device_size(dm_device, &dev_size) < 0 || !length)
|
||||
return -1;
|
||||
|
||||
dev_size >>= TST_SECTOR_SHIFT;
|
||||
|
||||
if (dev_size <= offset)
|
||||
return -1;
|
||||
|
||||
if (ei == ERR_REMOVE) {
|
||||
r = snprintf(cmd, sizeof(cmd),
|
||||
"dmsetup load %s --table \"0 %" PRIu64 " linear %s %" PRIu64 "\"",
|
||||
dm_name, dev_size, THE_LOOP_DEV, data_offset);
|
||||
if (r < 0 || (size_t)r >= sizeof(str))
|
||||
return -3;
|
||||
|
||||
if ((r = _system(cmd, 1)))
|
||||
return r;
|
||||
|
||||
r = snprintf(cmd, sizeof(cmd), "dmsetup resume %s", dm_name);
|
||||
if (r < 0 || (size_t)r >= sizeof(cmd))
|
||||
return -3;
|
||||
|
||||
return _system(cmd, 1);
|
||||
}
|
||||
|
||||
if ((dev_size - offset) < length) {
|
||||
printf("Not enough space on target device\n.");
|
||||
return -2;
|
||||
}
|
||||
|
||||
remains = sizeof(str);
|
||||
ptr = str;
|
||||
|
||||
if (offset) {
|
||||
r = _snprintf(&ptr, &remains,
|
||||
"0 %" PRIu64 " linear %s %" PRIu64 "\n",
|
||||
offset, THE_LOOP_DEV, data_offset);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
r = _snprintf(&ptr, &remains, "%" PRIu64 " %" PRIu64 " delay ",
|
||||
offset, length);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ei == ERR_RW || ei == ERR_RD) {
|
||||
r = _snprintf(&ptr, &remains, "%s 0 0",
|
||||
error_device);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (ei == ERR_RD) {
|
||||
r = _snprintf(&ptr, &remains, " %s %" PRIu64 " 0",
|
||||
THE_LOOP_DEV, data_offset + offset);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
} else if (ei == ERR_WR) {
|
||||
r = _snprintf(&ptr, &remains, "%s %" PRIu64 " 0 %s 0 0",
|
||||
THE_LOOP_DEV, data_offset + offset, error_device);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (dev_size > (offset + length)) {
|
||||
r = _snprintf(&ptr, &remains,
|
||||
"\n%" PRIu64 " %" PRIu64 " linear %s %" PRIu64,
|
||||
offset + length, dev_size - offset - length, THE_LOOP_DEV,
|
||||
data_offset + offset + length);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Hello darkness, my old friend...
|
||||
*
|
||||
* On few old distributions there's issue with
|
||||
* processing multiline tables via dmsetup load --table.
|
||||
* This workaround passes on all systems we run tests on.
|
||||
*/
|
||||
r = snprintf(cmd, sizeof(cmd), "dmsetup load %s <<EOF\n%s\nEOF", dm_name, str);
|
||||
if (r < 0 || (size_t)r >= sizeof(cmd))
|
||||
return -3;
|
||||
|
||||
if ((r = _system(cmd, 1)))
|
||||
return r;
|
||||
|
||||
r = snprintf(cmd, sizeof(cmd), "dmsetup resume %s", dm_name);
|
||||
if (r < 0 || (size_t)r >= sizeof(cmd))
|
||||
return -3;
|
||||
|
||||
if ((r = _system(cmd, 1)))
|
||||
return r;
|
||||
|
||||
return t_set_readahead(dm_device, 0);
|
||||
}
|
||||
|
||||
// Get key from kernel dm mapping table using dm-ioctl
|
||||
int get_key_dm(const char *name, char *buffer, unsigned int buffer_size)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user