Provide routine for setting LUKS2 requirement with version.

This commit is contained in:
Ondrej Kozina
2022-05-31 17:06:42 +02:00
parent 07f8dfc46d
commit 7b4d5fe067
3 changed files with 104 additions and 10 deletions

View File

@@ -405,6 +405,7 @@ int LUKS2_config_set_flags(struct crypt_device *cd, struct luks2_hdr *hdr, uint3
*/
int LUKS2_config_get_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t *reqs);
int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs, bool commit);
int LUKS2_config_set_requirement_version(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t req_id, uint32_t req_version, bool commit);
int LUKS2_config_get_reencrypt_version(struct luks2_hdr *hdr, uint32_t *version);

View File

@@ -1659,6 +1659,94 @@ err:
return r;
}
static json_object *LUKS2_get_mandatory_requirements_filtered_jobj(struct luks2_hdr *hdr,
uint32_t filter_req_ids)
{
int i, len;
const struct requirement_flag *req;
json_object *jobj_mandatory, *jobj_mandatory_filtered, *jobj;
jobj_mandatory_filtered = json_object_new_array();
if (!jobj_mandatory_filtered)
return NULL;
jobj_mandatory = mandatory_requirements_jobj(hdr);
if (!jobj_mandatory)
return jobj_mandatory_filtered;
len = (int) json_object_array_length(jobj_mandatory);
for (i = 0; i < len; i++) {
jobj = json_object_array_get_idx(jobj_mandatory, i);
req = get_requirement_by_name(json_object_get_string(jobj));
if (req->flag == CRYPT_REQUIREMENT_UNKNOWN || req->flag & filter_req_ids)
continue;
json_object_array_add(jobj_mandatory_filtered,
json_object_new_string(req->description));
}
return jobj_mandatory_filtered;
}
/*
* The function looks for specific version of requirement id.
* If it can't be fulfilled function fails.
*/
int LUKS2_config_set_requirement_version(struct crypt_device *cd,
struct luks2_hdr *hdr,
uint32_t req_id,
uint32_t req_version,
bool commit)
{
json_object *jobj_config, *jobj_requirements, *jobj_mandatory;
const struct requirement_flag *req;
int r = -EINVAL;
if (!hdr || req_id == CRYPT_REQUIREMENT_UNKNOWN)
return -EINVAL;
req = requirements_flags;
while (req->description) {
/* we have a match */
if (req->flag == req_id && req->version == req_version)
break;
req++;
}
if (!req->description)
return -EINVAL;
/*
* Creates copy of mandatory requirements set without specific requirement
* (no matter the version) we want to set.
*/
jobj_mandatory = LUKS2_get_mandatory_requirements_filtered_jobj(hdr, req_id);
if (!jobj_mandatory)
return -ENOMEM;
json_object_array_add(jobj_mandatory, json_object_new_string(req->description));
if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config))
goto err;
if (!json_object_object_get_ex(jobj_config, "requirements", &jobj_requirements)) {
jobj_requirements = json_object_new_object();
if (!jobj_requirements) {
r = -ENOMEM;
goto err;
}
json_object_object_add(jobj_config, "requirements", jobj_requirements);
}
json_object_object_add(jobj_requirements, "mandatory", jobj_mandatory);
return commit ? LUKS2_hdr_write(cd, hdr) : 0;
err:
json_object_put(jobj_mandatory);
return r;
}
/*
* Header dump
*/

View File

@@ -24,6 +24,8 @@
#include "luks2_internal.h"
#include "utils_device_locking.h"
#define LUKS2_REENCRYPT_REQ_VERSION 2
struct luks2_reencrypt {
/* reencryption window attributes */
uint64_t offset;
@@ -1201,7 +1203,8 @@ static int modify_offset(uint64_t *offset, uint64_t data_shift, crypt_reencrypt_
return r;
}
static int reencrypt_update_flag(struct crypt_device *cd, int enable, bool commit)
static int reencrypt_update_flag(struct crypt_device *cd, uint32_t version,
bool enable, bool commit)
{
uint32_t reqs;
struct luks2_hdr *hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
@@ -1217,12 +1220,14 @@ static int reencrypt_update_flag(struct crypt_device *cd, int enable, bool commi
if (!enable && !(reqs & CRYPT_REQUIREMENT_ONLINE_REENCRYPT))
return -EINVAL;
if (enable)
reqs |= CRYPT_REQUIREMENT_ONLINE_REENCRYPT;
else
if (enable) {
log_dbg(cd, "Going to store reencryption requirement flag (version: %u).", version);
return LUKS2_config_set_requirement_version(cd, hdr, CRYPT_REQUIREMENT_ONLINE_REENCRYPT, version, commit);
}
reqs &= ~CRYPT_REQUIREMENT_ONLINE_REENCRYPT;
log_dbg(cd, "Going to %s reencryption requirement flag.", enable ? "store" : "wipe");
log_dbg(cd, "Going to wipe reencryption requirement flag.");
return LUKS2_config_set_requirements(cd, hdr, reqs, commit);
}
@@ -2516,7 +2521,7 @@ static int reencrypt_init(struct crypt_device *cd,
}
/* 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, LUKS2_REENCRYPT_REQ_VERSION, true, true);
if (r) {
log_dbg(cd, "Failed to set online-reencryption requirement.");
r = -EINVAL;
@@ -3072,11 +3077,11 @@ static int reencrypt_repair_by_passphrase(
goto out;
/* removes online-reencrypt flag v1 */
if ((r = reencrypt_update_flag(cd, 0, false)))
if ((r = reencrypt_update_flag(cd, 0, false, false)))
goto out;
/* adds online-reencrypt flag v2 and commits metadata */
r = reencrypt_update_flag(cd, 1, true);
r = reencrypt_update_flag(cd, LUKS2_REENCRYPT_REQ_VERSION, true, true);
out:
LUKS2_reencrypt_unlock(cd, reencrypt_lock);
crypt_free_volume_key(vks);
@@ -3406,7 +3411,7 @@ static int reencrypt_teardown_ok(struct crypt_device *cd, struct luks2_hdr *hdr,
if (reencrypt_erase_backup_segments(cd, hdr))
log_dbg(cd, "Failed to erase backup segments");
if (reencrypt_update_flag(cd, 0, false))
if (reencrypt_update_flag(cd, 0, false, false))
log_dbg(cd, "Failed to disable reencryption requirement flag.");
/* metadata commit point also removing reencryption flag on-disk */