fname.c 10.3 KB
Newer Older
1
/*
2
 * This contains functions for filename crypto management
3 4 5 6 7
 *
 * Copyright (C) 2015, Google, Inc.
 * Copyright (C) 2015, Motorola Mobility
 *
 * Written by Uday Savagaonkar, 2014.
8
 * Modified by Jaegeuk Kim, 2015.
9 10 11
 *
 * This has not yet undergone a rigorous security audit.
 */
12

13 14
#include <linux/scatterlist.h>
#include <linux/ratelimit.h>
15
#include "fscrypt_private.h"
16 17

/**
18 19 20
 * fname_crypt_complete() - completion callback for filename crypto
 * @req: The asynchronous cipher request context
 * @res: The result of the cipher operation
21
 */
22
static void fname_crypt_complete(struct crypto_async_request *req, int res)
23
{
24
	struct fscrypt_completion_result *ecr = req->data;
25 26 27 28 29 30 31 32

	if (res == -EINPROGRESS)
		return;
	ecr->res = res;
	complete(&ecr->completion);
}

/**
33
 * fname_encrypt() - encrypt a filename
34
 *
35 36 37
 * The caller must have allocated sufficient memory for the @oname string.
 *
 * Return: 0 on success, -errno on failure
38
 */
39 40
static int fname_encrypt(struct inode *inode,
			const struct qstr *iname, struct fscrypt_str *oname)
41
{
H
Herbert Xu 已提交
42
	struct skcipher_request *req = NULL;
43 44
	DECLARE_FS_COMPLETION_RESULT(ecr);
	struct fscrypt_info *ci = inode->i_crypt_info;
H
Herbert Xu 已提交
45
	struct crypto_skcipher *tfm = ci->ci_ctfm;
46
	int res = 0;
47
	char iv[FS_CRYPTO_BLOCK_SIZE];
48
	struct scatterlist sg;
49
	int padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK);
50 51
	unsigned int lim;
	unsigned int cryptlen;
52

53
	lim = inode->i_sb->s_cop->max_namelen(inode);
54 55 56
	if (iname->len <= 0 || iname->len > lim)
		return -EIO;

57 58 59 60 61 62 63 64 65
	/*
	 * Copy the filename to the output buffer for encrypting in-place and
	 * pad it with the needed number of NUL bytes.
	 */
	cryptlen = max_t(unsigned int, iname->len, FS_CRYPTO_BLOCK_SIZE);
	cryptlen = round_up(cryptlen, padding);
	cryptlen = min(cryptlen, lim);
	memcpy(oname->name, iname->name, iname->len);
	memset(oname->name + iname->len, 0, cryptlen - iname->len);
66

67 68
	/* Initialize the IV */
	memset(iv, 0, FS_CRYPTO_BLOCK_SIZE);
69

70
	/* Set up the encryption request */
H
Herbert Xu 已提交
71
	req = skcipher_request_alloc(tfm, GFP_NOFS);
72 73
	if (!req) {
		printk_ratelimited(KERN_ERR
74
			"%s: skcipher_request_alloc() failed\n", __func__);
75 76
		return -ENOMEM;
	}
H
Herbert Xu 已提交
77
	skcipher_request_set_callback(req,
78
			CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
79
			fname_crypt_complete, &ecr);
80 81
	sg_init_one(&sg, oname->name, cryptlen);
	skcipher_request_set_crypt(req, &sg, &sg, cryptlen, iv);
82

83
	/* Do the encryption */
H
Herbert Xu 已提交
84
	res = crypto_skcipher_encrypt(req);
85
	if (res == -EINPROGRESS || res == -EBUSY) {
86
		/* Request is being completed asynchronously; wait for it */
87 88 89
		wait_for_completion(&ecr.completion);
		res = ecr.res;
	}
H
Herbert Xu 已提交
90
	skcipher_request_free(req);
91
	if (res < 0) {
92 93
		printk_ratelimited(KERN_ERR
				"%s: Error (error code %d)\n", __func__, res);
94 95
		return res;
	}
96

97
	oname->len = cryptlen;
98
	return 0;
99 100
}

101 102 103 104 105 106
/**
 * fname_decrypt() - decrypt a filename
 *
 * The caller must have allocated sufficient memory for the @oname string.
 *
 * Return: 0 on success, -errno on failure
107
 */
108 109 110
static int fname_decrypt(struct inode *inode,
				const struct fscrypt_str *iname,
				struct fscrypt_str *oname)
111
{
H
Herbert Xu 已提交
112
	struct skcipher_request *req = NULL;
113
	DECLARE_FS_COMPLETION_RESULT(ecr);
114
	struct scatterlist src_sg, dst_sg;
115
	struct fscrypt_info *ci = inode->i_crypt_info;
H
Herbert Xu 已提交
116
	struct crypto_skcipher *tfm = ci->ci_ctfm;
117
	int res = 0;
118 119
	char iv[FS_CRYPTO_BLOCK_SIZE];
	unsigned lim;
120

121
	lim = inode->i_sb->s_cop->max_namelen(inode);
122 123 124 125
	if (iname->len <= 0 || iname->len > lim)
		return -EIO;

	/* Allocate request */
H
Herbert Xu 已提交
126
	req = skcipher_request_alloc(tfm, GFP_NOFS);
127 128 129 130 131
	if (!req) {
		printk_ratelimited(KERN_ERR
			"%s: crypto_request_alloc() failed\n",  __func__);
		return -ENOMEM;
	}
H
Herbert Xu 已提交
132
	skcipher_request_set_callback(req,
133
		CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
134
		fname_crypt_complete, &ecr);
135 136

	/* Initialize IV */
137
	memset(iv, 0, FS_CRYPTO_BLOCK_SIZE);
138 139 140 141

	/* Create decryption request */
	sg_init_one(&src_sg, iname->name, iname->len);
	sg_init_one(&dst_sg, oname->name, oname->len);
H
Herbert Xu 已提交
142 143
	skcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, iv);
	res = crypto_skcipher_decrypt(req);
144 145 146 147
	if (res == -EINPROGRESS || res == -EBUSY) {
		wait_for_completion(&ecr.completion);
		res = ecr.res;
	}
H
Herbert Xu 已提交
148
	skcipher_request_free(req);
149 150
	if (res < 0) {
		printk_ratelimited(KERN_ERR
151
				"%s: Error (error code %d)\n", __func__, res);
152 153 154 155
		return res;
	}

	oname->len = strnlen(oname->name, iname->len);
156
	return 0;
157 158 159 160 161 162
}

static const char *lookup_table =
	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";

/**
163
 * digest_encode() -
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
 *
 * Encodes the input digest using characters from the set [a-zA-Z0-9_+].
 * The encoded string is roughly 4/3 times the size of the input string.
 */
static int digest_encode(const char *src, int len, char *dst)
{
	int i = 0, bits = 0, ac = 0;
	char *cp = dst;

	while (i < len) {
		ac += (((unsigned char) src[i]) << bits);
		bits += 8;
		do {
			*cp++ = lookup_table[ac & 0x3f];
			ac >>= 6;
			bits -= 6;
		} while (bits >= 6);
		i++;
	}
	if (bits)
		*cp++ = lookup_table[ac & 0x3f];
	return cp - dst;
}

static int digest_decode(const char *src, int len, char *dst)
{
	int i = 0, bits = 0, ac = 0;
	const char *p;
	char *cp = dst;

	while (i < len) {
		p = strchr(lookup_table, src[i]);
		if (p == NULL || src[i] == 0)
			return -2;
		ac += (p - lookup_table) << bits;
		bits += 6;
		if (bits >= 8) {
			*cp++ = ac & 0xff;
			ac >>= 8;
			bits -= 8;
		}
		i++;
	}
	if (ac)
		return -1;
	return cp - dst;
}

212
u32 fscrypt_fname_encrypted_size(const struct inode *inode, u32 ilen)
213
{
214
	int padding = 32;
215
	struct fscrypt_info *ci = inode->i_crypt_info;
216 217

	if (ci)
218
		padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK);
219 220
	ilen = max(ilen, (u32)FS_CRYPTO_BLOCK_SIZE);
	return round_up(ilen, padding);
221
}
222
EXPORT_SYMBOL(fscrypt_fname_encrypted_size);
223 224

/**
225
 * fscrypt_fname_crypto_alloc_obuff() -
226 227 228 229
 *
 * Allocates an output buffer that is sufficient for the crypto operation
 * specified by the context and the direction.
 */
230
int fscrypt_fname_alloc_buffer(const struct inode *inode,
231
				u32 ilen, struct fscrypt_str *crypto_str)
232
{
233
	unsigned int olen = fscrypt_fname_encrypted_size(inode, ilen);
234 235

	crypto_str->len = olen;
236 237 238 239 240 241
	if (olen < FS_FNAME_CRYPTO_DIGEST_SIZE * 2)
		olen = FS_FNAME_CRYPTO_DIGEST_SIZE * 2;
	/*
	 * Allocated buffer can hold one more character to null-terminate the
	 * string
	 */
242 243 244 245 246
	crypto_str->name = kmalloc(olen + 1, GFP_NOFS);
	if (!(crypto_str->name))
		return -ENOMEM;
	return 0;
}
247
EXPORT_SYMBOL(fscrypt_fname_alloc_buffer);
248 249

/**
250
 * fscrypt_fname_crypto_free_buffer() -
251 252 253
 *
 * Frees the buffer allocated for crypto operation.
 */
254
void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str)
255 256 257 258 259 260
{
	if (!crypto_str)
		return;
	kfree(crypto_str->name);
	crypto_str->name = NULL;
}
261
EXPORT_SYMBOL(fscrypt_fname_free_buffer);
262 263

/**
264 265
 * fscrypt_fname_disk_to_usr() - converts a filename from disk space to user
 * space
266 267 268 269
 *
 * The caller must have allocated sufficient memory for the @oname string.
 *
 * Return: 0 on success, -errno on failure
270
 */
271 272 273 274
int fscrypt_fname_disk_to_usr(struct inode *inode,
			u32 hash, u32 minor_hash,
			const struct fscrypt_str *iname,
			struct fscrypt_str *oname)
275 276 277 278
{
	const struct qstr qname = FSTR_TO_QSTR(iname);
	char buf[24];

279
	if (fscrypt_is_dot_dotdot(&qname)) {
280 281 282
		oname->name[0] = '.';
		oname->name[iname->len - 1] = '.';
		oname->len = iname->len;
283
		return 0;
284 285
	}

286
	if (iname->len < FS_CRYPTO_BLOCK_SIZE)
287
		return -EUCLEAN;
288

289 290 291 292
	if (inode->i_crypt_info)
		return fname_decrypt(inode, iname, oname);

	if (iname->len <= FS_FNAME_CRYPTO_DIGEST_SIZE) {
293 294 295
		oname->len = digest_encode(iname->name, iname->len,
					   oname->name);
		return 0;
296 297
	}
	if (hash) {
298 299 300
		memcpy(buf, &hash, 4);
		memcpy(buf + 4, &minor_hash, 4);
	} else {
301
		memset(buf, 0, 8);
302
	}
303
	memcpy(buf + 8, iname->name + ((iname->len - 17) & ~15), 16);
304
	oname->name[0] = '_';
305 306
	oname->len = 1 + digest_encode(buf, 24, oname->name + 1);
	return 0;
307
}
308
EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);
309 310

/**
311 312
 * fscrypt_fname_usr_to_disk() - converts a filename from user space to disk
 * space
313 314 315 316
 *
 * The caller must have allocated sufficient memory for the @oname string.
 *
 * Return: 0 on success, -errno on failure
317
 */
318
int fscrypt_fname_usr_to_disk(struct inode *inode,
319
			const struct qstr *iname,
320
			struct fscrypt_str *oname)
321
{
322
	if (fscrypt_is_dot_dotdot(iname)) {
323 324 325
		oname->name[0] = '.';
		oname->name[iname->len - 1] = '.';
		oname->len = iname->len;
326
		return 0;
327
	}
328 329 330 331
	if (inode->i_crypt_info)
		return fname_encrypt(inode, iname, oname);
	/*
	 * Without a proper key, a user is not allowed to modify the filenames
332
	 * in a directory. Consequently, a user space name cannot be mapped to
333 334
	 * a disk-space name
	 */
335
	return -ENOKEY;
336
}
337
EXPORT_SYMBOL(fscrypt_fname_usr_to_disk);
338

339 340
int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
			      int lookup, struct fscrypt_name *fname)
341 342 343
{
	int ret = 0, bigname = 0;

344
	memset(fname, 0, sizeof(struct fscrypt_name));
345 346
	fname->usr_fname = iname;

347 348
	if (!dir->i_sb->s_cop->is_encrypted(dir) ||
				fscrypt_is_dot_dotdot(iname)) {
349 350
		fname->disk_name.name = (unsigned char *)iname->name;
		fname->disk_name.len = iname->len;
351
		return 0;
352
	}
353
	ret = fscrypt_get_encryption_info(dir);
354
	if (ret && ret != -EOPNOTSUPP)
355
		return ret;
356 357 358 359

	if (dir->i_crypt_info) {
		ret = fscrypt_fname_alloc_buffer(dir, iname->len,
							&fname->crypto_buf);
360
		if (ret)
361
			return ret;
362
		ret = fname_encrypt(dir, iname, &fname->crypto_buf);
363
		if (ret)
364
			goto errout;
365 366
		fname->disk_name.name = fname->crypto_buf.name;
		fname->disk_name.len = fname->crypto_buf.len;
367
		return 0;
368
	}
369
	if (!lookup)
370
		return -ENOKEY;
371

372 373
	/*
	 * We don't have the key and we are doing a lookup; decode the
374 375 376 377
	 * user-supplied name
	 */
	if (iname->name[0] == '_')
		bigname = 1;
378
	if ((bigname && (iname->len != 33)) || (!bigname && (iname->len > 43)))
379 380
		return -ENOENT;

381
	fname->crypto_buf.name = kmalloc(32, GFP_KERNEL);
382 383
	if (fname->crypto_buf.name == NULL)
		return -ENOMEM;
384

385 386 387 388
	ret = digest_decode(iname->name + bigname, iname->len - bigname,
				fname->crypto_buf.name);
	if (ret < 0) {
		ret = -ENOENT;
389
		goto errout;
390 391 392 393
	}
	fname->crypto_buf.len = ret;
	if (bigname) {
		memcpy(&fname->hash, fname->crypto_buf.name, 4);
394
		memcpy(&fname->minor_hash, fname->crypto_buf.name + 4, 4);
395 396 397 398
	} else {
		fname->disk_name.name = fname->crypto_buf.name;
		fname->disk_name.len = fname->crypto_buf.len;
	}
399
	return 0;
400

401
errout:
402
	fscrypt_fname_free_buffer(&fname->crypto_buf);
403 404
	return ret;
}
405
EXPORT_SYMBOL(fscrypt_setup_filename);
406

407
void fscrypt_free_filename(struct fscrypt_name *fname)
408 409 410 411 412 413
{
	kfree(fname->crypto_buf.name);
	fname->crypto_buf.name = NULL;
	fname->usr_fname = NULL;
	fname->disk_name.name = NULL;
}
414
EXPORT_SYMBOL(fscrypt_free_filename);