big_key.c 8.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/* Large capacity key type
 *
 * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved.
 * Written by David Howells (dhowells@redhat.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public Licence
 * as published by the Free Software Foundation; either version
 * 2 of the Licence, or (at your option) any later version.
 */

12
#define pr_fmt(fmt) "big_key: "fmt
13 14 15 16 17
#include <linux/init.h>
#include <linux/seq_file.h>
#include <linux/file.h>
#include <linux/shmem_fs.h>
#include <linux/err.h>
18
#include <linux/scatterlist.h>
19 20
#include <keys/user-type.h>
#include <keys/big_key-type.h>
21
#include <crypto/rng.h>
H
Herbert Xu 已提交
22
#include <crypto/skcipher.h>
23

24 25 26 27 28 29 30 31 32 33
/*
 * Layout of key payload words.
 */
enum {
	big_key_data,
	big_key_path,
	big_key_path_2nd_part,
	big_key_len,
};

34 35 36 37 38 39 40 41
/*
 * Crypto operation with big_key data
 */
enum big_key_op {
	BIG_KEY_ENC,
	BIG_KEY_DEC,
};

42 43 44 45 46 47 48
/*
 * If the data is under this limit, there's no point creating a shm file to
 * hold it as the permanently resident metadata for the shmem fs will be at
 * least as large as the data.
 */
#define BIG_KEY_FILE_THRESHOLD (sizeof(struct inode) + sizeof(struct dentry))

49 50 51 52 53
/*
 * Key size for big_key data encryption
 */
#define ENC_KEY_SIZE	16

54 55 56 57 58 59
/*
 * big_key defined keys take an arbitrary string as the description and an
 * arbitrary blob of data as the payload
 */
struct key_type key_type_big_key = {
	.name			= "big_key",
60 61 62
	.preparse		= big_key_preparse,
	.free_preparse		= big_key_free_preparse,
	.instantiate		= generic_key_instantiate,
63 64 65 66 67 68
	.revoke			= big_key_revoke,
	.destroy		= big_key_destroy,
	.describe		= big_key_describe,
	.read			= big_key_read,
};

69 70 71 72 73 74 75 76 77 78
/*
 * Crypto names for big_key data encryption
 */
static const char big_key_rng_name[] = "stdrng";
static const char big_key_alg_name[] = "ecb(aes)";

/*
 * Crypto algorithms for big_key data encryption
 */
static struct crypto_rng *big_key_rng;
H
Herbert Xu 已提交
79
static struct crypto_skcipher *big_key_skcipher;
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95

/*
 * Generate random key to encrypt big_key data
 */
static inline int big_key_gen_enckey(u8 *key)
{
	return crypto_rng_get_bytes(big_key_rng, key, ENC_KEY_SIZE);
}

/*
 * Encrypt/decrypt big_key data
 */
static int big_key_crypt(enum big_key_op op, u8 *data, size_t datalen, u8 *key)
{
	int ret = -EINVAL;
	struct scatterlist sgio;
H
Herbert Xu 已提交
96
	SKCIPHER_REQUEST_ON_STACK(req, big_key_skcipher);
97

H
Herbert Xu 已提交
98
	if (crypto_skcipher_setkey(big_key_skcipher, key, ENC_KEY_SIZE)) {
99 100 101 102
		ret = -EAGAIN;
		goto error;
	}

H
Herbert Xu 已提交
103 104 105
	skcipher_request_set_tfm(req, big_key_skcipher);
	skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP,
				      NULL, NULL);
106 107

	sg_init_one(&sgio, data, datalen);
H
Herbert Xu 已提交
108
	skcipher_request_set_crypt(req, &sgio, &sgio, datalen, NULL);
109 110

	if (op == BIG_KEY_ENC)
H
Herbert Xu 已提交
111
		ret = crypto_skcipher_encrypt(req);
112
	else
H
Herbert Xu 已提交
113 114 115
		ret = crypto_skcipher_decrypt(req);

	skcipher_request_zero(req);
116 117 118 119 120

error:
	return ret;
}

121
/*
122
 * Preparse a big key
123
 */
124
int big_key_preparse(struct key_preparsed_payload *prep)
125
{
126
	struct path *path = (struct path *)&prep->payload.data[big_key_path];
127
	struct file *file;
128 129
	u8 *enckey;
	u8 *data = NULL;
130 131 132 133 134 135 136 137 138
	ssize_t written;
	size_t datalen = prep->datalen;
	int ret;

	ret = -EINVAL;
	if (datalen <= 0 || datalen > 1024 * 1024 || !prep->data)
		goto error;

	/* Set an arbitrary quota */
139
	prep->quotalen = 16;
140

141
	prep->payload.data[big_key_len] = (void *)(unsigned long)datalen;
142 143 144 145 146

	if (datalen > BIG_KEY_FILE_THRESHOLD) {
		/* Create a shmem file to store the data in.  This will permit the data
		 * to be swapped out if needed.
		 *
147
		 * File content is stored encrypted with randomly generated key.
148
		 */
H
Herbert Xu 已提交
149
		size_t enclen = ALIGN(datalen, crypto_skcipher_blocksize(big_key_skcipher));
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176

		/* prepare aligned data to encrypt */
		data = kmalloc(enclen, GFP_KERNEL);
		if (!data)
			return -ENOMEM;

		memcpy(data, prep->data, datalen);
		memset(data + datalen, 0x00, enclen - datalen);

		/* generate random key */
		enckey = kmalloc(ENC_KEY_SIZE, GFP_KERNEL);
		if (!enckey) {
			ret = -ENOMEM;
			goto error;
		}

		ret = big_key_gen_enckey(enckey);
		if (ret)
			goto err_enckey;

		/* encrypt aligned data */
		ret = big_key_crypt(BIG_KEY_ENC, data, enclen, enckey);
		if (ret)
			goto err_enckey;

		/* save aligned data to file */
		file = shmem_kernel_file_setup("", enclen, 0);
177 178
		if (IS_ERR(file)) {
			ret = PTR_ERR(file);
179
			goto err_enckey;
180
		}
181

182 183
		written = kernel_write(file, data, enclen, 0);
		if (written != enclen) {
184
			ret = written;
185 186 187 188 189 190 191 192
			if (written >= 0)
				ret = -ENOMEM;
			goto err_fput;
		}

		/* Pin the mount and dentry to the key so that we can open it again
		 * later
		 */
193
		prep->payload.data[big_key_data] = enckey;
194 195 196
		*path = file->f_path;
		path_get(path);
		fput(file);
197
		kfree(data);
198 199 200
	} else {
		/* Just store the data in a buffer */
		void *data = kmalloc(datalen, GFP_KERNEL);
201

202 203
		if (!data)
			return -ENOMEM;
204

205 206
		prep->payload.data[big_key_data] = data;
		memcpy(data, prep->data, prep->datalen);
207 208 209 210 211
	}
	return 0;

err_fput:
	fput(file);
212 213
err_enckey:
	kfree(enckey);
214
error:
215
	kfree(data);
216 217 218
	return ret;
}

219 220 221 222 223 224
/*
 * Clear preparsement.
 */
void big_key_free_preparse(struct key_preparsed_payload *prep)
{
	if (prep->datalen > BIG_KEY_FILE_THRESHOLD) {
225
		struct path *path = (struct path *)&prep->payload.data[big_key_path];
226

227 228
		path_put(path);
	}
229
	kfree(prep->payload.data[big_key_data]);
230 231
}

232 233 234 235 236 237
/*
 * dispose of the links from a revoked keyring
 * - called with the key sem write-locked
 */
void big_key_revoke(struct key *key)
{
238
	struct path *path = (struct path *)&key->payload.data[big_key_path];
239 240 241

	/* clear the quota */
	key_payload_reserve(key, 0);
242 243
	if (key_is_instantiated(key) &&
	    (size_t)key->payload.data[big_key_len] > BIG_KEY_FILE_THRESHOLD)
244 245 246 247 248 249 250 251
		vfs_truncate(path, 0);
}

/*
 * dispose of the data dangling from the corpse of a big_key key
 */
void big_key_destroy(struct key *key)
{
252 253
	size_t datalen = (size_t)key->payload.data[big_key_len];

254
	if (datalen > BIG_KEY_FILE_THRESHOLD) {
255
		struct path *path = (struct path *)&key->payload.data[big_key_path];
256

257 258 259 260
		path_put(path);
		path->mnt = NULL;
		path->dentry = NULL;
	}
261 262
	kfree(key->payload.data[big_key_data]);
	key->payload.data[big_key_data] = NULL;
263 264 265 266 267 268 269
}

/*
 * describe the big_key key
 */
void big_key_describe(const struct key *key, struct seq_file *m)
{
270
	size_t datalen = (size_t)key->payload.data[big_key_len];
271 272 273 274

	seq_puts(m, key->description);

	if (key_is_instantiated(key))
275
		seq_printf(m, ": %zu [%s]",
276 277 278 279 280 281 282 283 284 285
			   datalen,
			   datalen > BIG_KEY_FILE_THRESHOLD ? "file" : "buff");
}

/*
 * read the key data
 * - the key's semaphore is read-locked
 */
long big_key_read(const struct key *key, char __user *buffer, size_t buflen)
{
286
	size_t datalen = (size_t)key->payload.data[big_key_len];
287 288 289 290 291 292
	long ret;

	if (!buffer || buflen < datalen)
		return datalen;

	if (datalen > BIG_KEY_FILE_THRESHOLD) {
293
		struct path *path = (struct path *)&key->payload.data[big_key_path];
294
		struct file *file;
295 296
		u8 *data;
		u8 *enckey = (u8 *)key->payload.data[big_key_data];
H
Herbert Xu 已提交
297
		size_t enclen = ALIGN(datalen, crypto_skcipher_blocksize(big_key_skcipher));
298 299 300 301

		data = kmalloc(enclen, GFP_KERNEL);
		if (!data)
			return -ENOMEM;
302 303

		file = dentry_open(path, O_RDONLY, current_cred());
304 305 306 307
		if (IS_ERR(file)) {
			ret = PTR_ERR(file);
			goto error;
		}
308

309 310 311
		/* read file to kernel and decrypt */
		ret = kernel_read(file, 0, data, enclen);
		if (ret >= 0 && ret != enclen) {
312
			ret = -EIO;
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
			goto err_fput;
		}

		ret = big_key_crypt(BIG_KEY_DEC, data, enclen, enckey);
		if (ret)
			goto err_fput;

		ret = datalen;

		/* copy decrypted data to user */
		if (copy_to_user(buffer, data, datalen) != 0)
			ret = -EFAULT;

err_fput:
		fput(file);
error:
		kfree(data);
330 331
	} else {
		ret = datalen;
332 333
		if (copy_to_user(buffer, key->payload.data[big_key_data],
				 datalen) != 0)
334 335 336 337 338 339
			ret = -EFAULT;
	}

	return ret;
}

340 341 342
/*
 * Register key type
 */
343 344
static int __init big_key_init(void)
{
345 346 347
	struct crypto_skcipher *cipher;
	struct crypto_rng *rng;
	int ret;
348

349 350 351 352
	rng = crypto_alloc_rng(big_key_rng_name, 0, 0);
	if (IS_ERR(rng)) {
		pr_err("Can't alloc rng: %ld\n", PTR_ERR(rng));
		return PTR_ERR(rng);
353 354
	}

355 356
	big_key_rng = rng;

357
	/* seed RNG */
358 359 360 361 362
	ret = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng));
	if (ret) {
		pr_err("Can't reset rng: %d\n", ret);
		goto error_rng;
	}
363 364

	/* init block cipher */
365 366 367 368 369 370 371 372 373 374 375 376 377
	cipher = crypto_alloc_skcipher(big_key_alg_name, 0, CRYPTO_ALG_ASYNC);
	if (IS_ERR(cipher)) {
		ret = PTR_ERR(cipher);
		pr_err("Can't alloc crypto: %d\n", ret);
		goto error_rng;
	}

	big_key_skcipher = cipher;

	ret = register_key_type(&key_type_big_key);
	if (ret < 0) {
		pr_err("Can't register type: %d\n", ret);
		goto error_cipher;
378 379 380 381
	}

	return 0;

382 383 384
error_cipher:
	crypto_free_skcipher(big_key_skcipher);
error_rng:
385 386 387 388
	crypto_free_rng(big_key_rng);
	return ret;
}

389
late_initcall(big_key_init);