Do not cache volume key in keyslot context.

First, there was a bug where passphrase based
keyslot contextets did not cache volume keys
properly and caused leaks.

Second, it causes problems when keyslot context
is used twice with different keyslot id, e.g.:
CRYPT_ANY_SLOT vs specific id, unbound key vs
volume key, etc.
This commit is contained in:
Ondrej Kozina
2022-11-02 11:41:40 +01:00
parent 01c16111d7
commit 0e6264c53c
3 changed files with 26 additions and 59 deletions

View File

@@ -130,21 +130,15 @@ static int get_luks2_key_by_keyfile(struct crypt_device *cd,
assert(kc && kc->type == CRYPT_KC_TYPE_KEYFILE);
assert(r_vk);
if (!kc->i_vk) {
r = get_passphrase_by_keyfile(cd, kc, &passphrase, &passphrase_size);
if (r)
return r;
r = get_passphrase_by_keyfile(cd, kc, &passphrase, &passphrase_size);
if (r)
return r;
r = LUKS2_keyslot_open(cd, keyslot, segment, passphrase, passphrase_size, &kc->i_vk);
if (r < 0) {
kc->error = r;
return r;
}
}
r = LUKS2_keyslot_open(cd, keyslot, segment, passphrase, passphrase_size, r_vk);
if (r < 0)
kc->error = r;
*r_vk = kc->i_vk;
return 0;
return r;
}
static int get_luks2_volume_key_by_keyfile(struct crypt_device *cd,
@@ -168,22 +162,16 @@ static int get_luks1_volume_key_by_keyfile(struct crypt_device *cd,
assert(kc && kc->type == CRYPT_KC_TYPE_KEYFILE);
assert(r_vk);
if (!kc->i_vk) {
r = get_passphrase_by_keyfile(cd, kc, &passphrase, &passphrase_size);
if (r)
return r;
r = get_passphrase_by_keyfile(cd, kc, &passphrase, &passphrase_size);
if (r)
return r;
r = LUKS_open_key_with_hdr(keyslot, passphrase, passphrase_size,
crypt_get_hdr(cd, CRYPT_LUKS1), &kc->i_vk, cd);
if (r < 0) {
kc->error = r;
return r;
}
}
r = LUKS_open_key_with_hdr(keyslot, passphrase, passphrase_size,
crypt_get_hdr(cd, CRYPT_LUKS1), r_vk, cd);
if (r < 0)
kc->error = r;
*r_vk = kc->i_vk;
return 0;
return r;
}
static int get_key_by_key(struct crypt_device *cd,
@@ -195,24 +183,17 @@ static int get_key_by_key(struct crypt_device *cd,
assert(kc && kc->type == CRYPT_KC_TYPE_KEY);
assert(r_vk);
if (kc->i_vk) {
*r_vk = kc->i_vk;
return 0;
}
if (!kc->u.k.volume_key) {
kc->error = -ENOENT;
return kc->error;
}
kc->i_vk = crypt_alloc_volume_key(kc->u.k.volume_key_size, kc->u.k.volume_key);
if (!kc->i_vk) {
*r_vk = crypt_alloc_volume_key(kc->u.k.volume_key_size, kc->u.k.volume_key);
if (!*r_vk) {
kc->error = -ENOMEM;
return kc->error;
}
*r_vk = kc->i_vk;
return 0;
}
@@ -236,19 +217,10 @@ static int get_luks2_key_by_token(struct crypt_device *cd,
assert(kc && kc->type == CRYPT_KC_TYPE_TOKEN);
assert(r_vk);
if (kc->i_vk) {
*r_vk = kc->i_vk;
return 0;
}
r = LUKS2_token_unlock_key(cd, crypt_get_hdr(cd, CRYPT_LUKS2), kc->u.t.id, kc->u.t.type,
kc->u.t.pin, kc->u.t.pin_size, segment, kc->u.t.usrptr, &kc->i_vk);
if (r < 0) {
kc->u.t.pin, kc->u.t.pin_size, segment, kc->u.t.usrptr, r_vk);
if (r < 0)
kc->error = r;
return r;
}
*r_vk = kc->i_vk;
return r;
}
@@ -297,7 +269,6 @@ static void unlock_method_init_internal(struct crypt_keyslot_context *kc)
kc->error = 0;
kc->i_passphrase = NULL;
kc->i_passphrase_size = 0;
kc->i_vk = NULL;
}
void crypt_keyslot_unlock_by_key_init_internal(struct crypt_keyslot_context *kc,
@@ -378,8 +349,6 @@ void crypt_keyslot_context_destroy_internal(struct crypt_keyslot_context *kc)
return;
crypt_safe_free(kc->i_passphrase);
crypt_free_volume_key(kc->i_vk);
kc->i_vk = NULL;
kc->i_passphrase = NULL;
kc->i_passphrase_size = 0;
}

View File

@@ -75,7 +75,6 @@ struct crypt_keyslot_context {
int error;
struct volume_key *i_vk;
char *i_passphrase;
size_t i_passphrase_size;

View File

@@ -6154,7 +6154,7 @@ int crypt_keyslot_add_by_keyslot_context(struct crypt_device *cd,
int active_slots, r;
const char *new_passphrase;
size_t new_passphrase_size;
struct volume_key *p_vk = NULL, *vk = NULL;
struct volume_key *vk = NULL;
if (!kc || ((flags & CRYPT_VOLUME_KEY_NO_SEGMENT) &&
(flags & CRYPT_VOLUME_KEY_SET)))
@@ -6191,21 +6191,20 @@ int crypt_keyslot_add_by_keyslot_context(struct crypt_device *cd,
if (active_slots == 0 && kc->type != CRYPT_KC_TYPE_KEY)
r = -ENOENT;
else if (is_luks1 && kc->get_luks1_volume_key)
r = kc->get_luks1_volume_key(cd, kc, keyslot_existing, &p_vk);
r = kc->get_luks1_volume_key(cd, kc, keyslot_existing, &vk);
else if (!is_luks1 && kc->get_luks2_volume_key)
r = kc->get_luks2_volume_key(cd, kc, keyslot_existing, &p_vk);
r = kc->get_luks2_volume_key(cd, kc, keyslot_existing, &vk);
else
return -EINVAL;
if (r == -ENOENT) {
if ((flags & CRYPT_VOLUME_KEY_NO_SEGMENT) && kc->type == CRYPT_KC_TYPE_KEY) {
vk = crypt_generate_volume_key(cd, kc->u.k.volume_key_size);
if (!vk)
if (!(vk = crypt_generate_volume_key(cd, kc->u.k.volume_key_size)))
return -ENOMEM;
p_vk = vk;
r = 0;
} else if (cd->volume_key) {
p_vk = cd->volume_key;
if (!(vk = crypt_alloc_volume_key(cd->volume_key->keylength, cd->volume_key->key)))
return -ENOMEM;
r = 0;
} else if (active_slots == 0) {
log_err(cd, _("Cannot add key slot, all slots disabled and no volume key provided."));
@@ -6221,7 +6220,7 @@ int crypt_keyslot_add_by_keyslot_context(struct crypt_device *cd,
if (r >= 0 && new_kc->type == CRYPT_KC_TYPE_TOKEN && !is_luks1)
r = LUKS2_token_assign(cd, &cd->u.luks2.hdr, keyslot_new, new_kc->u.t.id, 1, 0);
if (r >= 0)
r = keyslot_add_by_key(cd, is_luks1, keyslot_new, new_passphrase, new_passphrase_size, p_vk, flags);
r = keyslot_add_by_key(cd, is_luks1, keyslot_new, new_passphrase, new_passphrase_size, vk, flags);
crypt_free_volume_key(vk);