Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 65de2b8f authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "ANDROID: add dm-default-key target for ICE metadata encryption"

parents 3407a845 3033ca13
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -292,6 +292,22 @@ config DM_REQ_CRYPT
	  To compile this code as a module, choose M here: the module will
	  be called dm-req-crypt.

config DM_DEFAULT_KEY
	tristate "Default-key crypt target support"
	depends on BLK_DEV_DM
	depends on PFK
	---help---
	  This (currently Android-specific) device-mapper target allows you to
	  create a device that assigns a default encryption key to bios that
	  don't already have one.  This can sit between inline cryptographic
	  acceleration hardware and filesystems that use it.  This ensures that
	  where the filesystem doesn't explicitly specify a key, such as for
	  filesystem metadata, a default key will be used instead, leaving no
	  sectors unencrypted.

	  To compile this code as a module, choose M here: the module will be
	  called dm-default-key.

	  If unsure, say N.

config DM_SNAPSHOT
+1 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ obj-$(CONFIG_BLK_DEV_DM_BUILTIN) += dm-builtin.o
obj-$(CONFIG_DM_BUFIO)		+= dm-bufio.o
obj-$(CONFIG_DM_BIO_PRISON)	+= dm-bio-prison.o
obj-$(CONFIG_DM_CRYPT)		+= dm-crypt.o
obj-$(CONFIG_DM_DEFAULT_KEY)	+= dm-default-key.o
obj-$(CONFIG_DM_DELAY)		+= dm-delay.o
obj-$(CONFIG_DM_FLAKEY)		+= dm-flakey.o
obj-$(CONFIG_DM_MULTIPATH)	+= dm-multipath.o dm-round-robin.o
+224 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 Google, Inc.
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/device-mapper.h>
#include <linux/module.h>
#include <linux/pfk.h>

#define DM_MSG_PREFIX "default-key"

struct default_key_c {
	struct dm_dev *dev;
	sector_t start;
	struct blk_encryption_key key;
};

static void default_key_dtr(struct dm_target *ti)
{
	struct default_key_c *dkc = ti->private;

	if (dkc->dev)
		dm_put_device(ti, dkc->dev);
	kzfree(dkc);
}

/*
 * Construct a default-key mapping: <mode> <key> <dev_path> <start>
 */
static int default_key_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
	struct default_key_c *dkc;
	size_t key_size;
	unsigned long long tmp;
	char dummy;
	int err;

	if (argc != 4) {
		ti->error = "Invalid argument count";
		return -EINVAL;
	}

	dkc = kzalloc(sizeof(*dkc), GFP_KERNEL);
	if (!dkc) {
		ti->error = "Out of memory";
		return -ENOMEM;
	}
	ti->private = dkc;

	if (strcmp(argv[0], "AES-256-XTS") != 0) {
		ti->error = "Unsupported encryption mode";
		err = -EINVAL;
		goto bad;
	}

	key_size = strlen(argv[1]);
	if (key_size != 2 * BLK_ENCRYPTION_KEY_SIZE_AES_256_XTS) {
		ti->error = "Unsupported key size";
		err = -EINVAL;
		goto bad;
	}
	key_size /= 2;

	if (hex2bin(dkc->key.raw, argv[1], key_size) != 0) {
		ti->error = "Malformed key string";
		err = -EINVAL;
		goto bad;
	}

	err = dm_get_device(ti, argv[2], dm_table_get_mode(ti->table),
			    &dkc->dev);
	if (err) {
		ti->error = "Device lookup failed";
		goto bad;
	}

	if (sscanf(argv[3], "%llu%c", &tmp, &dummy) != 1) {
		ti->error = "Invalid start sector";
		err = -EINVAL;
		goto bad;
	}
	dkc->start = tmp;

	if (!blk_queue_inlinecrypt(bdev_get_queue(dkc->dev->bdev))) {
		ti->error = "Device does not support inline encryption";
		err = -EINVAL;
		goto bad;
	}

	/* Pass flush requests through to the underlying device. */
	ti->num_flush_bios = 1;

	/*
	 * We pass discard requests through to the underlying device, although
	 * the discarded blocks will be zeroed, which leaks information about
	 * unused blocks.  It's also impossible for dm-default-key to know not
	 * to decrypt discarded blocks, so they will not be read back as zeroes
	 * and we must set discard_zeroes_data_unsupported.
	 */
	ti->num_discard_bios = 1;

	/*
	 * It's unclear whether WRITE_SAME would work with inline encryption; it
	 * would depend on whether the hardware duplicates the data before or
	 * after encryption.  But since the internal storage in some  devices
	 * (MSM8998-based) doesn't claim to support WRITE_SAME anyway, we don't
	 * currently have a way to test it.  Leave it disabled it for now.
	 */
	/*ti->num_write_same_bios = 1;*/

	return 0;

bad:
	default_key_dtr(ti);
	return err;
}

static int default_key_map(struct dm_target *ti, struct bio *bio)
{
	const struct default_key_c *dkc = ti->private;

	bio->bi_bdev = dkc->dev->bdev;
	if (bio_sectors(bio)) {
		bio->bi_iter.bi_sector = dkc->start +
			dm_target_offset(ti, bio->bi_iter.bi_sector);
	}

	if (!bio->bi_crypt_key)
		bio->bi_crypt_key = &dkc->key;

	return DM_MAPIO_REMAPPED;
}

static void default_key_status(struct dm_target *ti, status_type_t type,
			       unsigned int status_flags, char *result,
			       unsigned int maxlen)
{
	const struct default_key_c *dkc = ti->private;
	unsigned int sz = 0;

	switch (type) {
	case STATUSTYPE_INFO:
		result[0] = '\0';
		break;

	case STATUSTYPE_TABLE:

		/* encryption mode */
		DMEMIT("AES-256-XTS");

		/* reserved for key; dm-crypt shows it, but we don't for now */
		DMEMIT(" -");

		/* name of underlying device, and the start sector in it */
		DMEMIT(" %s %llu", dkc->dev->name,
		       (unsigned long long)dkc->start);
		break;
	}
}

static int default_key_prepare_ioctl(struct dm_target *ti,
				     struct block_device **bdev, fmode_t *mode)
{
	struct default_key_c *dkc = ti->private;
	struct dm_dev *dev = dkc->dev;

	*bdev = dev->bdev;

	/*
	 * Only pass ioctls through if the device sizes match exactly.
	 */
	if (dkc->start ||
	    ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT)
		return 1;
	return 0;
}

static int default_key_iterate_devices(struct dm_target *ti,
				       iterate_devices_callout_fn fn,
				       void *data)
{
	struct default_key_c *dkc = ti->private;

	return fn(ti, dkc->dev, dkc->start, ti->len, data);
}

static struct target_type default_key_target = {
	.name   = "default-key",
	.version = {1, 0, 0},
	.module = THIS_MODULE,
	.ctr    = default_key_ctr,
	.dtr    = default_key_dtr,
	.map    = default_key_map,
	.status = default_key_status,
	.prepare_ioctl = default_key_prepare_ioctl,
	.iterate_devices = default_key_iterate_devices,
};

static int __init dm_default_key_init(void)
{
	return dm_register_target(&default_key_target);
}

static void __exit dm_default_key_exit(void)
{
	dm_unregister_target(&default_key_target);
}

module_init(dm_default_key_init);
module_exit(dm_default_key_exit);

MODULE_AUTHOR("Paul Lawrence <paullawrence@google.com>");
MODULE_AUTHOR("Paul Crowley <paulcrowley@google.com>");
MODULE_AUTHOR("Eric Biggers <ebiggers@google.com>");
MODULE_DESCRIPTION(DM_NAME " target for encrypting filesystem metadata");
MODULE_LICENSE("GPL v2");