"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "lib/luks2/luks2_reencrypt.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.

luks2_reencrypt.c  (cryptsetup-2.3.6.tar.xz):luks2_reencrypt.c  (cryptsetup-2.4.0.tar.xz)
skipping to change at line 25 skipping to change at line 25
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/ */
#include "luks2_internal.h" #include "luks2_internal.h"
#include "utils_device_locking.h" #include "utils_device_locking.h"
struct reenc_protection {
enum { REENC_PROTECTION_NONE = 0, /* none should be 0 always */
REENC_PROTECTION_CHECKSUM,
REENC_PROTECTION_JOURNAL,
REENC_PROTECTION_DATASHIFT } type;
union {
struct {
} none;
struct {
char hash[LUKS2_CHECKSUM_ALG_L]; // or include luks.h
struct crypt_hash *ch;
size_t hash_size;
/* buffer for checksums */
void *checksums;
size_t checksums_len;
} csum;
struct {
} ds;
} p;
};
struct luks2_reencrypt {
/* reencryption window attributes */
uint64_t offset;
uint64_t progress;
uint64_t length;
uint64_t data_shift;
size_t alignment;
uint64_t device_size;
bool online;
bool fixed_length;
crypt_reencrypt_direction_info direction;
crypt_reencrypt_mode_info mode;
char *device_name;
char *hotzone_name;
char *overlay_name;
uint32_t flags;
/* reencryption window persistence attributes */
struct reenc_protection rp;
int reenc_keyslot;
/* already running reencryption */
json_object *jobj_segs_hot;
struct json_object *jobj_segs_post;
/* backup segments */
json_object *jobj_segment_new;
int digest_new;
json_object *jobj_segment_old;
int digest_old;
json_object *jobj_segment_moved;
struct volume_key *vks;
void *reenc_buffer;
ssize_t read;
struct crypt_storage_wrapper *cw1;
struct crypt_storage_wrapper *cw2;
uint32_t wflags1;
uint32_t wflags2;
struct crypt_lock_handle *reenc_lock;
};
static int reencrypt_keyslot_update(struct crypt_device *cd,
const struct luks2_reencrypt *rh)
{
json_object *jobj_keyslot, *jobj_area, *jobj_area_type;
struct luks2_hdr *hdr;
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
return -EINVAL;
jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, rh->reenc_keyslot);
if (!jobj_keyslot)
return -EINVAL;
json_object_object_get_ex(jobj_keyslot, "area", &jobj_area);
json_object_object_get_ex(jobj_area, "type", &jobj_area_type);
if (rh->rp.type == REENC_PROTECTION_CHECKSUM) {
log_dbg(cd, "Updating reencrypt keyslot for checksum protection."
);
json_object_object_add(jobj_area, "type", json_object_new_string(
"checksum"));
json_object_object_add(jobj_area, "hash", json_object_new_string(
rh->rp.p.csum.hash));
json_object_object_add(jobj_area, "sector_size", json_object_new_
int64(rh->alignment));
} else if (rh->rp.type == REENC_PROTECTION_NONE) {
log_dbg(cd, "Updating reencrypt keyslot for none protection.");
json_object_object_add(jobj_area, "type", json_object_new_string(
"none"));
json_object_object_del(jobj_area, "hash");
} else if (rh->rp.type == REENC_PROTECTION_JOURNAL) {
log_dbg(cd, "Updating reencrypt keyslot for journal protection.")
;
json_object_object_add(jobj_area, "type", json_object_new_string(
"journal"));
json_object_object_del(jobj_area, "hash");
} else
log_dbg(cd, "No update of reencrypt keyslot needed.");
return 0;
}
static json_object *reencrypt_segment(struct luks2_hdr *hdr, unsigned new) static json_object *reencrypt_segment(struct luks2_hdr *hdr, unsigned new)
{ {
return LUKS2_get_segment_by_flag(hdr, new ? "backup-final" : "backup-prev ious"); return LUKS2_get_segment_by_flag(hdr, new ? "backup-final" : "backup-prev ious");
} }
static json_object *reencrypt_segment_new(struct luks2_hdr *hdr) static json_object *reencrypt_segment_new(struct luks2_hdr *hdr)
{ {
return reencrypt_segment(hdr, 1); return reencrypt_segment(hdr, 1);
} }
skipping to change at line 171 skipping to change at line 276
if (strcmp(json_object_get_string(jobj_type), "checksum")) if (strcmp(json_object_get_string(jobj_type), "checksum"))
return 0; return 0;
if (!json_object_object_get_ex(jobj_area, "hash", &jobj_hash)) if (!json_object_object_get_ex(jobj_area, "hash", &jobj_hash))
return 0; return 0;
if (!json_object_object_get_ex(jobj_area, "sector_size", &jobj_sector_siz e)) if (!json_object_object_get_ex(jobj_area, "sector_size", &jobj_sector_siz e))
return 0; return 0;
return crypt_jobj_get_uint32(jobj_sector_size); return crypt_jobj_get_uint32(jobj_sector_size);
} }
static json_object *_enc_create_segments_shift_after(struct crypt_device *cd, static json_object *_enc_create_segments_shift_after(struct luks2_reencrypt *rh,
struct luks2_hdr *hdr, uint64_t data_offset)
struct luks2_reenc_context *rh,
uint64_t data_offset)
{ {
int reenc_seg, i = 0; int reenc_seg, i = 0;
json_object *jobj_copy, *jobj_seg_new = NULL, *jobj_segs_post = json_obje ct_new_object(); json_object *jobj_copy, *jobj_seg_new = NULL, *jobj_segs_post = json_obje ct_new_object();
uint64_t tmp; uint64_t tmp;
if (!rh->jobj_segs_hot || !jobj_segs_post) if (!rh->jobj_segs_hot || !jobj_segs_post)
goto err; goto err;
if (json_segments_count(rh->jobj_segs_hot) == 0) if (json_segments_count(rh->jobj_segs_hot) == 0)
return jobj_segs_post; return jobj_segs_post;
skipping to change at line 218 skipping to change at line 320
/* alter size of new segment, reenc_seg == 0 we're finished */ /* alter size of new segment, reenc_seg == 0 we're finished */
json_object_object_add(jobj_seg_new, "size", reenc_seg > 0 ? crypt_jobj_n ew_uint64(tmp) : json_object_new_string("dynamic")); json_object_object_add(jobj_seg_new, "size", reenc_seg > 0 ? crypt_jobj_n ew_uint64(tmp) : json_object_new_string("dynamic"));
json_object_object_add_by_uint(jobj_segs_post, reenc_seg, jobj_seg_new); json_object_object_add_by_uint(jobj_segs_post, reenc_seg, jobj_seg_new);
return jobj_segs_post; return jobj_segs_post;
err: err:
json_object_put(jobj_segs_post); json_object_put(jobj_segs_post);
return NULL; return NULL;
} }
static json_object *reencrypt_make_hot_segments_encrypt_shift(struct crypt_devic static json_object *reencrypt_make_hot_segments_encrypt_shift(struct luks2_hdr *
e *cd, hdr,
struct luks2_hdr *hdr, struct luks2_reencrypt *rh,
struct luks2_reenc_context *rh,
uint64_t data_offset) uint64_t data_offset)
{ {
int sg, crypt_seg, i = 0; int sg, crypt_seg, i = 0;
uint64_t segment_size; uint64_t segment_size;
json_object *jobj_seg_shrunk, *jobj_seg_new, *jobj_copy, *jobj_enc_seg = NULL, json_object *jobj_seg_shrunk, *jobj_seg_new, *jobj_copy, *jobj_enc_seg = NULL,
*jobj_segs_hot = json_object_new_object(); *jobj_segs_hot = json_object_new_object();
if (!jobj_segs_hot) if (!jobj_segs_hot)
return NULL; return NULL;
skipping to change at line 284 skipping to change at line 385
return jobj_segs_hot; return jobj_segs_hot;
err: err:
json_object_put(jobj_enc_seg); json_object_put(jobj_enc_seg);
json_object_put(jobj_segs_hot); json_object_put(jobj_segs_hot);
return NULL; return NULL;
} }
static json_object *reencrypt_make_segment_new(struct crypt_device *cd, static json_object *reencrypt_make_segment_new(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
const struct luks2_reenc_context *rh, const struct luks2_reencrypt *rh,
uint64_t data_offset, uint64_t data_offset,
uint64_t segment_offset, uint64_t segment_offset,
uint64_t iv_offset, uint64_t iv_offset,
const uint64_t *segment_length) const uint64_t *segment_length)
{ {
switch (rh->mode) { switch (rh->mode) {
case CRYPT_REENCRYPT_REENCRYPT: case CRYPT_REENCRYPT_REENCRYPT:
case CRYPT_REENCRYPT_ENCRYPT: case CRYPT_REENCRYPT_ENCRYPT:
return json_segment_create_crypt(data_offset + segment_offset, return json_segment_create_crypt(data_offset + segment_offset,
crypt_get_iv_offset(cd) + (iv_o ffset >> SECTOR_SHIFT), crypt_get_iv_offset(cd) + (iv_o ffset >> SECTOR_SHIFT),
skipping to change at line 307 skipping to change at line 408
reencrypt_get_sector_size_new(h dr), 0); reencrypt_get_sector_size_new(h dr), 0);
case CRYPT_REENCRYPT_DECRYPT: case CRYPT_REENCRYPT_DECRYPT:
return json_segment_create_linear(data_offset + segment_offset, s egment_length, 0); return json_segment_create_linear(data_offset + segment_offset, s egment_length, 0);
} }
return NULL; return NULL;
} }
static json_object *reencrypt_make_post_segments_forward(struct crypt_device *cd , static json_object *reencrypt_make_post_segments_forward(struct crypt_device *cd ,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
struct luks2_reenc_context *rh, struct luks2_reencrypt *rh,
uint64_t data_offset) uint64_t data_offset)
{ {
int reenc_seg; int reenc_seg;
json_object *jobj_new_seg_after, *jobj_old_seg, *jobj_old_seg_copy = NULL , json_object *jobj_new_seg_after, *jobj_old_seg, *jobj_old_seg_copy = NULL ,
*jobj_segs_post = json_object_new_object(); *jobj_segs_post = json_object_new_object();
uint64_t fixed_length = rh->offset + rh->length; uint64_t fixed_length = rh->offset + rh->length;
if (!rh->jobj_segs_hot || !jobj_segs_post) if (!rh->jobj_segs_hot || !jobj_segs_post)
goto err; goto err;
skipping to change at line 353 skipping to change at line 454
} }
return jobj_segs_post; return jobj_segs_post;
err: err:
json_object_put(jobj_segs_post); json_object_put(jobj_segs_post);
return NULL; return NULL;
} }
static json_object *reencrypt_make_post_segments_backward(struct crypt_device *c d, static json_object *reencrypt_make_post_segments_backward(struct crypt_device *c d,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
struct luks2_reenc_context *rh, struct luks2_reencrypt *rh,
uint64_t data_offset) uint64_t data_offset)
{ {
int reenc_seg; int reenc_seg;
uint64_t fixed_length; uint64_t fixed_length;
json_object *jobj_new_seg_after, *jobj_old_seg, json_object *jobj_new_seg_after, *jobj_old_seg,
*jobj_segs_post = json_object_new_object(); *jobj_segs_post = json_object_new_object();
if (!rh->jobj_segs_hot || !jobj_segs_post) if (!rh->jobj_segs_hot || !jobj_segs_post)
goto err; goto err;
skipping to change at line 389 skipping to change at line 490
json_object_object_add_by_uint(jobj_segs_post, reenc_seg, jobj_new_seg_af ter); json_object_object_add_by_uint(jobj_segs_post, reenc_seg, jobj_new_seg_af ter);
return jobj_segs_post; return jobj_segs_post;
err: err:
json_object_put(jobj_segs_post); json_object_put(jobj_segs_post);
return NULL; return NULL;
} }
static json_object *reencrypt_make_segment_reencrypt(struct crypt_device *cd, static json_object *reencrypt_make_segment_reencrypt(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
const struct luks2_reenc_context *rh, const struct luks2_reencrypt *rh,
uint64_t data_offset, uint64_t data_offset,
uint64_t segment_offset, uint64_t segment_offset,
uint64_t iv_offset, uint64_t iv_offset,
const uint64_t *segment_length) const uint64_t *segment_length)
{ {
switch (rh->mode) { switch (rh->mode) {
case CRYPT_REENCRYPT_REENCRYPT: case CRYPT_REENCRYPT_REENCRYPT:
case CRYPT_REENCRYPT_ENCRYPT: case CRYPT_REENCRYPT_ENCRYPT:
return json_segment_create_crypt(data_offset + segment_offset, return json_segment_create_crypt(data_offset + segment_offset,
crypt_get_iv_offset(cd) + (iv_offset >> SECTOR_SH IFT), crypt_get_iv_offset(cd) + (iv_offset >> SECTOR_SH IFT),
skipping to change at line 412 skipping to change at line 513
reencrypt_get_sector_size_new(hdr), 1); reencrypt_get_sector_size_new(hdr), 1);
case CRYPT_REENCRYPT_DECRYPT: case CRYPT_REENCRYPT_DECRYPT:
return json_segment_create_linear(data_offset + segment_offset, s egment_length, 1); return json_segment_create_linear(data_offset + segment_offset, s egment_length, 1);
} }
return NULL; return NULL;
} }
static json_object *reencrypt_make_segment_old(struct crypt_device *cd, static json_object *reencrypt_make_segment_old(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
const struct luks2_reenc_context *rh, const struct luks2_reencrypt *rh,
uint64_t data_offset, uint64_t data_offset,
uint64_t segment_offset, uint64_t segment_offset,
const uint64_t *segment_length) const uint64_t *segment_length)
{ {
json_object *jobj_old_seg = NULL; json_object *jobj_old_seg = NULL;
switch (rh->mode) { switch (rh->mode) {
case CRYPT_REENCRYPT_REENCRYPT: case CRYPT_REENCRYPT_REENCRYPT:
case CRYPT_REENCRYPT_DECRYPT: case CRYPT_REENCRYPT_DECRYPT:
jobj_old_seg = json_segment_create_crypt(data_offset + segment_of fset, jobj_old_seg = json_segment_create_crypt(data_offset + segment_of fset,
skipping to change at line 438 skipping to change at line 539
break; break;
case CRYPT_REENCRYPT_ENCRYPT: case CRYPT_REENCRYPT_ENCRYPT:
jobj_old_seg = json_segment_create_linear(data_offset + segment_o ffset, segment_length, 0); jobj_old_seg = json_segment_create_linear(data_offset + segment_o ffset, segment_length, 0);
} }
return jobj_old_seg; return jobj_old_seg;
} }
static json_object *reencrypt_make_hot_segments_forward(struct crypt_device *cd, static json_object *reencrypt_make_hot_segments_forward(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
struct luks2_reenc_context *rh, struct luks2_reencrypt *rh,
uint64_t device_size, uint64_t device_size,
uint64_t data_offset) uint64_t data_offset)
{ {
json_object *jobj_segs_hot, *jobj_reenc_seg, *jobj_old_seg, *jobj_new_seg ; json_object *jobj_segs_hot, *jobj_reenc_seg, *jobj_old_seg, *jobj_new_seg ;
uint64_t fixed_length, tmp = rh->offset + rh->length; uint64_t fixed_length, tmp = rh->offset + rh->length;
unsigned int sg = 0; unsigned int sg = 0;
jobj_segs_hot = json_object_new_object(); jobj_segs_hot = json_object_new_object();
if (!jobj_segs_hot) if (!jobj_segs_hot)
return NULL; return NULL;
skipping to change at line 479 skipping to change at line 580
} }
return jobj_segs_hot; return jobj_segs_hot;
err: err:
json_object_put(jobj_segs_hot); json_object_put(jobj_segs_hot);
return NULL; return NULL;
} }
static json_object *reencrypt_make_hot_segments_backward(struct crypt_device *cd , static json_object *reencrypt_make_hot_segments_backward(struct crypt_device *cd ,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
struct luks2_reenc_context *rh, struct luks2_reencrypt *rh,
uint64_t device_size, uint64_t device_size,
uint64_t data_offset) uint64_t data_offset)
{ {
json_object *jobj_reenc_seg, *jobj_new_seg, *jobj_old_seg = NULL, json_object *jobj_reenc_seg, *jobj_new_seg, *jobj_old_seg = NULL,
*jobj_segs_hot = json_object_new_object(); *jobj_segs_hot = json_object_new_object();
int sg = 0; int sg = 0;
uint64_t fixed_length, tmp = rh->offset + rh->length; uint64_t fixed_length, tmp = rh->offset + rh->length;
if (!jobj_segs_hot) if (!jobj_segs_hot)
return NULL; return NULL;
skipping to change at line 521 skipping to change at line 622
} }
return jobj_segs_hot; return jobj_segs_hot;
err: err:
json_object_put(jobj_segs_hot); json_object_put(jobj_segs_hot);
return NULL; return NULL;
} }
static int reencrypt_make_hot_segments(struct crypt_device *cd, static int reencrypt_make_hot_segments(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
struct luks2_reenc_context *rh, struct luks2_reencrypt *rh,
uint64_t device_size, uint64_t device_size,
uint64_t data_offset) uint64_t data_offset)
{ {
rh->jobj_segs_hot = NULL; rh->jobj_segs_hot = NULL;
if (rh->mode == CRYPT_REENCRYPT_ENCRYPT && rh->direction == CRYPT_REENCRY PT_BACKWARD && if (rh->mode == CRYPT_REENCRYPT_ENCRYPT && rh->direction == CRYPT_REENCRY PT_BACKWARD &&
rh->data_shift && rh->jobj_segment_moved) { rh->data_shift && rh->jobj_segment_moved) {
log_dbg(cd, "Calculating hot segments for encryption with data mo ve."); log_dbg(cd, "Calculating hot segments for encryption with data mo ve.");
rh->jobj_segs_hot = reencrypt_make_hot_segments_encrypt_shift(cd, hdr, rh, data_offset); rh->jobj_segs_hot = reencrypt_make_hot_segments_encrypt_shift(hdr , rh, data_offset);
} else if (rh->direction == CRYPT_REENCRYPT_FORWARD) { } else if (rh->direction == CRYPT_REENCRYPT_FORWARD) {
log_dbg(cd, "Calculating hot segments (forward direction)."); log_dbg(cd, "Calculating hot segments (forward direction).");
rh->jobj_segs_hot = reencrypt_make_hot_segments_forward(cd, hdr, rh, device_size, data_offset); rh->jobj_segs_hot = reencrypt_make_hot_segments_forward(cd, hdr, rh, device_size, data_offset);
} else if (rh->direction == CRYPT_REENCRYPT_BACKWARD) { } else if (rh->direction == CRYPT_REENCRYPT_BACKWARD) {
log_dbg(cd, "Calculating hot segments (backward direction)."); log_dbg(cd, "Calculating hot segments (backward direction).");
rh->jobj_segs_hot = reencrypt_make_hot_segments_backward(cd, hdr, rh, device_size, data_offset); rh->jobj_segs_hot = reencrypt_make_hot_segments_backward(cd, hdr, rh, device_size, data_offset);
} }
return rh->jobj_segs_hot ? 0 : -EINVAL; return rh->jobj_segs_hot ? 0 : -EINVAL;
} }
static int reencrypt_make_post_segments(struct crypt_device *cd, static int reencrypt_make_post_segments(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
struct luks2_reenc_context *rh, struct luks2_reencrypt *rh,
uint64_t data_offset) uint64_t data_offset)
{ {
rh->jobj_segs_post = NULL; rh->jobj_segs_post = NULL;
if (rh->mode == CRYPT_REENCRYPT_ENCRYPT && rh->direction == CRYPT_REENCRY PT_BACKWARD && if (rh->mode == CRYPT_REENCRYPT_ENCRYPT && rh->direction == CRYPT_REENCRY PT_BACKWARD &&
rh->data_shift && rh->jobj_segment_moved) { rh->data_shift && rh->jobj_segment_moved) {
log_dbg(cd, "Calculating post segments for encryption with data m ove."); log_dbg(cd, "Calculating post segments for encryption with data m ove.");
rh->jobj_segs_post = _enc_create_segments_shift_after(cd, hdr, rh , data_offset); rh->jobj_segs_post = _enc_create_segments_shift_after(rh, data_of fset);
} else if (rh->direction == CRYPT_REENCRYPT_FORWARD) { } else if (rh->direction == CRYPT_REENCRYPT_FORWARD) {
log_dbg(cd, "Calculating post segments (forward direction)."); log_dbg(cd, "Calculating post segments (forward direction).");
rh->jobj_segs_post = reencrypt_make_post_segments_forward(cd, hdr , rh, data_offset); rh->jobj_segs_post = reencrypt_make_post_segments_forward(cd, hdr , rh, data_offset);
} else if (rh->direction == CRYPT_REENCRYPT_BACKWARD) { } else if (rh->direction == CRYPT_REENCRYPT_BACKWARD) {
log_dbg(cd, "Calculating segments (backward direction)."); log_dbg(cd, "Calculating segments (backward direction).");
rh->jobj_segs_post = reencrypt_make_post_segments_backward(cd, hd r, rh, data_offset); rh->jobj_segs_post = reencrypt_make_post_segments_backward(cd, hd r, rh, data_offset);
} }
return rh->jobj_segs_post ? 0 : -EINVAL; return rh->jobj_segs_post ? 0 : -EINVAL;
} }
skipping to change at line 625 skipping to change at line 726
/* validation enforces allowed values */ /* validation enforces allowed values */
if (strcmp(value, "forward")) if (strcmp(value, "forward"))
di = CRYPT_REENCRYPT_BACKWARD; di = CRYPT_REENCRYPT_BACKWARD;
return di; return di;
} }
typedef enum { REENC_OK = 0, REENC_ERR, REENC_ROLLBACK, REENC_FATAL } reenc_stat us_t; typedef enum { REENC_OK = 0, REENC_ERR, REENC_ROLLBACK, REENC_FATAL } reenc_stat us_t;
void LUKS2_reenc_context_free(struct crypt_device *cd, struct luks2_reenc_contex t *rh) void LUKS2_reencrypt_free(struct crypt_device *cd, struct luks2_reencrypt *rh)
{ {
if (!rh) if (!rh)
return; return;
if (rh->rp.type == REENC_PROTECTION_CHECKSUM) { if (rh->rp.type == REENC_PROTECTION_CHECKSUM) {
if (rh->rp.p.csum.ch) { if (rh->rp.p.csum.ch) {
crypt_hash_destroy(rh->rp.p.csum.ch); crypt_hash_destroy(rh->rp.p.csum.ch);
rh->rp.p.csum.ch = NULL; rh->rp.p.csum.ch = NULL;
} }
if (rh->rp.p.csum.checksums) { if (rh->rp.p.csum.checksums) {
skipping to change at line 688 skipping to change at line 789
alignment = ss; alignment = ss;
ss = reencrypt_get_sector_size_new(hdr); ss = reencrypt_get_sector_size_new(hdr);
if (ss > 0 && (size_t)ss > alignment) if (ss > 0 && (size_t)ss > alignment)
alignment = (size_t)ss; alignment = (size_t)ss;
return alignment; return alignment;
} }
/* returns void because it must not fail on valid LUKS2 header */ /* returns void because it must not fail on valid LUKS2 header */
static void _load_backup_segments(struct luks2_hdr *hdr, static void _load_backup_segments(struct luks2_hdr *hdr,
struct luks2_reenc_context *rh) struct luks2_reencrypt *rh)
{ {
int segment = LUKS2_get_segment_id_by_flag(hdr, "backup-final"); int segment = LUKS2_get_segment_id_by_flag(hdr, "backup-final");
if (segment >= 0) { if (segment >= 0) {
rh->jobj_segment_new = json_object_get(LUKS2_get_segment_jobj(hdr , segment)); rh->jobj_segment_new = json_object_get(LUKS2_get_segment_jobj(hdr , segment));
rh->digest_new = LUKS2_digest_by_segment(hdr, segment); rh->digest_new = LUKS2_digest_by_segment(hdr, segment);
} else { } else {
rh->jobj_segment_new = NULL; rh->jobj_segment_new = NULL;
rh->digest_new = -ENOENT; rh->digest_new = -ENOENT;
} }
skipping to change at line 749 skipping to change at line 850
if (segs == 1) { if (segs == 1) {
*offset = 0; *offset = 0;
return 0; return 0;
} }
/* should be unreachable */ /* should be unreachable */
return -EINVAL; return -EINVAL;
} }
static int _offset_forward(struct luks2_hdr *hdr, json_object *jobj_segments, ui nt64_t *offset) static int _offset_forward(json_object *jobj_segments, uint64_t *offset)
{ {
int segs = json_segments_count(jobj_segments); int segs = json_segments_count(jobj_segments);
if (segs == 1) if (segs == 1)
*offset = 0; *offset = 0;
else if (segs == 2) { else if (segs == 2) {
*offset = json_segment_get_size(json_segments_get_segment(jobj_se gments, 0), 0); *offset = json_segment_get_size(json_segments_get_segment(jobj_se gments, 0), 0);
if (!*offset) if (!*offset)
return -EINVAL; return -EINVAL;
} else } else
return -EINVAL; return -EINVAL;
return 0; return 0;
} }
static int _offset_backward(struct luks2_hdr *hdr, json_object *jobj_segments, u int64_t device_size, uint64_t *length, uint64_t *offset) static int _offset_backward(json_object *jobj_segments, uint64_t device_size, ui nt64_t *length, uint64_t *offset)
{ {
int segs = json_segments_count(jobj_segments); int segs = json_segments_count(jobj_segments);
uint64_t tmp; uint64_t tmp;
if (segs == 1) { if (segs == 1) {
if (device_size < *length) if (device_size < *length)
*length = device_size; *length = device_size;
*offset = device_size - *length; *offset = device_size - *length;
} else if (segs == 2) { } else if (segs == 2) {
tmp = json_segment_get_size(json_segments_get_segment(jobj_segmen ts, 0), 0); tmp = json_segment_get_size(json_segments_get_segment(jobj_segmen ts, 0), 0);
skipping to change at line 809 skipping to change at line 910
/* if there's segment in reencryption return directly offset of it */ /* if there's segment in reencryption return directly offset of it */
json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments); json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments);
sg = json_segments_segment_in_reencrypt(jobj_segments); sg = json_segments_segment_in_reencrypt(jobj_segments);
if (sg >= 0) { if (sg >= 0) {
*offset = LUKS2_segment_offset(hdr, sg, 0) - (reencrypt_get_data_ offset_new(hdr)); *offset = LUKS2_segment_offset(hdr, sg, 0) - (reencrypt_get_data_ offset_new(hdr));
return 0; return 0;
} }
if (di == CRYPT_REENCRYPT_FORWARD) if (di == CRYPT_REENCRYPT_FORWARD)
return _offset_forward(hdr, jobj_segments, offset); return _offset_forward(jobj_segments, offset);
else if (di == CRYPT_REENCRYPT_BACKWARD) { else if (di == CRYPT_REENCRYPT_BACKWARD) {
if (reencrypt_mode(hdr) == CRYPT_REENCRYPT_ENCRYPT && if (reencrypt_mode(hdr) == CRYPT_REENCRYPT_ENCRYPT &&
LUKS2_get_segment_id_by_flag(hdr, "backup-moved-segment") >= 0) LUKS2_get_segment_id_by_flag(hdr, "backup-moved-segment") >= 0)
return reencrypt_offset_backward_moved(hdr, jobj_segments , reencrypt_length, data_shift, offset); return reencrypt_offset_backward_moved(hdr, jobj_segments , reencrypt_length, data_shift, offset);
return _offset_backward(hdr, jobj_segments, device_size, reencryp t_length, offset); return _offset_backward(jobj_segments, device_size, reencrypt_len gth, offset);
} }
return -EINVAL; return -EINVAL;
} }
static uint64_t reencrypt_length(struct crypt_device *cd, static uint64_t reencrypt_length(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
struct luks2_reenc_context *rh, struct luks2_reencrypt *rh,
uint64_t keyslot_area_length, uint64_t keyslot_area_length,
uint64_t length_max) uint64_t length_max)
{ {
unsigned long dummy, optimal_alignment; unsigned long dummy, optimal_alignment;
uint64_t length, soft_mem_limit; uint64_t length, soft_mem_limit;
if (rh->rp.type == REENC_PROTECTION_NONE) if (rh->rp.type == REENC_PROTECTION_NONE)
length = length_max ?: LUKS2_DEFAULT_NONE_REENCRYPTION_LENGTH; length = length_max ?: LUKS2_DEFAULT_NONE_REENCRYPTION_LENGTH;
else if (rh->rp.type == REENC_PROTECTION_CHECKSUM) else if (rh->rp.type == REENC_PROTECTION_CHECKSUM)
length = (keyslot_area_length / rh->rp.p.csum.hash_size) * rh->al ignment; length = (keyslot_area_length / rh->rp.p.csum.hash_size) * rh->al ignment;
skipping to change at line 870 skipping to change at line 971
if (optimal_alignment % rh->alignment) if (optimal_alignment % rh->alignment)
return length; return length;
/* align to opt-io size only if remaining size allows it */ /* align to opt-io size only if remaining size allows it */
if (length > optimal_alignment) if (length > optimal_alignment)
length -= (length % optimal_alignment); length -= (length % optimal_alignment);
return length; return length;
} }
static int reencrypt_context_init(struct crypt_device *cd, struct luks2_hdr *hdr , struct luks2_reenc_context *rh, uint64_t device_size, const struct crypt_param s_reencrypt *params) static int reencrypt_context_init(struct crypt_device *cd, struct luks2_hdr *hdr , struct luks2_reencrypt *rh, uint64_t device_size, const struct crypt_params_re encrypt *params)
{ {
int r; int r;
uint64_t dummy, area_length; uint64_t dummy, area_length;
rh->reenc_keyslot = LUKS2_find_keyslot(hdr, "reencrypt"); rh->reenc_keyslot = LUKS2_find_keyslot(hdr, "reencrypt");
if (rh->reenc_keyslot < 0) if (rh->reenc_keyslot < 0)
return -EINVAL; return -EINVAL;
if (LUKS2_keyslot_area(hdr, rh->reenc_keyslot, &dummy, &area_length) < 0) if (LUKS2_keyslot_area(hdr, rh->reenc_keyslot, &dummy, &area_length) < 0)
return -EINVAL; return -EINVAL;
skipping to change at line 990 skipping to change at line 1091
log_dbg(cd, "reencrypt offset: %" PRIu64, rh->offset); log_dbg(cd, "reencrypt offset: %" PRIu64, rh->offset);
log_dbg(cd, "reencrypt shift: %s%" PRIu64, (rh->data_shift && rh->directi on == CRYPT_REENCRYPT_BACKWARD ? "-" : ""), rh->data_shift); log_dbg(cd, "reencrypt shift: %s%" PRIu64, (rh->data_shift && rh->directi on == CRYPT_REENCRYPT_BACKWARD ? "-" : ""), rh->data_shift);
log_dbg(cd, "reencrypt alignment: %zu", rh->alignment); log_dbg(cd, "reencrypt alignment: %zu", rh->alignment);
log_dbg(cd, "reencrypt progress: %" PRIu64, rh->progress); log_dbg(cd, "reencrypt progress: %" PRIu64, rh->progress);
rh->device_size = device_size; rh->device_size = device_size;
return rh->length < 512 ? -EINVAL : 0; return rh->length < 512 ? -EINVAL : 0;
} }
static size_t reencrypt_buffer_length(struct luks2_reenc_context *rh) static size_t reencrypt_buffer_length(struct luks2_reencrypt *rh)
{ {
if (rh->data_shift) if (rh->data_shift)
return rh->data_shift; return rh->data_shift;
return rh->length; return rh->length;
} }
static int reencrypt_load_clean(struct crypt_device *cd, static int reencrypt_load_clean(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
uint64_t device_size, uint64_t device_size,
struct luks2_reenc_context **rh, struct luks2_reencrypt **rh,
const struct crypt_params_reencrypt *params) const struct crypt_params_reencrypt *params)
{ {
int r; int r;
const struct crypt_params_reencrypt hdr_reenc_params = { const struct crypt_params_reencrypt hdr_reenc_params = {
.resilience = reencrypt_resilience_type(hdr), .resilience = reencrypt_resilience_type(hdr),
.hash = reencrypt_resilience_hash(hdr), .hash = reencrypt_resilience_hash(hdr),
.device_size = params ? params->device_size : 0 .device_size = params ? params->device_size : 0
}; };
struct luks2_reenc_context *tmp = crypt_zalloc(sizeof (*tmp)); struct luks2_reencrypt *tmp = crypt_zalloc(sizeof (*tmp));
if (!tmp) if (!tmp)
return -ENOMEM; return -ENOMEM;
r = -EINVAL; r = -EINVAL;
if (!hdr_reenc_params.resilience) if (!hdr_reenc_params.resilience)
goto err; goto err;
/* skip context update if data shift is detected in header */ /* skip context update if data shift is detected in header */
if (!strcmp(hdr_reenc_params.resilience, "datashift")) if (!strcmp(hdr_reenc_params.resilience, "datashift"))
skipping to change at line 1041 skipping to change at line 1142
if (posix_memalign(&tmp->reenc_buffer, device_alignment(crypt_data_device (cd)), if (posix_memalign(&tmp->reenc_buffer, device_alignment(crypt_data_device (cd)),
reencrypt_buffer_length(tmp))) { reencrypt_buffer_length(tmp))) {
r = -ENOMEM; r = -ENOMEM;
goto err; goto err;
} }
*rh = tmp; *rh = tmp;
return 0; return 0;
err: err:
LUKS2_reenc_context_free(cd, tmp); LUKS2_reencrypt_free(cd, tmp);
return r; return r;
} }
static int reencrypt_make_segments(struct crypt_device *cd, static int reencrypt_make_segments(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
struct luks2_reenc_context *rh, struct luks2_reencrypt *rh,
uint64_t device_size) uint64_t device_size)
{ {
int r; int r;
uint64_t data_offset = reencrypt_get_data_offset_new(hdr); uint64_t data_offset = reencrypt_get_data_offset_new(hdr);
log_dbg(cd, "Calculating segments."); log_dbg(cd, "Calculating segments.");
r = reencrypt_make_hot_segments(cd, hdr, rh, device_size, data_offset); r = reencrypt_make_hot_segments(cd, hdr, rh, device_size, data_offset);
if (!r) { if (!r) {
r = reencrypt_make_post_segments(cd, hdr, rh, data_offset); r = reencrypt_make_post_segments(cd, hdr, rh, data_offset);
skipping to change at line 1071 skipping to change at line 1172
} }
if (r) if (r)
log_dbg(cd, "Failed to make reencryption segments."); log_dbg(cd, "Failed to make reencryption segments.");
return r; return r;
} }
static int reencrypt_make_segments_crashed(struct crypt_device *cd, static int reencrypt_make_segments_crashed(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
struct luks2_reenc_context *rh) struct luks2_reencrypt *rh)
{ {
int r; int r;
uint64_t data_offset = crypt_get_data_offset(cd) << SECTOR_SHIFT; uint64_t data_offset = crypt_get_data_offset(cd) << SECTOR_SHIFT;
if (!rh) if (!rh)
return -EINVAL; return -EINVAL;
rh->jobj_segs_hot = json_object_new_object(); rh->jobj_segs_hot = json_object_new_object();
if (!rh->jobj_segs_hot) if (!rh->jobj_segs_hot)
return -ENOMEM; return -ENOMEM;
skipping to change at line 1099 skipping to change at line 1200
r = reencrypt_make_post_segments(cd, hdr, rh, data_offset); r = reencrypt_make_post_segments(cd, hdr, rh, data_offset);
if (r) { if (r) {
json_object_put(rh->jobj_segs_hot); json_object_put(rh->jobj_segs_hot);
rh->jobj_segs_hot = NULL; rh->jobj_segs_hot = NULL;
} }
return r; return r;
} }
static int reencrypt_load_crashed(struct crypt_device *cd, static int reencrypt_load_crashed(struct crypt_device *cd,
struct luks2_hdr *hdr, uint64_t device_size, struct luks2_reenc_context * *rh) struct luks2_hdr *hdr, uint64_t device_size, struct luks2_reencrypt **rh)
{ {
bool dynamic; bool dynamic;
uint64_t minimal_size; uint64_t minimal_size;
int r, reenc_seg; int r, reenc_seg;
struct crypt_params_reencrypt params = {}; struct crypt_params_reencrypt params = {};
if (LUKS2_get_data_size(hdr, &minimal_size, &dynamic)) if (LUKS2_get_data_size(hdr, &minimal_size, &dynamic))
return -EINVAL; return -EINVAL;
if (!dynamic) if (!dynamic)
skipping to change at line 1135 skipping to change at line 1236
if (!(*rh)->alignment) { if (!(*rh)->alignment) {
log_dbg(cd, "Failed to get read resilience sector_size fr om metadata."); log_dbg(cd, "Failed to get read resilience sector_size fr om metadata.");
r = -EINVAL; r = -EINVAL;
} }
} }
if (!r) if (!r)
r = reencrypt_make_segments_crashed(cd, hdr, *rh); r = reencrypt_make_segments_crashed(cd, hdr, *rh);
if (r) { if (r) {
LUKS2_reenc_context_free(cd, *rh); LUKS2_reencrypt_free(cd, *rh);
*rh = NULL; *rh = NULL;
} }
return r; return r;
} }
static int reencrypt_init_storage_wrappers(struct crypt_device *cd, static int reencrypt_init_storage_wrappers(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
struct luks2_reenc_context *rh, struct luks2_reencrypt *rh,
struct volume_key *vks) struct volume_key *vks)
{ {
int r; int r;
struct volume_key *vk; struct volume_key *vk;
uint32_t wrapper_flags = (getuid() || geteuid()) ? 0 : DISABLE_KCAPI; uint32_t wrapper_flags = (getuid() || geteuid()) ? 0 : DISABLE_KCAPI;
vk = crypt_volume_key_by_id(vks, rh->digest_old); vk = crypt_volume_key_by_id(vks, rh->digest_old);
r = crypt_storage_wrapper_init(cd, &rh->cw1, crypt_data_device(cd), r = crypt_storage_wrapper_init(cd, &rh->cw1, crypt_data_device(cd),
reencrypt_get_data_offset_old(hdr), reencrypt_get_data_offset_old(hdr),
crypt_get_iv_offset(cd), crypt_get_iv_offset(cd),
skipping to change at line 1181 skipping to change at line 1282
if (r) { if (r) {
log_err(cd, _("Failed to initialize new segment storage wrapper." )); log_err(cd, _("Failed to initialize new segment storage wrapper." ));
return r; return r;
} }
rh->wflags2 = wrapper_flags; rh->wflags2 = wrapper_flags;
log_dbg(cd, "New cipher storage wrapper type: %d", crypt_storage_wrapper_ get_type(rh->cw2)); log_dbg(cd, "New cipher storage wrapper type: %d", crypt_storage_wrapper_ get_type(rh->cw2));
return 0; return 0;
} }
static int reencrypt_context_set_names(struct luks2_reenc_context *rh, const cha r *name) static int reencrypt_context_set_names(struct luks2_reencrypt *rh, const char *n ame)
{ {
if (!rh | !name) if (!rh | !name)
return -EINVAL; return -EINVAL;
if (*name == '/') { if (*name == '/') {
if (!(rh->device_name = dm_device_name(name))) if (!(rh->device_name = dm_device_name(name)))
return -EINVAL; return -EINVAL;
} else if (!(rh->device_name = strdup(name))) } else if (!(rh->device_name = strdup(name)))
return -ENOMEM; return -ENOMEM;
skipping to change at line 1254 skipping to change at line 1355
else else
reqs &= ~CRYPT_REQUIREMENT_ONLINE_REENCRYPT; reqs &= ~CRYPT_REQUIREMENT_ONLINE_REENCRYPT;
log_dbg(cd, "Going to %s reencryption requirement flag.", enable ? "store " : "wipe"); log_dbg(cd, "Going to %s reencryption requirement flag.", enable ? "store " : "wipe");
return LUKS2_config_set_requirements(cd, hdr, reqs, commit); return LUKS2_config_set_requirements(cd, hdr, reqs, commit);
} }
static int reencrypt_recover_segment(struct crypt_device *cd, static int reencrypt_recover_segment(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
struct luks2_reenc_context *rh, struct luks2_reencrypt *rh,
struct volume_key *vks) struct volume_key *vks)
{ {
struct volume_key *vk_old, *vk_new; struct volume_key *vk_old, *vk_new;
size_t count, s; size_t count, s;
ssize_t read, w; ssize_t read, w;
unsigned resilience; unsigned resilience;
uint64_t area_offset, area_length, area_length_read, crash_iv_offset, uint64_t area_offset, area_length, area_length_read, crash_iv_offset,
data_offset = crypt_get_data_offset(cd) << SECTOR_SHIFT; data_offset = crypt_get_data_offset(cd) << SECTOR_SHIFT;
int devfd, r, new_sector_size, old_sector_size, rseg = json_segments_segm ent_in_reencrypt(rh->jobj_segs_hot); int devfd, r, new_sector_size, old_sector_size, rseg = json_segments_segm ent_in_reencrypt(rh->jobj_segs_hot);
char *checksum_tmp = NULL, *data_buffer = NULL; char *checksum_tmp = NULL, *data_buffer = NULL;
skipping to change at line 1468 skipping to change at line 1569
rh->read = rh->length; rh->read = rh->length;
out: out:
free(data_buffer); free(data_buffer);
free(checksum_tmp); free(checksum_tmp);
crypt_storage_wrapper_destroy(cw1); crypt_storage_wrapper_destroy(cw1);
crypt_storage_wrapper_destroy(cw2); crypt_storage_wrapper_destroy(cw2);
return r; return r;
} }
static int reencrypt_add_moved_segment(struct crypt_device *cd, static int reencrypt_add_moved_segment(struct luks2_hdr *hdr, struct luks2_reenc
struct luks2_hdr *hdr, rypt *rh)
struct luks2_reenc_context *rh)
{ {
int s = LUKS2_segment_first_unused_id(hdr); int s = LUKS2_segment_first_unused_id(hdr);
if (!rh->jobj_segment_moved) if (!rh->jobj_segment_moved)
return 0; return 0;
if (s < 0) if (s < 0)
return s; return s;
if (json_object_object_add_by_uint(LUKS2_get_segments_jobj(hdr), s, json_ object_get(rh->jobj_segment_moved))) { if (json_object_object_add_by_uint(LUKS2_get_segments_jobj(hdr), s, json_ object_get(rh->jobj_segment_moved))) {
json_object_put(rh->jobj_segment_moved); json_object_put(rh->jobj_segment_moved);
return -EINVAL; return -EINVAL;
} }
return 0; return 0;
} }
static int reencrypt_add_backup_segment(struct crypt_device *cd, static int reencrypt_add_backup_segment(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
struct luks2_reenc_context *rh, struct luks2_reencrypt *rh,
unsigned final) unsigned final)
{ {
int digest, s = LUKS2_segment_first_unused_id(hdr); int digest, s = LUKS2_segment_first_unused_id(hdr);
json_object *jobj; json_object *jobj;
if (s < 0) if (s < 0)
return s; return s;
digest = final ? rh->digest_new : rh->digest_old; digest = final ? rh->digest_new : rh->digest_old;
jobj = final ? rh->jobj_segment_new : rh->jobj_segment_old; jobj = final ? rh->jobj_segment_new : rh->jobj_segment_old;
skipping to change at line 1515 skipping to change at line 1614
} }
if (strcmp(json_segment_type(jobj), "crypt")) if (strcmp(json_segment_type(jobj), "crypt"))
return 0; return 0;
return LUKS2_digest_segment_assign(cd, hdr, s, digest, 1, 0); return LUKS2_digest_segment_assign(cd, hdr, s, digest, 1, 0);
} }
static int reencrypt_assign_segments_simple(struct crypt_device *cd, static int reencrypt_assign_segments_simple(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
struct luks2_reenc_context *rh, struct luks2_reencrypt *rh,
unsigned hot, unsigned hot,
unsigned commit) unsigned commit)
{ {
int r, sg; int r, sg;
if (hot && json_segments_count(rh->jobj_segs_hot) > 0) { if (hot && json_segments_count(rh->jobj_segs_hot) > 0) {
log_dbg(cd, "Setting 'hot' segments."); log_dbg(cd, "Setting 'hot' segments.");
r = LUKS2_segments_set(cd, hdr, rh->jobj_segs_hot, 0); r = LUKS2_segments_set(cd, hdr, rh->jobj_segs_hot, 0);
if (!r) if (!r)
skipping to change at line 1554 skipping to change at line 1653
log_dbg(cd, "Failed to assign reencryption previous backup segmen t."); log_dbg(cd, "Failed to assign reencryption previous backup segmen t.");
return r; return r;
} }
r = reencrypt_add_backup_segment(cd, hdr, rh, 1); r = reencrypt_add_backup_segment(cd, hdr, rh, 1);
if (r) { if (r) {
log_dbg(cd, "Failed to assign reencryption final backup segment." ); log_dbg(cd, "Failed to assign reencryption final backup segment." );
return r; return r;
} }
r = reencrypt_add_moved_segment(cd, hdr, rh); r = reencrypt_add_moved_segment(hdr, rh);
if (r) { if (r) {
log_dbg(cd, "Failed to assign reencryption moved backup segment." ); log_dbg(cd, "Failed to assign reencryption moved backup segment." );
return r; return r;
} }
for (sg = 0; sg < LUKS2_segments_count(hdr); sg++) { for (sg = 0; sg < LUKS2_segments_count(hdr); sg++) {
if (LUKS2_segment_is_type(hdr, sg, "crypt") && if (LUKS2_segment_is_type(hdr, sg, "crypt") &&
LUKS2_digest_segment_assign(cd, hdr, sg, rh->mode == CRYPT_RE ENCRYPT_ENCRYPT ? rh->digest_new : rh->digest_old, 1, 0)) { LUKS2_digest_segment_assign(cd, hdr, sg, rh->mode == CRYPT_RE ENCRYPT_ENCRYPT ? rh->digest_new : rh->digest_old, 1, 0)) {
log_dbg(cd, "Failed to assign digest %u to segment %u.", rh->digest_new, sg); log_dbg(cd, "Failed to assign digest %u to segment %u.", rh->digest_new, sg);
return -EINVAL; return -EINVAL;
} }
} }
return commit ? LUKS2_hdr_write(cd, hdr) : 0; return commit ? LUKS2_hdr_write(cd, hdr) : 0;
} }
static int reencrypt_assign_segments(struct crypt_device *cd, static int reencrypt_assign_segments(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
struct luks2_reenc_context *rh, struct luks2_reencrypt *rh,
unsigned hot, unsigned hot,
unsigned commit) unsigned commit)
{ {
bool forward; bool forward;
int rseg, scount, r = -EINVAL; int rseg, scount, r = -EINVAL;
/* FIXME: validate in reencrypt context load */ /* FIXME: validate in reencrypt context load */
if (rh->digest_new < 0 && rh->mode != CRYPT_REENCRYPT_DECRYPT) if (rh->digest_new < 0 && rh->mode != CRYPT_REENCRYPT_DECRYPT)
return -EINVAL; return -EINVAL;
skipping to change at line 1686 skipping to change at line 1785
jobj_segments = json_object_new_object(); jobj_segments = json_object_new_object();
if (!jobj_segments) if (!jobj_segments)
return -ENOMEM; return -ENOMEM;
r = -EINVAL; r = -EINVAL;
if (move_first_segment) { if (move_first_segment) {
jobj_segment_first = json_segment_create_linear(first_segment_of fset, &first_segment_length, 0); jobj_segment_first = json_segment_create_linear(first_segment_of fset, &first_segment_length, 0);
if (second_segment_length && if (second_segment_length &&
!(jobj_segment_second = json_segment_create_linear(second_seg ment_offset, &second_segment_length, 0))) { !(jobj_segment_second = json_segment_create_linear(second_seg ment_offset, &second_segment_length, 0))) {
log_dbg(cd, "Failed generate 2nd segment."); log_dbg(cd, "Failed generate 2nd segment.");
goto err; return r;
} }
} else } else
jobj_segment_first = json_segment_create_linear(first_segment_of fset, first_segment_length ? &first_segment_length : NULL, 0); jobj_segment_first = json_segment_create_linear(first_segment_of fset, first_segment_length ? &first_segment_length : NULL, 0);
if (!jobj_segment_first) { if (!jobj_segment_first) {
log_dbg(cd, "Failed generate 1st segment."); log_dbg(cd, "Failed generate 1st segment.");
goto err; return r;
} }
json_object_object_add(jobj_segments, "0", jobj_segment_first); json_object_object_add(jobj_segments, "0", jobj_segment_first);
if (jobj_segment_second) if (jobj_segment_second)
json_object_object_add(jobj_segments, "1", jobj_segment_second); json_object_object_add(jobj_segments, "1", jobj_segment_second);
r = LUKS2_digest_segment_assign(cd, hdr, CRYPT_ANY_SEGMENT, CRYPT_ANY_DIG EST, 0, 0); r = LUKS2_digest_segment_assign(cd, hdr, CRYPT_ANY_SEGMENT, CRYPT_ANY_DIG EST, 0, 0);
if (!r) return r ?: LUKS2_segments_set(cd, hdr, jobj_segments, 0);
r = LUKS2_segments_set(cd, hdr, jobj_segments, 0);
err:
return r;
} }
static int reencrypt_make_targets(struct crypt_device *cd, static int reencrypt_make_targets(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
struct device *hz_device, struct device *hz_device,
struct volume_key *vks, struct volume_key *vks,
struct dm_target *result, struct dm_target *result,
uint64_t size) uint64_t size)
{ {
bool reenc_seg; bool reenc_seg;
struct volume_key *vk; struct volume_key *vk;
uint64_t segment_size, segment_offset, segment_start = 0; uint64_t segment_size, segment_offset, segment_start = 0;
int r; int r;
int s = 0; int s = 0;
json_object *jobj, *jobj_segments = LUKS2_get_segments_jobj(hdr); json_object *jobj, *jobj_segments = LUKS2_get_segments_jobj(hdr);
while (result) { while (result) {
jobj = json_segments_get_segment(jobj_segments, s); jobj = json_segments_get_segment(jobj_segments, s);
if (!jobj) { if (!jobj) {
log_dbg(cd, "Internal error. Segment %u is null.", s); log_dbg(cd, "Internal error. Segment %u is null.", s);
r = -EINVAL; return -EINVAL;
goto out;
} }
reenc_seg = (s == json_segments_segment_in_reencrypt(jobj_segment s)); reenc_seg = (s == json_segments_segment_in_reencrypt(jobj_segment s));
segment_offset = json_segment_get_offset(jobj, 1); segment_offset = json_segment_get_offset(jobj, 1);
segment_size = json_segment_get_size(jobj, 1); segment_size = json_segment_get_size(jobj, 1);
/* 'dynamic' length allowed in last segment only */ /* 'dynamic' length allowed in last segment only */
if (!segment_size && !result->next) if (!segment_size && !result->next)
segment_size = (size >> SECTOR_SHIFT) - segment_start; segment_size = (size >> SECTOR_SHIFT) - segment_start;
if (!segment_size) { if (!segment_size) {
log_dbg(cd, "Internal error. Wrong segment size %u", s); log_dbg(cd, "Internal error. Wrong segment size %u", s);
r = -EINVAL; return -EINVAL;
goto out;
} }
if (!strcmp(json_segment_type(jobj), "crypt")) { if (!strcmp(json_segment_type(jobj), "crypt")) {
vk = crypt_volume_key_by_id(vks, reenc_seg ? LUKS2_reencr ypt_digest_new(hdr) : LUKS2_digest_by_segment(hdr, s)); vk = crypt_volume_key_by_id(vks, reenc_seg ? LUKS2_reencr ypt_digest_new(hdr) : LUKS2_digest_by_segment(hdr, s));
if (!vk) { if (!vk) {
log_err(cd, _("Missing key for dm-crypt segment % u"), s); log_err(cd, _("Missing key for dm-crypt segment % u"), s);
r = -EINVAL; return -EINVAL;
goto out;
} }
if (reenc_seg) if (reenc_seg)
segment_offset -= crypt_get_data_offset(cd); segment_offset -= crypt_get_data_offset(cd);
r = dm_crypt_target_set(result, segment_start, segment_si ze, r = dm_crypt_target_set(result, segment_start, segment_si ze,
reenc_seg ? hz_device : crypt_dat a_device(cd), reenc_seg ? hz_device : crypt_dat a_device(cd),
vk, vk,
json_segment_get_cipher(jobj), json_segment_get_cipher(jobj),
json_segment_get_iv_offset(jobj), json_segment_get_iv_offset(jobj),
segment_offset, segment_offset,
"none", "none",
0, 0,
json_segment_get_sector_size(jobj )); json_segment_get_sector_size(jobj ));
if (r) { if (r) {
log_err(cd, _("Failed to set dm-crypt segment.")) ; log_err(cd, _("Failed to set dm-crypt segment.")) ;
goto out; return r;
} }
} else if (!strcmp(json_segment_type(jobj), "linear")) { } else if (!strcmp(json_segment_type(jobj), "linear")) {
r = dm_linear_target_set(result, segment_start, segment_s ize, reenc_seg ? hz_device : crypt_data_device(cd), segment_offset); r = dm_linear_target_set(result, segment_start, segment_s ize, reenc_seg ? hz_device : crypt_data_device(cd), segment_offset);
if (r) { if (r) {
log_err(cd, _("Failed to set dm-linear segment.") ); log_err(cd, _("Failed to set dm-linear segment.") );
goto out; return r;
} }
} else { } else
r = -EINVAL; return EINVAL;
goto out;
}
segment_start += segment_size; segment_start += segment_size;
s++; s++;
result = result->next; result = result->next;
} }
return s; return s;
out:
return r;
} }
/* GLOBAL FIXME: audit function names and parameters names */ /* GLOBAL FIXME: audit function names and parameters names */
/* FIXME: /* FIXME:
* 1) audit log routines * 1) audit log routines
* 2) can't we derive hotzone device name from crypt context? (unlocked name , device uuid, etc?) * 2) can't we derive hotzone device name from crypt context? (unlocked name , device uuid, etc?)
*/ */
static int reencrypt_load_overlay_device(struct crypt_device *cd, struct luks2_h dr *hdr, static int reencrypt_load_overlay_device(struct crypt_device *cd, struct luks2_h dr *hdr,
const char *overlay, const char *hotzone, struct volume_key *vks, uint64_ t size, const char *overlay, const char *hotzone, struct volume_key *vks, uint64_ t size,
skipping to change at line 1860 skipping to change at line 1949
return r; return r;
} }
r = dm_query_device(cd, source, DM_ACTIVE_DEVICE | DM_ACTIVE_CRYPT_CIPHER | r = dm_query_device(cd, source, DM_ACTIVE_DEVICE | DM_ACTIVE_CRYPT_CIPHER |
DM_ACTIVE_CRYPT_KEYSIZE | DM_ACTIVE_CRYPT_KEY, &dmd_s ource); DM_ACTIVE_CRYPT_KEYSIZE | DM_ACTIVE_CRYPT_KEY, &dmd_s ource);
if (r < 0) if (r < 0)
return r; return r;
if (exists && ((r = dm_query_device(cd, target, 0, &dmd_target)) < 0)) if (exists && ((r = dm_query_device(cd, target, 0, &dmd_target)) < 0))
goto err; goto out;
dmd_source.flags |= flags; dmd_source.flags |= flags;
dmd_source.uuid = crypt_get_uuid(cd); dmd_source.uuid = crypt_get_uuid(cd);
if (exists) { if (exists) {
if (dmd_target.size != dmd_source.size) { if (dmd_target.size != dmd_source.size) {
log_err(cd, _("Source and target device sizes don't match . Source %" PRIu64 ", target: %" PRIu64 "."), log_err(cd, _("Source and target device sizes don't match . Source %" PRIu64 ", target: %" PRIu64 "."),
dmd_source.size, dmd_target.size); dmd_source.size, dmd_target.size);
r = -EINVAL; r = -EINVAL;
goto err; goto out;
} }
r = dm_reload_device(cd, target, &dmd_source, 0, 0); r = dm_reload_device(cd, target, &dmd_source, 0, 0);
if (!r) { if (!r) {
log_dbg(cd, "Resuming device %s", target); log_dbg(cd, "Resuming device %s", target);
r = dm_resume_device(cd, target, dmflags | act2dmflags(dm d_source.flags)); r = dm_resume_device(cd, target, dmflags | act2dmflags(dm d_source.flags));
} }
} else } else
r = dm_create_device(cd, target, CRYPT_SUBDEV, &dmd_source); r = dm_create_device(cd, target, CRYPT_SUBDEV, &dmd_source);
err: out:
dm_targets_free(cd, &dmd_source); dm_targets_free(cd, &dmd_source);
dm_targets_free(cd, &dmd_target); dm_targets_free(cd, &dmd_target);
return r; return r;
} }
static int reencrypt_swap_backing_device(struct crypt_device *cd, const char *na me, static int reencrypt_swap_backing_device(struct crypt_device *cd, const char *na me,
const char *new_backend_name) const char *new_backend_name)
{ {
int r; int r;
skipping to change at line 1944 skipping to change at line 2033
.flags = flags, .flags = flags,
.uuid = crypt_get_uuid(cd), .uuid = crypt_get_uuid(cd),
.size = device_size >> SECTOR_SHIFT .size = device_size >> SECTOR_SHIFT
}; };
log_dbg(cd, "Activating hotzone device %s.", name); log_dbg(cd, "Activating hotzone device %s.", name);
r = device_block_adjust(cd, crypt_data_device(cd), DEV_OK, r = device_block_adjust(cd, crypt_data_device(cd), DEV_OK,
new_offset, &dmd.size, &dmd.flags); new_offset, &dmd.size, &dmd.flags);
if (r) if (r)
goto err; goto out;
r = dm_linear_target_set(&dmd.segment, 0, dmd.size, crypt_data_device(cd) , new_offset); r = dm_linear_target_set(&dmd.segment, 0, dmd.size, crypt_data_device(cd) , new_offset);
if (r) if (r)
goto err; goto out;
r = dm_create_device(cd, name, CRYPT_SUBDEV, &dmd); r = dm_create_device(cd, name, CRYPT_SUBDEV, &dmd);
err: out:
dm_targets_free(cd, &dmd); dm_targets_free(cd, &dmd);
return r; return r;
} }
static int reencrypt_init_device_stack(struct crypt_device *cd, static int reencrypt_init_device_stack(struct crypt_device *cd,
const struct luks2_reenc_context *rh) const struct luks2_reencrypt *rh)
{ {
int r; int r;
/* Activate hotzone device 1:1 linear mapping to data_device */ /* Activate hotzone device 1:1 linear mapping to data_device */
r = reencrypt_activate_hotzone_device(cd, rh->hotzone_name, rh->device_si ze, CRYPT_ACTIVATE_PRIVATE); r = reencrypt_activate_hotzone_device(cd, rh->hotzone_name, rh->device_si ze, CRYPT_ACTIVATE_PRIVATE);
if (r) { if (r) {
log_err(cd, _("Failed to activate hotzone device %s."), rh->hotzo ne_name); log_err(cd, _("Failed to activate hotzone device %s."), rh->hotzo ne_name);
return r; return r;
} }
skipping to change at line 2098 skipping to change at line 2187
if (posix_memalign(&buffer, device_alignment(crypt_data_device(cd)), buff er_len)) if (posix_memalign(&buffer, device_alignment(crypt_data_device(cd)), buff er_len))
return -ENOMEM; return -ENOMEM;
ret = read_lseek_blockwise(devfd, ret = read_lseek_blockwise(devfd,
device_block_size(cd, crypt_data_device(cd)), device_block_size(cd, crypt_data_device(cd)),
device_alignment(crypt_data_device(cd)), device_alignment(crypt_data_device(cd)),
buffer, buffer_len, 0); buffer, buffer_len, 0);
if (ret < 0 || (uint64_t)ret != buffer_len) { if (ret < 0 || (uint64_t)ret != buffer_len) {
r = -EIO; r = -EIO;
goto err; goto out;
} }
log_dbg(cd, "Going to write %" PRIu64 " bytes at offset %" PRIu64, buffer _len, offset); log_dbg(cd, "Going to write %" PRIu64 " bytes at offset %" PRIu64, buffer _len, offset);
ret = write_lseek_blockwise(devfd, ret = write_lseek_blockwise(devfd,
device_block_size(cd, crypt_data_device(cd)), device_block_size(cd, crypt_data_device(cd)),
device_alignment(crypt_data_device(cd)), device_alignment(crypt_data_device(cd)),
buffer, buffer_len, offset); buffer, buffer_len, offset);
if (ret < 0 || (uint64_t)ret != buffer_len) { if (ret < 0 || (uint64_t)ret != buffer_len) {
r = -EIO; r = -EIO;
goto err; goto out;
} }
r = 0; r = 0;
err: out:
memset(buffer, 0, buffer_len); memset(buffer, 0, buffer_len);
free(buffer); free(buffer);
return r; return r;
} }
static int reencrypt_make_backup_segments(struct crypt_device *cd, static int reencrypt_make_backup_segments(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
int keyslot_new, int keyslot_new,
const char *cipher, const char *cipher,
uint64_t data_offset, uint64_t data_offset,
skipping to change at line 2345 skipping to change at line 2434
if (r) if (r)
return r; return r;
dev_size -= data_offset; dev_size -= data_offset;
if (MISALIGNED(dev_size, sector_size)) { if (MISALIGNED(dev_size, sector_size)) {
log_err(cd, _("Data device is not aligned to requested encryption sector size (%" PRIu32 " bytes)."), sector_size); log_err(cd, _("Data device is not aligned to requested encryption sector size (%" PRIu32 " bytes)."), sector_size);
return -EINVAL; return -EINVAL;
} }
reencrypt_keyslot = LUKS2_keyslot_find_empty(hdr); reencrypt_keyslot = LUKS2_keyslot_find_empty(cd, hdr, 0);
if (reencrypt_keyslot < 0) { if (reencrypt_keyslot < 0) {
log_err(cd, _("All key slots full.")); log_err(cd, _("All key slots full."));
return -EINVAL; return -EINVAL;
} }
/* /*
* We must perform data move with exclusive open data device * We must perform data move with exclusive open data device
* to exclude another cryptsetup process to colide with * to exclude another cryptsetup process to colide with
* encryption initialization (or mount) * encryption initialization (or mount)
*/ */
skipping to change at line 2377 skipping to change at line 2466
if (devfd == -EBUSY) if (devfd == -EBUSY)
log_err(cd,_("Failed to open %s in exclusive mode (already mapped or mounted)."), device_path(crypt_data_device(cd))); log_err(cd,_("Failed to open %s in exclusive mode (already mapped or mounted)."), device_path(crypt_data_device(cd)));
return -EINVAL; return -EINVAL;
} }
} }
if (params->mode == CRYPT_REENCRYPT_ENCRYPT) { if (params->mode == CRYPT_REENCRYPT_ENCRYPT) {
/* in-memory only */ /* in-memory only */
r = reencrypt_set_encrypt_segments(cd, hdr, dev_size, params->dat a_shift << SECTOR_SHIFT, move_first_segment, params->direction); r = reencrypt_set_encrypt_segments(cd, hdr, dev_size, params->dat a_shift << SECTOR_SHIFT, move_first_segment, params->direction);
if (r) if (r)
goto err; goto out;
} }
r = LUKS2_keyslot_reencrypt_create(cd, hdr, reencrypt_keyslot, r = LUKS2_keyslot_reencrypt_create(cd, hdr, reencrypt_keyslot,
params); params);
if (r < 0) if (r < 0)
goto err; goto out;
r = reencrypt_make_backup_segments(cd, hdr, keyslot_new, _cipher, data_of fset, params); r = reencrypt_make_backup_segments(cd, hdr, keyslot_new, _cipher, data_of fset, params);
if (r) { if (r) {
log_dbg(cd, "Failed to create reencryption backup device segments ."); log_dbg(cd, "Failed to create reencryption backup device segments .");
goto err; goto out;
} }
r = LUKS2_keyslot_open_all_segments(cd, keyslot_old, keyslot_new, passphr ase, passphrase_size, vks); r = LUKS2_keyslot_open_all_segments(cd, keyslot_old, keyslot_new, passphr ase, passphrase_size, vks);
if (r < 0) if (r < 0)
goto err; goto out;
if (name && params->mode != CRYPT_REENCRYPT_ENCRYPT) { if (name && params->mode != CRYPT_REENCRYPT_ENCRYPT) {
r = reencrypt_verify_and_upload_keys(cd, hdr, LUKS2_reencrypt_dig est_old(hdr), LUKS2_reencrypt_digest_new(hdr), *vks); r = reencrypt_verify_and_upload_keys(cd, hdr, LUKS2_reencrypt_dig est_old(hdr), LUKS2_reencrypt_digest_new(hdr), *vks);
if (r) if (r)
goto err; goto out;
r = dm_query_device(cd, name, DM_ACTIVE_UUID | DM_ACTIVE_DEVICE | r = dm_query_device(cd, name, DM_ACTIVE_UUID | DM_ACTIVE_DEVICE |
DM_ACTIVE_CRYPT_KEYSIZE | DM_ACTIVE_CRYPT_KEY | DM_ACTIVE_CRYPT_KEYSIZE | DM_ACTIVE_CRYPT_KEY |
DM_ACTIVE_CRYPT_CIPHER, &dmd_target); DM_ACTIVE_CRYPT_CIPHER, &dmd_target);
if (r < 0) if (r < 0)
goto err; goto out;
r = LUKS2_assembly_multisegment_dmd(cd, hdr, *vks, LUKS2_get_segm ents_jobj(hdr), &dmd_source); r = LUKS2_assembly_multisegment_dmd(cd, hdr, *vks, LUKS2_get_segm ents_jobj(hdr), &dmd_source);
if (!r) { if (!r) {
r = crypt_compare_dm_devices(cd, &dmd_source, &dmd_target ); r = crypt_compare_dm_devices(cd, &dmd_source, &dmd_target );
if (r) if (r)
log_err(cd, _("Mismatching parameters on device % s."), name); log_err(cd, _("Mismatching parameters on device % s."), name);
} }
dm_targets_free(cd, &dmd_source); dm_targets_free(cd, &dmd_source);
dm_targets_free(cd, &dmd_target); dm_targets_free(cd, &dmd_target);
free(CONST_CAST(void*)dmd_target.uuid); free(CONST_CAST(void*)dmd_target.uuid);
if (r) if (r)
goto err; goto out;
} }
if (move_first_segment && reencrypt_move_data(cd, devfd, params->data_shi ft << SECTOR_SHIFT)) { if (move_first_segment && reencrypt_move_data(cd, devfd, params->data_shi ft << SECTOR_SHIFT)) {
r = -EIO; r = -EIO;
goto err; goto out;
} }
/* This must be first and only write in LUKS2 metadata during _reencrypt_ init */ /* This must be first and only write in LUKS2 metadata during _reencrypt_ init */
r = reencrypt_update_flag(cd, 1, true); r = reencrypt_update_flag(cd, 1, true);
if (r) { if (r) {
log_dbg(cd, "Failed to set online-reencryption requirement."); log_dbg(cd, "Failed to set online-reencryption requirement.");
r = -EINVAL; r = -EINVAL;
} else } else
r = reencrypt_keyslot; r = reencrypt_keyslot;
err: out:
device_release_excl(cd, crypt_data_device(cd)); device_release_excl(cd, crypt_data_device(cd));
if (r < 0) if (r < 0)
crypt_load(cd, CRYPT_LUKS2, NULL); crypt_load(cd, CRYPT_LUKS2, NULL);
return r; return r;
} }
static int reencrypt_hotzone_protect_final(struct crypt_device *cd, static int reencrypt_hotzone_protect_final(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_reenc_context *rh, struct luks2_hdr *hdr, struct luks2_reencrypt *rh,
const void *buffer, size_t buffer_len) const void *buffer, size_t buffer_len)
{ {
const void *pbuffer; const void *pbuffer;
size_t data_offset, len; size_t data_offset, len;
int r; int r;
if (rh->rp.type == REENC_PROTECTION_NONE) if (rh->rp.type == REENC_PROTECTION_NONE)
return 0; return 0;
if (rh->rp.type == REENC_PROTECTION_CHECKSUM) { if (rh->rp.type == REENC_PROTECTION_CHECKSUM) {
skipping to change at line 2484 skipping to change at line 2573
return -EINVAL; return -EINVAL;
log_dbg(cd, "Going to store %zu bytes in reencrypt keyslot.", len); log_dbg(cd, "Going to store %zu bytes in reencrypt keyslot.", len);
r = LUKS2_keyslot_reencrypt_store(cd, hdr, rh->reenc_keyslot, pbuffer, le n); r = LUKS2_keyslot_reencrypt_store(cd, hdr, rh->reenc_keyslot, pbuffer, le n);
return r > 0 ? 0 : r; return r > 0 ? 0 : r;
} }
static int reencrypt_context_update(struct crypt_device *cd, static int reencrypt_context_update(struct crypt_device *cd,
struct luks2_reenc_context *rh) struct luks2_reencrypt *rh)
{ {
if (rh->read < 0) if (rh->read < 0)
return -EINVAL; return -EINVAL;
if (rh->direction == CRYPT_REENCRYPT_BACKWARD) { if (rh->direction == CRYPT_REENCRYPT_BACKWARD) {
if (rh->data_shift && rh->mode == CRYPT_REENCRYPT_ENCRYPT) { if (rh->data_shift && rh->mode == CRYPT_REENCRYPT_ENCRYPT) {
if (rh->offset) if (rh->offset)
rh->offset -= rh->data_shift; rh->offset -= rh->data_shift;
if (rh->offset && (rh->offset < rh->data_shift)) { if (rh->offset && (rh->offset < rh->data_shift)) {
rh->length = rh->offset; rh->length = rh->offset;
skipping to change at line 2525 skipping to change at line 2614
} }
rh->progress += (uint64_t)rh->read; rh->progress += (uint64_t)rh->read;
return 0; return 0;
} }
static int reencrypt_load(struct crypt_device *cd, struct luks2_hdr *hdr, static int reencrypt_load(struct crypt_device *cd, struct luks2_hdr *hdr,
uint64_t device_size, uint64_t device_size,
const struct crypt_params_reencrypt *params, const struct crypt_params_reencrypt *params,
struct luks2_reenc_context **rh) struct luks2_reencrypt **rh)
{ {
int r; int r;
struct luks2_reenc_context *tmp = NULL; struct luks2_reencrypt *tmp = NULL;
crypt_reencrypt_info ri = LUKS2_reenc_status(hdr); crypt_reencrypt_info ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_CLEAN) if (ri == CRYPT_REENCRYPT_CLEAN)
r = reencrypt_load_clean(cd, hdr, device_size, &tmp, params); r = reencrypt_load_clean(cd, hdr, device_size, &tmp, params);
else if (ri == CRYPT_REENCRYPT_CRASH) else if (ri == CRYPT_REENCRYPT_CRASH)
r = reencrypt_load_crashed(cd, hdr, device_size, &tmp); r = reencrypt_load_crashed(cd, hdr, device_size, &tmp);
else if (ri == CRYPT_REENCRYPT_NONE) { else if (ri == CRYPT_REENCRYPT_NONE) {
log_err(cd, _("Device not marked for LUKS2 reencryption.")); log_err(cd, _("Device not marked for LUKS2 reencryption."));
return -EINVAL; return -EINVAL;
} else } else
r = -EINVAL; r = -EINVAL;
skipping to change at line 2565 skipping to change at line 2654
if (!crypt_metadata_locking_enabled()) { if (!crypt_metadata_locking_enabled()) {
*reencrypt_lock = NULL; *reencrypt_lock = NULL;
return 0; return 0;
} }
r = asprintf(&lock_resource, "LUKS2-reencryption-%s", uuid); r = asprintf(&lock_resource, "LUKS2-reencryption-%s", uuid);
if (r < 0) if (r < 0)
return -ENOMEM; return -ENOMEM;
if (r < 20) { if (r < 20) {
r = -EINVAL; free(lock_resource);
goto out; return -EINVAL;
} }
r = crypt_write_lock(cd, lock_resource, false, reencrypt_lock); r = crypt_write_lock(cd, lock_resource, false, reencrypt_lock);
out:
free(lock_resource); free(lock_resource);
return r; return r;
} }
/* internal only */ /* internal only */
int crypt_reencrypt_lock_by_dm_uuid(struct crypt_device *cd, const char *dm_uuid int LUKS2_reencrypt_lock_by_dm_uuid(struct crypt_device *cd, const char *dm_uuid
, struct crypt_lock_handle **reencrypt_lock) ,
struct crypt_lock_handle **reencrypt_lock)
{ {
int r; int r;
char hdr_uuid[37]; char hdr_uuid[37];
const char *uuid = crypt_get_uuid(cd); const char *uuid = crypt_get_uuid(cd);
if (!dm_uuid) if (!dm_uuid)
return -EINVAL; return -EINVAL;
if (!uuid) { if (!uuid) {
r = snprintf(hdr_uuid, sizeof(hdr_uuid), "%.8s-%.4s-%.4s-%.4s-%.1 2s", r = snprintf(hdr_uuid, sizeof(hdr_uuid), "%.8s-%.4s-%.4s-%.4s-%.1 2s",
dm_uuid + 6, dm_uuid + 14, dm_uuid + 18, dm_uuid + 22, d m_uuid + 26); dm_uuid + 6, dm_uuid + 14, dm_uuid + 18, dm_uuid + 22, d m_uuid + 26);
if (r < 0 || (size_t)r != (sizeof(hdr_uuid) - 1)) if (r < 0 || (size_t)r != (sizeof(hdr_uuid) - 1))
return -EINVAL; return -EINVAL;
} else if (crypt_uuid_cmp(dm_uuid, uuid)) } else if (crypt_uuid_cmp(dm_uuid, uuid))
return -EINVAL; return -EINVAL;
return reencrypt_lock_internal(cd, uuid, reencrypt_lock); return reencrypt_lock_internal(cd, uuid, reencrypt_lock);
} }
/* internal only */ /* internal only */
int crypt_reencrypt_lock(struct crypt_device *cd, struct crypt_lock_handle **ree ncrypt_lock) int LUKS2_reencrypt_lock(struct crypt_device *cd, struct crypt_lock_handle **ree ncrypt_lock)
{ {
if (!cd || !crypt_get_type(cd) || strcmp(crypt_get_type(cd), CRYPT_LUKS2) ) if (!cd || !crypt_get_type(cd) || strcmp(crypt_get_type(cd), CRYPT_LUKS2) )
return -EINVAL; return -EINVAL;
return reencrypt_lock_internal(cd, crypt_get_uuid(cd), reencrypt_lock); return reencrypt_lock_internal(cd, crypt_get_uuid(cd), reencrypt_lock);
} }
/* internal only */ /* internal only */
void crypt_reencrypt_unlock(struct crypt_device *cd, struct crypt_lock_handle *r eencrypt_lock) void LUKS2_reencrypt_unlock(struct crypt_device *cd, struct crypt_lock_handle *r eencrypt_lock)
{ {
crypt_unlock_internal(cd, reencrypt_lock); crypt_unlock_internal(cd, reencrypt_lock);
} }
static int reencrypt_lock_and_verify(struct crypt_device *cd, struct luks2_hdr * hdr, static int reencrypt_lock_and_verify(struct crypt_device *cd, struct luks2_hdr * hdr,
struct crypt_lock_handle **reencrypt_lock) struct crypt_lock_handle **reencrypt_lock)
{ {
int r; int r;
crypt_reencrypt_info ri; crypt_reencrypt_info ri;
struct crypt_lock_handle *h; struct crypt_lock_handle *h;
ri = LUKS2_reenc_status(hdr); ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_INVALID) { if (ri == CRYPT_REENCRYPT_INVALID) {
log_err(cd, _("Failed to get reencryption state.")); log_err(cd, _("Failed to get reencryption state."));
return -EINVAL; return -EINVAL;
} }
if (ri < CRYPT_REENCRYPT_CLEAN) { if (ri < CRYPT_REENCRYPT_CLEAN) {
log_err(cd, _("Device is not in reencryption.")); log_err(cd, _("Device is not in reencryption."));
return -EINVAL; return -EINVAL;
} }
r = crypt_reencrypt_lock(cd, &h); r = LUKS2_reencrypt_lock(cd, &h);
if (r < 0) { if (r < 0) {
if (r == -EBUSY) if (r == -EBUSY)
log_err(cd, _("Reencryption process is already running.") ); log_err(cd, _("Reencryption process is already running.") );
else else
log_err(cd, _("Failed to acquire reencryption lock.")); log_err(cd, _("Failed to acquire reencryption lock."));
return r; return r;
} }
/* With reencryption lock held, reload device context and verify metadata state */ /* With reencryption lock held, reload device context and verify metadata state */
r = crypt_load(cd, CRYPT_LUKS2, NULL); r = crypt_load(cd, CRYPT_LUKS2, NULL);
if (r) { if (r) {
crypt_reencrypt_unlock(cd, h); LUKS2_reencrypt_unlock(cd, h);
return r; return r;
} }
ri = LUKS2_reenc_status(hdr); ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_CLEAN) { if (ri == CRYPT_REENCRYPT_CLEAN) {
*reencrypt_lock = h; *reencrypt_lock = h;
return 0; return 0;
} }
crypt_reencrypt_unlock(cd, h); LUKS2_reencrypt_unlock(cd, h);
log_err(cd, _("Cannot proceed with reencryption. Run reencryption recover y first.")); log_err(cd, _("Cannot proceed with reencryption. Run reencryption recover y first."));
return -EINVAL; return -EINVAL;
} }
static int reencrypt_load_by_passphrase(struct crypt_device *cd, static int reencrypt_load_by_passphrase(struct crypt_device *cd,
const char *name, const char *name,
const char *passphrase, const char *passphrase,
size_t passphrase_size, size_t passphrase_size,
int keyslot_old, int keyslot_old,
int keyslot_new, int keyslot_new,
struct volume_key **vks, struct volume_key **vks,
const struct crypt_params_reencrypt *params) const struct crypt_params_reencrypt *params)
{ {
int r, old_ss, new_ss; int r, old_ss, new_ss;
struct luks2_hdr *hdr; struct luks2_hdr *hdr;
struct crypt_lock_handle *reencrypt_lock; struct crypt_lock_handle *reencrypt_lock;
struct luks2_reenc_context *rh; struct luks2_reencrypt *rh;
const struct volume_key *vk; const struct volume_key *vk;
struct crypt_dm_active_device dmd_target, dmd_source = { struct crypt_dm_active_device dmd_target, dmd_source = {
.uuid = crypt_get_uuid(cd), .uuid = crypt_get_uuid(cd),
.flags = CRYPT_ACTIVATE_SHARED /* turn off exclusive open checks */ .flags = CRYPT_ACTIVATE_SHARED /* turn off exclusive open checks */
}; };
uint64_t minimal_size, device_size, mapping_size = 0, required_size = 0; uint64_t minimal_size, device_size, mapping_size = 0, required_size = 0;
bool dynamic; bool dynamic;
struct crypt_params_reencrypt rparams = {}; struct crypt_params_reencrypt rparams = {};
uint32_t flags = 0; uint32_t flags = 0;
if (params) { if (params) {
rparams = *params; rparams = *params;
required_size = params->device_size; required_size = params->device_size;
} }
log_dbg(cd, "Loading LUKS2 reencryption context."); log_dbg(cd, "Loading LUKS2 reencryption context.");
rh = crypt_get_reenc_context(cd); rh = crypt_get_luks2_reencrypt(cd);
if (rh) { if (rh) {
LUKS2_reenc_context_free(cd, rh); LUKS2_reencrypt_free(cd, rh);
crypt_set_reenc_context(cd, NULL); crypt_set_luks2_reencrypt(cd, NULL);
rh = NULL; rh = NULL;
} }
hdr = crypt_get_hdr(cd, CRYPT_LUKS2); hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
r = reencrypt_lock_and_verify(cd, hdr, &reencrypt_lock); r = reencrypt_lock_and_verify(cd, hdr, &reencrypt_lock);
if (r) if (r)
return r; return r;
/* From now on we hold reencryption lock */ /* From now on we hold reencryption lock */
if (LUKS2_get_data_size(hdr, &minimal_size, &dynamic)) if (LUKS2_get_data_size(hdr, &minimal_size, &dynamic))
return -EINVAL; return -EINVAL;
/* some configurations provides fixed device size */ /* some configurations provides fixed device size */
r = luks2_check_device_size(cd, hdr, minimal_size, &device_size, false, d ynamic); r = LUKS2_reencrypt_check_device_size(cd, hdr, minimal_size, &device_size , false, dynamic);
if (r) { if (r) {
r = -EINVAL; r = -EINVAL;
goto err; goto err;
} }
minimal_size >>= SECTOR_SHIFT; minimal_size >>= SECTOR_SHIFT;
old_ss = reencrypt_get_sector_size_old(hdr); old_ss = reencrypt_get_sector_size_old(hdr);
new_ss = reencrypt_get_sector_size_new(hdr); new_ss = reencrypt_get_sector_size_new(hdr);
skipping to change at line 2801 skipping to change at line 2891
goto err; goto err;
/* Reassure device is not mounted and there's no dm mapping active */ /* Reassure device is not mounted and there's no dm mapping active */
if (!name && (device_open_excl(cd, crypt_data_device(cd), O_RDONLY) < 0)) { if (!name && (device_open_excl(cd, crypt_data_device(cd), O_RDONLY) < 0)) {
log_err(cd,_("Failed to open %s in exclusive mode (already mapped or mounted)."), device_path(crypt_data_device(cd))); log_err(cd,_("Failed to open %s in exclusive mode (already mapped or mounted)."), device_path(crypt_data_device(cd)));
r = -EBUSY; r = -EBUSY;
goto err; goto err;
} }
device_release_excl(cd, crypt_data_device(cd)); device_release_excl(cd, crypt_data_device(cd));
/* FIXME: There's a race for dm device activation not managed by cryptset up. /* There's a race for dm device activation not managed by cryptsetup.
* *
* 1) excl close * 1) excl close
* 2) rogue dm device activation * 2) rogue dm device activation
* 3) one or more dm-crypt based wrapper activation * 3) one or more dm-crypt based wrapper activation
* 4) next excl open get's skipped due to 3) device from 2) remains undet ected. * 4) next excl open gets skipped due to 3) device from 2) remains undete cted.
*/ */
r = reencrypt_init_storage_wrappers(cd, hdr, rh, *vks); r = reencrypt_init_storage_wrappers(cd, hdr, rh, *vks);
if (r) if (r)
goto err; goto err;
/* If one of wrappers is based on dmcrypt fallback it already blocked mou nt */ /* If one of wrappers is based on dmcrypt fallback it already blocked mou nt */
if (!name && crypt_storage_wrapper_get_type(rh->cw1) != DMCRYPT && if (!name && crypt_storage_wrapper_get_type(rh->cw1) != DMCRYPT &&
crypt_storage_wrapper_get_type(rh->cw2) != DMCRYPT) { crypt_storage_wrapper_get_type(rh->cw2) != DMCRYPT) {
if (device_open_excl(cd, crypt_data_device(cd), O_RDONLY) < 0) { if (device_open_excl(cd, crypt_data_device(cd), O_RDONLY) < 0) {
log_err(cd,_("Failed to open %s in exclusive mode (alread y mapped or mounted)."), device_path(crypt_data_device(cd))); log_err(cd,_("Failed to open %s in exclusive mode (alread y mapped or mounted)."), device_path(crypt_data_device(cd)));
r = -EBUSY; r = -EBUSY;
goto err; goto err;
} }
} }
rh->flags = flags; rh->flags = flags;
MOVE_REF(rh->vks, *vks); MOVE_REF(rh->vks, *vks);
MOVE_REF(rh->reenc_lock, reencrypt_lock); MOVE_REF(rh->reenc_lock, reencrypt_lock);
crypt_set_reenc_context(cd, rh); crypt_set_luks2_reencrypt(cd, rh);
return 0; return 0;
err: err:
crypt_reencrypt_unlock(cd, reencrypt_lock); LUKS2_reencrypt_unlock(cd, reencrypt_lock);
LUKS2_reenc_context_free(cd, rh); LUKS2_reencrypt_free(cd, rh);
return r; return r;
} }
static int reencrypt_recovery_by_passphrase(struct crypt_device *cd, static int reencrypt_recovery_by_passphrase(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
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)
{ {
int r; int r;
crypt_reencrypt_info ri; crypt_reencrypt_info ri;
struct crypt_lock_handle *reencrypt_lock; struct crypt_lock_handle *reencrypt_lock;
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 perform r ecovery.")); log_err(cd, _("Reencryption in-progress. Cannot perform r ecovery."));
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))) {
crypt_reencrypt_unlock(cd, reencrypt_lock); LUKS2_reencrypt_unlock(cd, reencrypt_lock);
return r; return r;
} }
ri = LUKS2_reenc_status(hdr); ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_INVALID) { if (ri == CRYPT_REENCRYPT_INVALID) {
crypt_reencrypt_unlock(cd, reencrypt_lock); LUKS2_reencrypt_unlock(cd, reencrypt_lock);
return -EINVAL; return -EINVAL;
} }
if (ri == CRYPT_REENCRYPT_CRASH) { if (ri == CRYPT_REENCRYPT_CRASH) {
r = LUKS2_reencrypt_locked_recovery_by_passphrase(cd, keyslot_old , keyslot_new, r = LUKS2_reencrypt_locked_recovery_by_passphrase(cd, keyslot_old , keyslot_new,
passphrase, passphrase_size, 0, NULL); passphrase, passphrase_size, 0, NULL);
if (r < 0) if (r < 0)
log_err(cd, _("LUKS2 reencryption recovery failed.")); log_err(cd, _("LUKS2 reencryption recovery failed."));
} else { } else {
log_dbg(cd, "No LUKS2 reencryption recovery needed."); log_dbg(cd, "No LUKS2 reencryption recovery needed.");
r = 0; r = 0;
} }
crypt_reencrypt_unlock(cd, reencrypt_lock); LUKS2_reencrypt_unlock(cd, reencrypt_lock);
return r; return r;
} }
static int reencrypt_init_by_passphrase(struct crypt_device *cd, static int reencrypt_init_by_passphrase(struct crypt_device *cd,
const char *name, const char *name,
const char *passphrase, const char *passphrase,
size_t passphrase_size, size_t passphrase_size,
int keyslot_old, int keyslot_old,
int keyslot_new, int keyslot_new,
const char *cipher, const char *cipher,
skipping to change at line 2914 skipping to change at line 3004
return r; return r;
r = LUKS2_check_cipher(cd, r, cipher, cipher_mode); r = LUKS2_check_cipher(cd, r, cipher, cipher_mode);
if (r < 0) if (r < 0)
return r; return r;
} }
r = LUKS2_device_write_lock(cd, hdr, crypt_metadata_device(cd)); r = LUKS2_device_write_lock(cd, hdr, crypt_metadata_device(cd));
if (r) if (r)
return r; return r;
ri = LUKS2_reenc_status(hdr); ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_INVALID) { if (ri == CRYPT_REENCRYPT_INVALID) {
device_write_unlock(cd, crypt_metadata_device(cd)); device_write_unlock(cd, crypt_metadata_device(cd));
return -EINVAL; return -EINVAL;
} }
if ((ri > CRYPT_REENCRYPT_NONE) && (flags & CRYPT_REENCRYPT_INITIALIZE_ON LY)) { if ((ri > CRYPT_REENCRYPT_NONE) && (flags & CRYPT_REENCRYPT_INITIALIZE_ON LY)) {
device_write_unlock(cd, crypt_metadata_device(cd)); device_write_unlock(cd, crypt_metadata_device(cd));
log_err(cd, _("LUKS2 reencryption already initialized in metadata .")); log_err(cd, _("LUKS2 reencryption already initialized in metadata ."));
return -EBUSY; return -EBUSY;
} }
skipping to change at line 3000 skipping to change at line 3090
if (onlyLUKS2mask(cd, CRYPT_REQUIREMENT_ONLINE_REENCRYPT) || !passphrase) if (onlyLUKS2mask(cd, CRYPT_REQUIREMENT_ONLINE_REENCRYPT) || !passphrase)
return -EINVAL; return -EINVAL;
if (params && (params->flags & CRYPT_REENCRYPT_INITIALIZE_ONLY) && (param s->flags & CRYPT_REENCRYPT_RESUME_ONLY)) if (params && (params->flags & CRYPT_REENCRYPT_INITIALIZE_ONLY) && (param s->flags & CRYPT_REENCRYPT_RESUME_ONLY))
return -EINVAL; return -EINVAL;
return reencrypt_init_by_passphrase(cd, name, passphrase, passphrase_size , keyslot_old, keyslot_new, cipher, cipher_mode, params); return reencrypt_init_by_passphrase(cd, name, passphrase, passphrase_size , keyslot_old, keyslot_new, cipher, cipher_mode, params);
} }
static reenc_status_t reencrypt_step(struct crypt_device *cd, static reenc_status_t reencrypt_step(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
struct luks2_reenc_context *rh, struct luks2_reencrypt *rh,
uint64_t device_size, uint64_t device_size,
bool online) bool online)
{ {
int r; int r;
/* update reencrypt keyslot protection parameters in memory only */ /* update reencrypt keyslot protection parameters in memory only */
r = reenc_keyslot_update(cd, rh); r = reencrypt_keyslot_update(cd, rh);
if (r < 0) { if (r < 0) {
log_dbg(cd, "Keyslot update failed."); log_dbg(cd, "Keyslot update failed.");
return REENC_ERR; return REENC_ERR;
} }
/* in memory only */ /* in memory only */
r = reencrypt_make_segments(cd, hdr, rh, device_size); r = reencrypt_make_segments(cd, hdr, rh, device_size);
if (r) if (r)
return REENC_ERR; return REENC_ERR;
skipping to change at line 3129 skipping to change at line 3219
segment = LUKS2_get_segment_id_by_flag(hdr, "backup-moved-segment"); segment = LUKS2_get_segment_id_by_flag(hdr, "backup-moved-segment");
if (segment >= 0) { if (segment >= 0) {
if (LUKS2_digest_segment_assign(cd, hdr, segment, CRYPT_ANY_DIGES T, 0, 0)) if (LUKS2_digest_segment_assign(cd, hdr, segment, CRYPT_ANY_DIGES T, 0, 0))
return -EINVAL; return -EINVAL;
json_object_object_del_by_uint(LUKS2_get_segments_jobj(hdr), segm ent); json_object_object_del_by_uint(LUKS2_get_segments_jobj(hdr), segm ent);
} }
return 0; return 0;
} }
static int reencrypt_wipe_moved_segment(struct crypt_device *cd, struct luks2_hd r *hdr, struct luks2_reenc_context *rh) static int reencrypt_wipe_moved_segment(struct crypt_device *cd, struct luks2_re encrypt *rh)
{ {
int r = 0; int r = 0;
uint64_t offset, length; uint64_t offset, length;
if (rh->jobj_segment_moved) { if (rh->jobj_segment_moved) {
offset = json_segment_get_offset(rh->jobj_segment_moved, 0); offset = json_segment_get_offset(rh->jobj_segment_moved, 0);
length = json_segment_get_size(rh->jobj_segment_moved, 0); length = json_segment_get_size(rh->jobj_segment_moved, 0);
log_dbg(cd, "Wiping %" PRIu64 " bytes of backup segment data at o ffset %" PRIu64, log_dbg(cd, "Wiping %" PRIu64 " bytes of backup segment data at o ffset %" PRIu64,
length, offset); length, offset);
r = crypt_wipe_device(cd, crypt_data_device(cd), CRYPT_WIPE_RANDO M, r = crypt_wipe_device(cd, crypt_data_device(cd), CRYPT_WIPE_RANDO M,
offset, length, 1024 * 1024, NULL, NULL); offset, length, 1024 * 1024, NULL, NULL);
} }
return r; return r;
} }
static int reencrypt_teardown_ok(struct crypt_device *cd, struct luks2_hdr *hdr, struct luks2_reenc_context *rh) static int reencrypt_teardown_ok(struct crypt_device *cd, struct luks2_hdr *hdr, struct luks2_reencrypt *rh)
{ {
int i, r; int i, r;
uint32_t dmt_flags; uint32_t dmt_flags;
bool finished = !(rh->device_size > rh->progress); bool finished = !(rh->device_size > rh->progress);
if (rh->rp.type == REENC_PROTECTION_NONE && if (rh->rp.type == REENC_PROTECTION_NONE &&
LUKS2_hdr_write(cd, hdr)) { LUKS2_hdr_write(cd, hdr)) {
log_err(cd, _("Failed to write LUKS2 metadata.")); log_err(cd, _("Failed to write LUKS2 metadata."));
return -EINVAL; return -EINVAL;
} }
skipping to change at line 3176 skipping to change at line 3266
} }
dm_remove_device(cd, rh->overlay_name, 0); dm_remove_device(cd, rh->overlay_name, 0);
dm_remove_device(cd, rh->hotzone_name, 0); dm_remove_device(cd, rh->hotzone_name, 0);
if (!r && finished && rh->mode == CRYPT_REENCRYPT_DECRYPT && if (!r && finished && rh->mode == CRYPT_REENCRYPT_DECRYPT &&
!dm_flags(cd, DM_LINEAR, &dmt_flags) && (dmt_flags & DM_DEFER RED_SUPPORTED)) !dm_flags(cd, DM_LINEAR, &dmt_flags) && (dmt_flags & DM_DEFER RED_SUPPORTED))
dm_remove_device(cd, rh->device_name, CRYPT_DEACTIVATE_DEFERR ED); dm_remove_device(cd, rh->device_name, CRYPT_DEACTIVATE_DEFERR ED);
} }
if (finished) { if (finished) {
if (reencrypt_wipe_moved_segment(cd, hdr, rh)) if (reencrypt_wipe_moved_segment(cd, rh))
log_err(cd, _("Failed to wipe backup segment data.")); log_err(cd, _("Failed to wipe backup segment data."));
if (reencrypt_get_data_offset_new(hdr) && LUKS2_set_keyslots_size (cd, hdr, reencrypt_get_data_offset_new(hdr))) if (reencrypt_get_data_offset_new(hdr) && LUKS2_set_keyslots_size (cd, hdr, reencrypt_get_data_offset_new(hdr)))
log_dbg(cd, "Failed to set new keyslots area size."); log_dbg(cd, "Failed to set new keyslots area size.");
if (rh->digest_old >= 0 && rh->digest_new != rh->digest_old) if (rh->digest_old >= 0 && rh->digest_new != rh->digest_old)
for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++) for (i = 0; i < LUKS2_KEYSLOTS_MAX; i++)
if (LUKS2_digest_by_keyslot(hdr, i) == rh->digest _old) if (LUKS2_digest_by_keyslot(hdr, i) == rh->digest _old)
crypt_keyslot_destroy(cd, i); crypt_keyslot_destroy(cd, i);
crypt_keyslot_destroy(cd, rh->reenc_keyslot); crypt_keyslot_destroy(cd, rh->reenc_keyslot);
if (reencrypt_erase_backup_segments(cd, hdr)) if (reencrypt_erase_backup_segments(cd, hdr))
log_dbg(cd, "Failed to erase backup segments"); log_dbg(cd, "Failed to erase backup segments");
/* do we need atomic erase? */ /* do we need atomic erase? */
if (reencrypt_update_flag(cd, 0, true)) if (reencrypt_update_flag(cd, 0, true))
log_err(cd, _("Failed to disable reencryption requirement flag.")); log_err(cd, _("Failed to disable reencryption requirement flag."));
} }
return 0; return 0;
} }
static void reencrypt_teardown_fatal(struct crypt_device *cd, struct luks2_hdr * hdr, struct luks2_reenc_context *rh) static void reencrypt_teardown_fatal(struct crypt_device *cd, struct luks2_reenc rypt *rh)
{ {
log_err(cd, _("Fatal error while reencrypting chunk starting at %" PRIu64 ", %" PRIu64 " sectors long."), log_err(cd, _("Fatal error while reencrypting chunk starting at %" PRIu64 ", %" PRIu64 " sectors long."),
(rh->offset >> SECTOR_SHIFT) + crypt_get_data_offset(cd), rh->len gth >> SECTOR_SHIFT); (rh->offset >> SECTOR_SHIFT) + crypt_get_data_offset(cd), rh->len gth >> SECTOR_SHIFT);
if (rh->online) { if (rh->online) {
log_err(cd, "Reencryption was run in online mode."); log_err(cd, "Reencryption was run in online mode.");
if (dm_status_suspended(cd, rh->hotzone_name) > 0) { if (dm_status_suspended(cd, rh->hotzone_name) > 0) {
log_dbg(cd, "Hotzone device %s suspended, replacing with dm-error.", rh->hotzone_name); log_dbg(cd, "Hotzone device %s suspended, replacing with dm-error.", rh->hotzone_name);
if (dm_error_device(cd, rh->hotzone_name)) { if (dm_error_device(cd, rh->hotzone_name)) {
log_err(cd, _("Failed to replace suspended device %s with dm-error target."), rh->hotzone_name); log_err(cd, _("Failed to replace suspended device %s with dm-error target."), rh->hotzone_name);
log_err(cd, _("Do not resume the device unless re placed with error target manually.")); log_err(cd, _("Do not resume the device unless re placed with error target manually."));
} }
} }
} }
} }
static int reencrypt_teardown(struct crypt_device *cd, struct luks2_hdr *hdr, static int reencrypt_teardown(struct crypt_device *cd, struct luks2_hdr *hdr,
struct luks2_reenc_context *rh, reenc_status_t rs, bool interrupt struct luks2_reencrypt *rh, reenc_status_t rs, bool interrupted,
ed, int (*progress)(uint64_t size, uint64_t offset, void *usrptr),
int (*progress)(uint64_t size, uint64_t offset, void *usrptr)) void *usrptr)
{ {
int r; int r;
switch (rs) { switch (rs) {
case REENC_OK: case REENC_OK:
if (progress && !interrupted) if (progress && !interrupted)
progress(rh->device_size, rh->progress, NULL); progress(rh->device_size, rh->progress, usrptr);
r = reencrypt_teardown_ok(cd, hdr, rh); r = reencrypt_teardown_ok(cd, hdr, rh);
break; break;
case REENC_FATAL: case REENC_FATAL:
reencrypt_teardown_fatal(cd, hdr, rh); reencrypt_teardown_fatal(cd, rh);
/* fall-through */ /* fall-through */
default: default:
r = -EIO; r = -EIO;
} }
/* this frees reencryption lock */ /* this frees reencryption lock */
LUKS2_reenc_context_free(cd, rh); LUKS2_reencrypt_free(cd, rh);
crypt_set_reenc_context(cd, NULL); crypt_set_luks2_reencrypt(cd, NULL);
return r; return r;
} }
int crypt_reencrypt(struct crypt_device *cd, int crypt_reencrypt_run(
int (*progress)(uint64_t size, uint64_t offset, void *usrptr) struct crypt_device *cd,
) int (*progress)(uint64_t size, uint64_t offset, void *usrptr),
void *usrptr)
{ {
int r; int r;
crypt_reencrypt_info ri; crypt_reencrypt_info ri;
struct luks2_hdr *hdr; struct luks2_hdr *hdr;
struct luks2_reenc_context *rh; struct luks2_reencrypt *rh;
reenc_status_t rs; reenc_status_t rs;
bool quit = false; bool quit = false;
if (onlyLUKS2mask(cd, CRYPT_REQUIREMENT_ONLINE_REENCRYPT)) if (onlyLUKS2mask(cd, CRYPT_REQUIREMENT_ONLINE_REENCRYPT))
return -EINVAL; return -EINVAL;
hdr = crypt_get_hdr(cd, CRYPT_LUKS2); hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
ri = LUKS2_reenc_status(hdr); ri = LUKS2_reencrypt_status(hdr);
if (ri > CRYPT_REENCRYPT_CLEAN) { if (ri > CRYPT_REENCRYPT_CLEAN) {
log_err(cd, _("Cannot proceed with reencryption. Unexpected reenc ryption status.")); log_err(cd, _("Cannot proceed with reencryption. Unexpected reenc ryption status."));
return -EINVAL; return -EINVAL;
} }
rh = crypt_get_reenc_context(cd); rh = crypt_get_luks2_reencrypt(cd);
if (!rh || (!rh->reenc_lock && crypt_metadata_locking_enabled())) { if (!rh || (!rh->reenc_lock && crypt_metadata_locking_enabled())) {
log_err(cd, _("Missing or invalid reencrypt context.")); log_err(cd, _("Missing or invalid reencrypt context."));
return -EINVAL; return -EINVAL;
} }
log_dbg(cd, "Resuming LUKS2 reencryption."); log_dbg(cd, "Resuming LUKS2 reencryption.");
if (rh->online && reencrypt_init_device_stack(cd, rh)) { if (rh->online && reencrypt_init_device_stack(cd, rh)) {
log_err(cd, _("Failed to initialize reencryption device stack.")) ; log_err(cd, _("Failed to initialize reencryption device stack.")) ;
return -EINVAL; return -EINVAL;
skipping to change at line 3283 skipping to change at line 3376
log_dbg(cd, "Progress %" PRIu64 ", device_size %" PRIu64, rh->progress, r h->device_size); log_dbg(cd, "Progress %" PRIu64 ", device_size %" PRIu64, rh->progress, r h->device_size);
rs = REENC_OK; rs = REENC_OK;
while (!quit && (rh->device_size > rh->progress)) { while (!quit && (rh->device_size > rh->progress)) {
rs = reencrypt_step(cd, hdr, rh, rh->device_size, rh->online); rs = reencrypt_step(cd, hdr, rh, rh->device_size, rh->online);
if (rs != REENC_OK) if (rs != REENC_OK)
break; break;
log_dbg(cd, "Progress %" PRIu64 ", device_size %" PRIu64, rh->pro gress, rh->device_size); log_dbg(cd, "Progress %" PRIu64 ", device_size %" PRIu64, rh->pro gress, rh->device_size);
if (progress && progress(rh->device_size, rh->progress, NULL)) if (progress && progress(rh->device_size, rh->progress, usrptr))
quit = true; quit = true;
r = reencrypt_context_update(cd, rh); r = reencrypt_context_update(cd, rh);
if (r) { if (r) {
log_err(cd, _("Failed to update reencryption context.")); log_err(cd, _("Failed to update reencryption context."));
rs = REENC_ERR; rs = REENC_ERR;
break; break;
} }
log_dbg(cd, "Next reencryption offset will be %" PRIu64 " sectors .", rh->offset); log_dbg(cd, "Next reencryption offset will be %" PRIu64 " sectors .", rh->offset);
log_dbg(cd, "Next reencryption chunk size will be %" PRIu64 " sec tors).", rh->length); log_dbg(cd, "Next reencryption chunk size will be %" PRIu64 " sec tors).", rh->length);
} }
r = reencrypt_teardown(cd, hdr, rh, rs, quit, progress); r = reencrypt_teardown(cd, hdr, rh, rs, quit, progress, usrptr);
return r; return r;
} }
int crypt_reencrypt(
struct crypt_device *cd,
int (*progress)(uint64_t size, uint64_t offset, void *usrptr))
{
return crypt_reencrypt_run(cd, progress, NULL);
}
static int reencrypt_recovery(struct crypt_device *cd, static int reencrypt_recovery(struct crypt_device *cd,
struct luks2_hdr *hdr, struct luks2_hdr *hdr,
uint64_t device_size, uint64_t device_size,
struct volume_key *vks) struct volume_key *vks)
{ {
int r; int r;
struct luks2_reenc_context *rh = NULL; struct luks2_reencrypt *rh = NULL;
r = reencrypt_load(cd, hdr, device_size, NULL, &rh); r = reencrypt_load(cd, hdr, device_size, NULL, &rh);
if (r < 0) { if (r < 0) {
log_err(cd, _("Failed to load LUKS2 reencryption context.")); log_err(cd, _("Failed to load LUKS2 reencryption context."));
return r; return r;
} }
r = reencrypt_recover_segment(cd, hdr, rh, vks); r = reencrypt_recover_segment(cd, hdr, rh, vks);
if (r < 0) if (r < 0)
goto err; goto out;
if ((r = reencrypt_assign_segments(cd, hdr, rh, 0, 0))) if ((r = reencrypt_assign_segments(cd, hdr, rh, 0, 0)))
goto err; goto out;
r = reencrypt_context_update(cd, rh); r = reencrypt_context_update(cd, rh);
if (r) { if (r) {
log_err(cd, _("Failed to update reencryption context.")); log_err(cd, _("Failed to update reencryption context."));
goto err; goto out;
} }
r = reencrypt_teardown_ok(cd, hdr, rh); r = reencrypt_teardown_ok(cd, hdr, rh);
if (!r) if (!r)
r = LUKS2_hdr_write(cd, hdr); r = LUKS2_hdr_write(cd, hdr);
err: out:
LUKS2_reenc_context_free(cd, rh); LUKS2_reencrypt_free(cd, rh);
return r; return r;
} }
/* /*
* use only for calculation of minimal data device size. * use only for calculation of minimal data device size.
* The real data offset is taken directly from segments! * The real data offset is taken directly from segments!
*/ */
int LUKS2_reencrypt_data_offset(struct luks2_hdr *hdr, bool blockwise) int LUKS2_reencrypt_data_offset(struct luks2_hdr *hdr, bool blockwise)
{ {
crypt_reencrypt_info ri = LUKS2_reenc_status(hdr); crypt_reencrypt_info ri = LUKS2_reencrypt_status(hdr);
uint64_t data_offset = LUKS2_get_data_offset(hdr); uint64_t data_offset = LUKS2_get_data_offset(hdr);
if (ri == CRYPT_REENCRYPT_CLEAN && reencrypt_direction(hdr) == CRYPT_REEN CRYPT_FORWARD) if (ri == CRYPT_REENCRYPT_CLEAN && reencrypt_direction(hdr) == CRYPT_REEN CRYPT_FORWARD)
data_offset += reencrypt_data_shift(hdr) >> SECTOR_SHIFT; data_offset += reencrypt_data_shift(hdr) >> SECTOR_SHIFT;
return blockwise ? data_offset : data_offset << SECTOR_SHIFT; return blockwise ? data_offset : data_offset << SECTOR_SHIFT;
} }
/* internal only */ /* internal only */
int luks2_check_device_size(struct crypt_device *cd, struct luks2_hdr *hdr, uint int LUKS2_reencrypt_check_device_size(struct crypt_device *cd, struct luks2_hdr
64_t check_size, uint64_t *dev_size, bool activation, bool dynamic) *hdr,
uint64_t check_size, uint64_t *dev_size, bool activation, bool dynamic)
{ {
int r; int r;
uint64_t data_offset, real_size = 0; uint64_t data_offset, real_size = 0;
if (reencrypt_direction(hdr) == CRYPT_REENCRYPT_BACKWARD && if (reencrypt_direction(hdr) == CRYPT_REENCRYPT_BACKWARD &&
(LUKS2_get_segment_by_flag(hdr, "backup-moved-segment") || dynamic)) (LUKS2_get_segment_by_flag(hdr, "backup-moved-segment") || dynamic))
check_size += reencrypt_data_shift(hdr); check_size += reencrypt_data_shift(hdr);
r = device_check_access(cd, crypt_data_device(cd), activation ? DEV_EXCL : DEV_OK); r = device_check_access(cd, crypt_data_device(cd), activation ? DEV_EXCL : DEV_OK);
if (r) if (r)
skipping to change at line 3398 skipping to change at line 3499
return 0; return 0;
} }
/* returns keyslot number on success (>= 0) or negative errnor otherwise */ /* returns keyslot number on success (>= 0) or negative errnor otherwise */
int LUKS2_reencrypt_locked_recovery_by_passphrase(struct crypt_device *cd, int LUKS2_reencrypt_locked_recovery_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,
uint32_t flags, uint32_t flags __attribute__((unused)),
struct volume_key **vks) struct volume_key **vks)
{ {
uint64_t minimal_size, device_size; uint64_t minimal_size, device_size;
int keyslot, r = -EINVAL; int keyslot, r = -EINVAL;
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2); struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
struct volume_key *vk = NULL, *_vks = NULL; struct volume_key *vk = NULL, *_vks = NULL;
log_dbg(cd, "Entering reencryption crash recovery."); log_dbg(cd, "Entering reencryption crash recovery.");
if (LUKS2_get_data_size(hdr, &minimal_size, NULL)) if (LUKS2_get_data_size(hdr, &minimal_size, NULL))
return r; return r;
r = LUKS2_keyslot_open_all_segments(cd, keyslot_old, keyslot_new, r = LUKS2_keyslot_open_all_segments(cd, keyslot_old, keyslot_new,
passphrase, passphrase_size, &_vks); passphrase, passphrase_size, &_vks);
if (r < 0) if (r < 0)
goto err; goto out;
keyslot = r; keyslot = r;
if (crypt_use_keyring_for_vk(cd)) if (crypt_use_keyring_for_vk(cd))
vk = _vks; vk = _vks;
while (vk) { while (vk) {
r = LUKS2_volume_key_load_in_keyring_by_digest(cd, hdr, vk, crypt _volume_key_get_id(vk)); r = LUKS2_volume_key_load_in_keyring_by_digest(cd, hdr, vk, crypt _volume_key_get_id(vk));
if (r < 0) if (r < 0)
goto err; goto out;
vk = crypt_volume_key_next(vk); vk = crypt_volume_key_next(vk);
} }
if (luks2_check_device_size(cd, hdr, minimal_size, &device_size, true, fa if (LUKS2_reencrypt_check_device_size(cd, hdr, minimal_size, &device_size
lse)) , true, false))
goto err; goto out;
r = reencrypt_recovery(cd, hdr, device_size, _vks); r = reencrypt_recovery(cd, hdr, device_size, _vks);
if (!r && vks) if (!r && vks)
MOVE_REF(*vks, _vks); MOVE_REF(*vks, _vks);
err: out:
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;
} }
crypt_reencrypt_info LUKS2_reencrypt_status(struct crypt_device *cd, struct cryp crypt_reencrypt_info LUKS2_reencrypt_get_params(struct luks2_hdr *hdr,
t_params_reencrypt *params) struct crypt_params_reencrypt *params)
{ {
crypt_reencrypt_info ri; crypt_reencrypt_info ri;
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
ri = LUKS2_reenc_status(hdr); ri = LUKS2_reencrypt_status(hdr);
if (ri == CRYPT_REENCRYPT_NONE || ri == CRYPT_REENCRYPT_INVALID || !param s) if (ri == CRYPT_REENCRYPT_NONE || ri == CRYPT_REENCRYPT_INVALID || !param s)
return ri; return ri;
params->mode = reencrypt_mode(hdr); params->mode = reencrypt_mode(hdr);
params->direction = reencrypt_direction(hdr); params->direction = reencrypt_direction(hdr);
params->resilience = reencrypt_resilience_type(hdr); params->resilience = reencrypt_resilience_type(hdr);
params->hash = reencrypt_resilience_hash(hdr); params->hash = reencrypt_resilience_hash(hdr);
params->data_shift = reencrypt_data_shift(hdr) >> SECTOR_SHIFT; params->data_shift = reencrypt_data_shift(hdr) >> SECTOR_SHIFT;
params->max_hotzone_size = 0; params->max_hotzone_size = 0;
if (LUKS2_get_segment_id_by_flag(hdr, "backup-moved-segment") >= 0) if (LUKS2_get_segment_id_by_flag(hdr, "backup-moved-segment") >= 0)
 End of changes. 128 change blocks. 
159 lines changed or deleted 266 lines changed or added

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