cryptsetup-reencrypt: harden checks for hdr backups removal

There're various situations where hdr backups together with log file
may get removed even when the hdr was already marked unusable. This
patch fixes the most sever case already reported and generaly tries
harder protecting the log file and both hdr backups.
This commit is contained in:
Ondrej Kozina
2016-02-26 16:42:30 +01:00
committed by Milan Broz
parent d7b127549c
commit 3e742452cd

View File

@@ -1,7 +1,7 @@
/*
* cryptsetup-reencrypt - crypt utility for offline re-encryption
*
* Copyright (C) 2012, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2016, Red Hat, Inc. All rights reserved.
* Copyright (C) 2012-2015, Milan Broz All rights reserved.
*
* This program is free software; you can redistribute it and/or
@@ -68,6 +68,7 @@ struct reenc_ctx {
uint64_t device_offset;
uint64_t device_shift;
int stained:1;
int in_progress:1;
enum { FORWARD = 0, BACKWARD = 1 } reencrypt_direction;
enum { REENCRYPT = 0, ENCRYPT = 1, DECRYPT = 2 } reencrypt_mode;
@@ -195,6 +196,8 @@ static int device_check(struct reenc_ctx *rc, header_magic set_magic)
log_err(_("Cannot write device %s.\n"), rc->device);
r = -EIO;
}
if (s > 0 && set_magic == MAKE_UNUSABLE)
rc->stained = 1;
} else
log_dbg("LUKS signature check failed for %s.", rc->device);
out:
@@ -365,6 +368,7 @@ static int open_log(struct reenc_ctx *rc)
rc->log_fd = open(rc->log_file, O_RDWR|O_EXCL|O_CREAT|flags, S_IRUSR|S_IWUSR);
if (rc->log_fd != -1) {
log_dbg("Created LUKS reencryption log file %s.", rc->log_file);
rc->stained = 0;
} else if (errno == EEXIST) {
log_std(_("Log file %s exists, resuming reencryption.\n"), rc->log_file);
rc->log_fd = open(rc->log_file, O_RDWR|flags);
@@ -646,8 +650,10 @@ static int restore_luks_header(struct reenc_ctx *rc)
crypt_free(cd);
if (r)
log_err(_("Cannot restore LUKS header on device %s.\n"), rc->device);
else
else {
log_verbose(_("LUKS header on device %s restored.\n"), rc->device);
rc->stained = 0;
}
return r;
}
@@ -784,6 +790,9 @@ static int copy_data_backward(struct reenc_ctx *rc, int fd_old, int fd_new,
if (write_log(rc) < 0)
return -EIO;
/* dirty the device during ENCRYPT mode */
rc->stained = 1;
while (!quit && rc->device_offset) {
if (rc->device_offset < block_size) {
working_offset = 0;
@@ -1175,10 +1184,7 @@ static void destroy_context(struct reenc_ctx *rc)
close_log(rc);
remove_headers(rc);
if ((rc->reencrypt_direction == FORWARD &&
rc->device_offset == rc->device_size) ||
(rc->reencrypt_direction == BACKWARD &&
(rc->device_offset == 0 || rc->device_offset == (uint64_t)~0))) {
if (!rc->stained) {
unlink(rc->log_file);
unlink(rc->header_file_org);
unlink(rc->header_file_new);
@@ -1194,7 +1200,9 @@ static void destroy_context(struct reenc_ctx *rc)
static int run_reencrypt(const char *device)
{
int r = -EINVAL;
static struct reenc_ctx rc = {};
static struct reenc_ctx rc = {
.stained = 1
};
if (initialize_context(&rc, device))
goto out;
@@ -1237,6 +1245,8 @@ static int run_reencrypt(const char *device)
// FIXME: fix error path above to not skip this
if (rc.reencrypt_mode != DECRYPT)
r = restore_luks_header(&rc);
else
rc.stained = 0;
out:
destroy_context(&rc);
return r;