Blame lib/luks2/luks2_segment.c

Packit 94f725
/*
Packit 94f725
 * LUKS - Linux Unified Key Setup v2, internal segment handling
Packit 94f725
 *
Packit 94f725
 * Copyright (C) 2018-2020, Red Hat, Inc. All rights reserved.
Packit 94f725
 * Copyright (C) 2018-2020, Ondrej Kozina
Packit 94f725
 *
Packit 94f725
 * This program is free software; you can redistribute it and/or
Packit 94f725
 * modify it under the terms of the GNU General Public License
Packit 94f725
 * as published by the Free Software Foundation; either version 2
Packit 94f725
 * of the License, or (at your option) any later version.
Packit 94f725
 *
Packit 94f725
 * This program is distributed in the hope that it will be useful,
Packit 94f725
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 94f725
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 94f725
 * GNU General Public License for more details.
Packit 94f725
 *
Packit 94f725
 * You should have received a copy of the GNU General Public License
Packit 94f725
 * along with this program; if not, write to the Free Software
Packit 94f725
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit 94f725
 */
Packit 94f725
Packit 94f725
#include "luks2_internal.h"
Packit 94f725
Packit 94f725
/* use only on already validated 'segments' object */
Packit 94f725
uint64_t json_segments_get_minimal_offset(json_object *jobj_segments, unsigned blockwise)
Packit 94f725
{
Packit 94f725
	uint64_t tmp, min = blockwise ? UINT64_MAX >> SECTOR_SHIFT : UINT64_MAX;
Packit 94f725
Packit 94f725
	if (!jobj_segments)
Packit 94f725
		return 0;
Packit 94f725
Packit 94f725
	json_object_object_foreach(jobj_segments, key, val) {
Packit 94f725
		UNUSED(key);
Packit 94f725
Packit 94f725
		if (json_segment_is_backup(val))
Packit 94f725
			continue;
Packit 94f725
Packit 94f725
		tmp = json_segment_get_offset(val, blockwise);
Packit 94f725
Packit 94f725
		if (!tmp)
Packit 94f725
			return tmp;
Packit 94f725
Packit 94f725
		if (tmp < min)
Packit 94f725
			min = tmp;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return min;
Packit 94f725
}
Packit 94f725
Packit 94f725
uint64_t json_segment_get_offset(json_object *jobj_segment, unsigned blockwise)
Packit 94f725
{
Packit 94f725
	json_object *jobj;
Packit 94f725
Packit 94f725
	if (!jobj_segment ||
Packit 94f725
	    !json_object_object_get_ex(jobj_segment, "offset", &jobj))
Packit 94f725
		return 0;
Packit 94f725
Packit 94f725
	return blockwise ? crypt_jobj_get_uint64(jobj) >> SECTOR_SHIFT : crypt_jobj_get_uint64(jobj);
Packit 94f725
}
Packit 94f725
Packit 94f725
const char *json_segment_type(json_object *jobj_segment)
Packit 94f725
{
Packit 94f725
	json_object *jobj;
Packit 94f725
Packit 94f725
	if (!jobj_segment ||
Packit 94f725
	    !json_object_object_get_ex(jobj_segment, "type", &jobj))
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	return json_object_get_string(jobj);
Packit 94f725
}
Packit 94f725
Packit 94f725
uint64_t json_segment_get_iv_offset(json_object *jobj_segment)
Packit 94f725
{
Packit 94f725
	json_object *jobj;
Packit 94f725
Packit 94f725
	if (!jobj_segment ||
Packit 94f725
	    !json_object_object_get_ex(jobj_segment, "iv_tweak", &jobj))
Packit 94f725
		return 0;
Packit 94f725
Packit 94f725
	return crypt_jobj_get_uint64(jobj);
Packit 94f725
}
Packit 94f725
Packit 94f725
uint64_t json_segment_get_size(json_object *jobj_segment, unsigned blockwise)
Packit 94f725
{
Packit 94f725
	json_object *jobj;
Packit 94f725
Packit 94f725
	if (!jobj_segment ||
Packit 94f725
	    !json_object_object_get_ex(jobj_segment, "size", &jobj))
Packit 94f725
		return 0;
Packit 94f725
Packit 94f725
	return blockwise ? crypt_jobj_get_uint64(jobj) >> SECTOR_SHIFT : crypt_jobj_get_uint64(jobj);
Packit 94f725
}
Packit 94f725
Packit 94f725
const char *json_segment_get_cipher(json_object *jobj_segment)
Packit 94f725
{
Packit 94f725
	json_object *jobj;
Packit 94f725
Packit 94f725
	/* FIXME: Pseudo "null" cipher should be handled elsewhere */
Packit 94f725
	if (!jobj_segment ||
Packit 94f725
	    !json_object_object_get_ex(jobj_segment, "encryption", &jobj))
Packit 94f725
		return "null";
Packit 94f725
Packit 94f725
	return json_object_get_string(jobj);
Packit 94f725
}
Packit 94f725
Packit 94f725
int json_segment_get_sector_size(json_object *jobj_segment)
Packit 94f725
{
Packit 94f725
	json_object *jobj;
Packit 94f725
Packit 94f725
	if (!jobj_segment ||
Packit 94f725
            !json_object_object_get_ex(jobj_segment, "sector_size", &jobj))
Packit 94f725
		return -1;
Packit 94f725
Packit 94f725
	return json_object_get_int(jobj);
Packit 94f725
}
Packit 94f725
Packit 94f725
static json_object *json_segment_get_flags(json_object *jobj_segment)
Packit 94f725
{
Packit 94f725
	json_object *jobj;
Packit 94f725
Packit 94f725
	if (!jobj_segment || !(json_object_object_get_ex(jobj_segment, "flags", &jobj)))
Packit 94f725
		return NULL;
Packit 94f725
	return jobj;
Packit 94f725
}
Packit 94f725
Packit 94f725
static bool json_segment_contains_flag(json_object *jobj_segment, const char *flag_str, size_t len)
Packit 94f725
{
Packit 94f725
	int r, i;
Packit 94f725
	json_object *jobj, *jobj_flags = json_segment_get_flags(jobj_segment);
Packit 94f725
Packit 94f725
	if (!jobj_flags)
Packit 94f725
		return false;
Packit 94f725
Packit 94f725
	for (i = 0; i < (int)json_object_array_length(jobj_flags); i++) {
Packit 94f725
		jobj = json_object_array_get_idx(jobj_flags, i);
Packit 94f725
		if (len)
Packit 94f725
			r = strncmp(json_object_get_string(jobj), flag_str, len);
Packit 94f725
		else
Packit 94f725
			r = strcmp(json_object_get_string(jobj), flag_str);
Packit 94f725
		if (!r)
Packit 94f725
			return true;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return false;
Packit 94f725
}
Packit 94f725
Packit 94f725
bool json_segment_is_backup(json_object *jobj_segment)
Packit 94f725
{
Packit 94f725
	return json_segment_contains_flag(jobj_segment, "backup-", 7);
Packit 94f725
}
Packit 94f725
Packit 94f725
json_object *json_segments_get_segment(json_object *jobj_segments, int segment)
Packit 94f725
{
Packit 94f725
	json_object *jobj;
Packit 94f725
	char segment_name[16];
Packit 94f725
Packit 94f725
	if (snprintf(segment_name, sizeof(segment_name), "%u", segment) < 1)
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(jobj_segments, segment_name, &jobj))
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	return jobj;
Packit 94f725
}
Packit 94f725
Packit 94f725
unsigned json_segments_count(json_object *jobj_segments)
Packit 94f725
{
Packit 94f725
	unsigned count = 0;
Packit 94f725
Packit 94f725
	if (!jobj_segments)
Packit 94f725
		return 0;
Packit 94f725
Packit 94f725
	json_object_object_foreach(jobj_segments, slot, val) {
Packit 94f725
		UNUSED(slot);
Packit 94f725
		if (!json_segment_is_backup(val))
Packit 94f725
			count++;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return count;
Packit 94f725
}
Packit 94f725
Packit 94f725
static void _get_segment_or_id_by_flag(json_object *jobj_segments, const char *flag, unsigned id, void *retval)
Packit 94f725
{
Packit 94f725
	json_object *jobj_flags, **jobj_ret = (json_object **)retval;
Packit 94f725
	int *ret = (int *)retval;
Packit 94f725
Packit 94f725
	if (!flag)
Packit 94f725
		return;
Packit 94f725
Packit 94f725
	json_object_object_foreach(jobj_segments, key, value) {
Packit 94f725
		if (!json_object_object_get_ex(value, "flags", &jobj_flags))
Packit 94f725
			continue;
Packit 94f725
		if (LUKS2_array_jobj(jobj_flags, flag)) {
Packit 94f725
			if (id)
Packit 94f725
				*ret = atoi(key);
Packit 94f725
			else
Packit 94f725
				*jobj_ret = value;
Packit 94f725
			return;
Packit 94f725
		}
Packit 94f725
	}
Packit 94f725
}
Packit 94f725
Packit 94f725
void json_segment_remove_flag(json_object *jobj_segment, const char *flag)
Packit 94f725
{
Packit 94f725
	json_object *jobj_flags, *jobj_flags_new;
Packit 94f725
Packit 94f725
	if (!jobj_segment)
Packit 94f725
		return;
Packit 94f725
Packit 94f725
	jobj_flags = json_segment_get_flags(jobj_segment);
Packit 94f725
	if (!jobj_flags)
Packit 94f725
		return;
Packit 94f725
Packit 94f725
	jobj_flags_new = LUKS2_array_remove(jobj_flags, flag);
Packit 94f725
	if (!jobj_flags_new)
Packit 94f725
		return;
Packit 94f725
Packit 94f725
	if (json_object_array_length(jobj_flags_new) <= 0) {
Packit 94f725
		json_object_put(jobj_flags_new);
Packit 94f725
		json_object_object_del(jobj_segment, "flags");
Packit 94f725
	} else
Packit 94f725
		json_object_object_add(jobj_segment, "flags", jobj_flags_new);
Packit 94f725
}
Packit 94f725
Packit 94f725
static json_object *_segment_create_generic(const char *type, uint64_t offset, const uint64_t *length)
Packit 94f725
{
Packit 94f725
	json_object *jobj = json_object_new_object();
Packit 94f725
	if (!jobj)
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	json_object_object_add(jobj, "type",		json_object_new_string(type));
Packit 94f725
	json_object_object_add(jobj, "offset",		crypt_jobj_new_uint64(offset));
Packit 94f725
	json_object_object_add(jobj, "size",		length ? crypt_jobj_new_uint64(*length) : json_object_new_string("dynamic"));
Packit 94f725
Packit 94f725
	return jobj;
Packit 94f725
}
Packit 94f725
Packit 94f725
json_object *json_segment_create_linear(uint64_t offset, const uint64_t *length, unsigned reencryption)
Packit 94f725
{
Packit 94f725
	json_object *jobj = _segment_create_generic("linear", offset, length);
Packit 94f725
	if (reencryption)
Packit 94f725
		LUKS2_segment_set_flag(jobj, "in-reencryption");
Packit 94f725
	return jobj;
Packit 94f725
}
Packit 94f725
Packit 94f725
json_object *json_segment_create_crypt(uint64_t offset,
Packit 94f725
				  uint64_t iv_offset, const uint64_t *length,
Packit 94f725
				  const char *cipher, uint32_t sector_size,
Packit 94f725
				  unsigned reencryption)
Packit 94f725
{
Packit 94f725
	json_object *jobj = _segment_create_generic("crypt", offset, length);
Packit 94f725
	if (!jobj)
Packit 94f725
		return NULL;
Packit 94f725
Packit 94f725
	json_object_object_add(jobj, "iv_tweak",	crypt_jobj_new_uint64(iv_offset));
Packit 94f725
	json_object_object_add(jobj, "encryption",	json_object_new_string(cipher));
Packit 94f725
	json_object_object_add(jobj, "sector_size",	json_object_new_int(sector_size));
Packit 94f725
	if (reencryption)
Packit 94f725
		LUKS2_segment_set_flag(jobj, "in-reencryption");
Packit 94f725
Packit 94f725
	return jobj;
Packit 94f725
}
Packit 94f725
Packit 94f725
uint64_t LUKS2_segment_offset(struct luks2_hdr *hdr, int segment, unsigned blockwise)
Packit 94f725
{
Packit 94f725
	return json_segment_get_offset(LUKS2_get_segment_jobj(hdr, segment), blockwise);
Packit 94f725
}
Packit 94f725
Packit 94f725
int json_segments_segment_in_reencrypt(json_object *jobj_segments)
Packit 94f725
{
Packit 94f725
	json_object *jobj_flags;
Packit 94f725
Packit 94f725
	json_object_object_foreach(jobj_segments, slot, val) {
Packit 94f725
		if (!json_object_object_get_ex(val, "flags", &jobj_flags) ||
Packit 94f725
		    !LUKS2_array_jobj(jobj_flags, "in-reencryption"))
Packit 94f725
			continue;
Packit 94f725
Packit 94f725
		return atoi(slot);
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return -1;
Packit 94f725
}
Packit 94f725
Packit 94f725
uint64_t LUKS2_segment_size(struct luks2_hdr *hdr, int segment, unsigned blockwise)
Packit 94f725
{
Packit 94f725
	return json_segment_get_size(LUKS2_get_segment_jobj(hdr, segment), blockwise);
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_segment_is_type(struct luks2_hdr *hdr, int segment, const char *type)
Packit 94f725
{
Packit 94f725
	return !strcmp(json_segment_type(LUKS2_get_segment_jobj(hdr, segment)) ?: "", type);
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_last_segment_by_type(struct luks2_hdr *hdr, const char *type)
Packit 94f725
{
Packit 94f725
	json_object *jobj_segments;
Packit 94f725
	int last_found = -1;
Packit 94f725
Packit 94f725
	if (!type)
Packit 94f725
		return -1;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
Packit 94f725
		return -1;
Packit 94f725
Packit 94f725
	json_object_object_foreach(jobj_segments, slot, val) {
Packit 94f725
		if (json_segment_is_backup(val))
Packit 94f725
			continue;
Packit 94f725
		if (strcmp(type, json_segment_type(val) ?: ""))
Packit 94f725
			continue;
Packit 94f725
Packit 94f725
		if (atoi(slot) > last_found)
Packit 94f725
			last_found = atoi(slot);
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return last_found;
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_segment_by_type(struct luks2_hdr *hdr, const char *type)
Packit 94f725
{
Packit 94f725
	json_object *jobj_segments;
Packit 94f725
	int first_found = -1;
Packit 94f725
Packit 94f725
	if (!type)
Packit 94f725
		return -EINVAL;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
Packit 94f725
		return -EINVAL;
Packit 94f725
Packit 94f725
	json_object_object_foreach(jobj_segments, slot, val) {
Packit 94f725
		if (json_segment_is_backup(val))
Packit 94f725
			continue;
Packit 94f725
		if (strcmp(type, json_segment_type(val) ?: ""))
Packit 94f725
			continue;
Packit 94f725
Packit 94f725
		if (first_found < 0)
Packit 94f725
			first_found = atoi(slot);
Packit 94f725
		else if (atoi(slot) < first_found)
Packit 94f725
			first_found = atoi(slot);
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return first_found;
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_segment_first_unused_id(struct luks2_hdr *hdr)
Packit 94f725
{
Packit 94f725
	json_object *jobj_segments;
Packit 94f725
	int id, last_id = -1;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(hdr->jobj, "segments", &jobj_segments))
Packit 94f725
		return -EINVAL;
Packit 94f725
Packit 94f725
	json_object_object_foreach(jobj_segments, slot, val) {
Packit 94f725
		UNUSED(val);
Packit 94f725
		id = atoi(slot);
Packit 94f725
		if (id > last_id)
Packit 94f725
			last_id = id;
Packit 94f725
	}
Packit 94f725
Packit 94f725
	return last_id + 1;
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_segment_set_flag(json_object *jobj_segment, const char *flag)
Packit 94f725
{
Packit 94f725
	json_object *jobj_flags;
Packit 94f725
Packit 94f725
	if (!jobj_segment || !flag)
Packit 94f725
		return -EINVAL;
Packit 94f725
Packit 94f725
	if (!json_object_object_get_ex(jobj_segment, "flags", &jobj_flags)) {
Packit 94f725
		jobj_flags = json_object_new_array();
Packit 94f725
		if (!jobj_flags)
Packit 94f725
			return -ENOMEM;
Packit 94f725
		json_object_object_add(jobj_segment, "flags", jobj_flags);
Packit 94f725
	}
Packit 94f725
Packit 94f725
	if (LUKS2_array_jobj(jobj_flags, flag))
Packit 94f725
		return 0;
Packit 94f725
Packit 94f725
	json_object_array_add(jobj_flags, json_object_new_string(flag));
Packit 94f725
Packit 94f725
	return 0;
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_segments_set(struct crypt_device *cd, struct luks2_hdr *hdr,
Packit 94f725
		       json_object *jobj_segments, int commit)
Packit 94f725
{
Packit 94f725
	json_object_object_add(hdr->jobj, "segments", jobj_segments);
Packit 94f725
Packit 94f725
	return commit ? LUKS2_hdr_write(cd, hdr) : 0;
Packit 94f725
}
Packit 94f725
Packit 94f725
int LUKS2_get_segment_id_by_flag(struct luks2_hdr *hdr, const char *flag)
Packit 94f725
{
Packit 94f725
	int ret = -ENOENT;
Packit 94f725
	json_object *jobj_segments = LUKS2_get_segments_jobj(hdr);
Packit 94f725
Packit 94f725
	if (jobj_segments)
Packit 94f725
		_get_segment_or_id_by_flag(jobj_segments, flag, 1, &ret;;
Packit 94f725
Packit 94f725
	return ret;
Packit 94f725
}
Packit 94f725
Packit 94f725
json_object *LUKS2_get_segment_by_flag(struct luks2_hdr *hdr, const char *flag)
Packit 94f725
{
Packit 94f725
	json_object *jobj_segment = NULL,
Packit 94f725
		    *jobj_segments = LUKS2_get_segments_jobj(hdr);
Packit 94f725
Packit 94f725
	if (jobj_segments)
Packit 94f725
		_get_segment_or_id_by_flag(jobj_segments, flag, 0, &jobj_segment);
Packit 94f725
Packit 94f725
	return jobj_segment;
Packit 94f725
}