Commit | Line | Data |
---|---|---|
d5d0e8c7 MH |
1 | /* |
2 | * linux/fs/ext4/crypto_fname.c | |
3 | * | |
4 | * Copyright (C) 2015, Google, Inc. | |
5 | * | |
6 | * This contains functions for filename crypto management in ext4 | |
7 | * | |
8 | * Written by Uday Savagaonkar, 2014. | |
9 | * | |
10 | * This has not yet undergone a rigorous security audit. | |
11 | * | |
12 | */ | |
13 | ||
14 | #include <crypto/hash.h> | |
15 | #include <crypto/sha.h> | |
16 | #include <keys/encrypted-type.h> | |
17 | #include <keys/user-type.h> | |
18 | #include <linux/crypto.h> | |
19 | #include <linux/gfp.h> | |
20 | #include <linux/kernel.h> | |
21 | #include <linux/key.h> | |
22 | #include <linux/key.h> | |
23 | #include <linux/list.h> | |
24 | #include <linux/mempool.h> | |
25 | #include <linux/random.h> | |
26 | #include <linux/scatterlist.h> | |
27 | #include <linux/spinlock_types.h> | |
28 | ||
29 | #include "ext4.h" | |
30 | #include "ext4_crypto.h" | |
31 | #include "xattr.h" | |
32 | ||
33 | /** | |
34 | * ext4_dir_crypt_complete() - | |
35 | */ | |
36 | static void ext4_dir_crypt_complete(struct crypto_async_request *req, int res) | |
37 | { | |
38 | struct ext4_completion_result *ecr = req->data; | |
39 | ||
40 | if (res == -EINPROGRESS) | |
41 | return; | |
42 | ecr->res = res; | |
43 | complete(&ecr->completion); | |
44 | } | |
45 | ||
46 | bool ext4_valid_filenames_enc_mode(uint32_t mode) | |
47 | { | |
48 | return (mode == EXT4_ENCRYPTION_MODE_AES_256_CTS); | |
49 | } | |
50 | ||
b7236e21 TT |
51 | static unsigned max_name_len(struct inode *inode) |
52 | { | |
53 | return S_ISLNK(inode->i_mode) ? inode->i_sb->s_blocksize : | |
54 | EXT4_NAME_LEN; | |
55 | } | |
56 | ||
d5d0e8c7 MH |
57 | /** |
58 | * ext4_fname_encrypt() - | |
59 | * | |
60 | * This function encrypts the input filename, and returns the length of the | |
61 | * ciphertext. Errors are returned as negative numbers. We trust the caller to | |
62 | * allocate sufficient memory to oname string. | |
63 | */ | |
b7236e21 | 64 | static int ext4_fname_encrypt(struct inode *inode, |
d5d0e8c7 MH |
65 | const struct qstr *iname, |
66 | struct ext4_str *oname) | |
67 | { | |
68 | u32 ciphertext_len; | |
69 | struct ablkcipher_request *req = NULL; | |
70 | DECLARE_EXT4_COMPLETION_RESULT(ecr); | |
b7236e21 TT |
71 | struct ext4_crypt_info *ci = EXT4_I(inode)->i_crypt_info; |
72 | struct crypto_ablkcipher *tfm = ci->ci_ctfm; | |
d5d0e8c7 MH |
73 | int res = 0; |
74 | char iv[EXT4_CRYPTO_BLOCK_SIZE]; | |
d2299590 | 75 | struct scatterlist src_sg, dst_sg; |
b7236e21 | 76 | int padding = 4 << (ci->ci_flags & EXT4_POLICY_FLAGS_PAD_MASK); |
d2299590 | 77 | char *workbuf, buf[32], *alloc_buf = NULL; |
b7236e21 | 78 | unsigned lim = max_name_len(inode); |
d5d0e8c7 | 79 | |
b7236e21 | 80 | if (iname->len <= 0 || iname->len > lim) |
d5d0e8c7 MH |
81 | return -EIO; |
82 | ||
83 | ciphertext_len = (iname->len < EXT4_CRYPTO_BLOCK_SIZE) ? | |
84 | EXT4_CRYPTO_BLOCK_SIZE : iname->len; | |
a44cd7a0 | 85 | ciphertext_len = ext4_fname_crypto_round_up(ciphertext_len, padding); |
b7236e21 TT |
86 | ciphertext_len = (ciphertext_len > lim) |
87 | ? lim : ciphertext_len; | |
d5d0e8c7 | 88 | |
d2299590 TT |
89 | if (ciphertext_len <= sizeof(buf)) { |
90 | workbuf = buf; | |
91 | } else { | |
92 | alloc_buf = kmalloc(ciphertext_len, GFP_NOFS); | |
93 | if (!alloc_buf) | |
94 | return -ENOMEM; | |
95 | workbuf = alloc_buf; | |
96 | } | |
97 | ||
d5d0e8c7 MH |
98 | /* Allocate request */ |
99 | req = ablkcipher_request_alloc(tfm, GFP_NOFS); | |
100 | if (!req) { | |
101 | printk_ratelimited( | |
102 | KERN_ERR "%s: crypto_request_alloc() failed\n", __func__); | |
d2299590 | 103 | kfree(alloc_buf); |
d5d0e8c7 MH |
104 | return -ENOMEM; |
105 | } | |
106 | ablkcipher_request_set_callback(req, | |
107 | CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, | |
108 | ext4_dir_crypt_complete, &ecr); | |
109 | ||
d5d0e8c7 MH |
110 | /* Copy the input */ |
111 | memcpy(workbuf, iname->name, iname->len); | |
112 | if (iname->len < ciphertext_len) | |
113 | memset(workbuf + iname->len, 0, ciphertext_len - iname->len); | |
114 | ||
115 | /* Initialize IV */ | |
116 | memset(iv, 0, EXT4_CRYPTO_BLOCK_SIZE); | |
117 | ||
118 | /* Create encryption request */ | |
d2299590 TT |
119 | sg_init_one(&src_sg, workbuf, ciphertext_len); |
120 | sg_init_one(&dst_sg, oname->name, ciphertext_len); | |
121 | ablkcipher_request_set_crypt(req, &src_sg, &dst_sg, ciphertext_len, iv); | |
d5d0e8c7 MH |
122 | res = crypto_ablkcipher_encrypt(req); |
123 | if (res == -EINPROGRESS || res == -EBUSY) { | |
124 | BUG_ON(req->base.data != &ecr); | |
125 | wait_for_completion(&ecr.completion); | |
126 | res = ecr.res; | |
127 | } | |
d2299590 | 128 | kfree(alloc_buf); |
d5d0e8c7 MH |
129 | ablkcipher_request_free(req); |
130 | if (res < 0) { | |
131 | printk_ratelimited( | |
132 | KERN_ERR "%s: Error (error code %d)\n", __func__, res); | |
133 | } | |
134 | oname->len = ciphertext_len; | |
135 | return res; | |
136 | } | |
137 | ||
138 | /* | |
139 | * ext4_fname_decrypt() | |
140 | * This function decrypts the input filename, and returns | |
141 | * the length of the plaintext. | |
142 | * Errors are returned as negative numbers. | |
143 | * We trust the caller to allocate sufficient memory to oname string. | |
144 | */ | |
b7236e21 | 145 | static int ext4_fname_decrypt(struct inode *inode, |
d5d0e8c7 MH |
146 | const struct ext4_str *iname, |
147 | struct ext4_str *oname) | |
148 | { | |
149 | struct ext4_str tmp_in[2], tmp_out[1]; | |
150 | struct ablkcipher_request *req = NULL; | |
151 | DECLARE_EXT4_COMPLETION_RESULT(ecr); | |
d2299590 | 152 | struct scatterlist src_sg, dst_sg; |
b7236e21 TT |
153 | struct ext4_crypt_info *ci = EXT4_I(inode)->i_crypt_info; |
154 | struct crypto_ablkcipher *tfm = ci->ci_ctfm; | |
d5d0e8c7 MH |
155 | int res = 0; |
156 | char iv[EXT4_CRYPTO_BLOCK_SIZE]; | |
b7236e21 | 157 | unsigned lim = max_name_len(inode); |
d5d0e8c7 | 158 | |
b7236e21 | 159 | if (iname->len <= 0 || iname->len > lim) |
d5d0e8c7 MH |
160 | return -EIO; |
161 | ||
162 | tmp_in[0].name = iname->name; | |
163 | tmp_in[0].len = iname->len; | |
164 | tmp_out[0].name = oname->name; | |
165 | ||
166 | /* Allocate request */ | |
167 | req = ablkcipher_request_alloc(tfm, GFP_NOFS); | |
168 | if (!req) { | |
169 | printk_ratelimited( | |
170 | KERN_ERR "%s: crypto_request_alloc() failed\n", __func__); | |
171 | return -ENOMEM; | |
172 | } | |
173 | ablkcipher_request_set_callback(req, | |
174 | CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, | |
175 | ext4_dir_crypt_complete, &ecr); | |
176 | ||
d5d0e8c7 MH |
177 | /* Initialize IV */ |
178 | memset(iv, 0, EXT4_CRYPTO_BLOCK_SIZE); | |
179 | ||
180 | /* Create encryption request */ | |
d2299590 TT |
181 | sg_init_one(&src_sg, iname->name, iname->len); |
182 | sg_init_one(&dst_sg, oname->name, oname->len); | |
183 | ablkcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, iv); | |
d5d0e8c7 MH |
184 | res = crypto_ablkcipher_decrypt(req); |
185 | if (res == -EINPROGRESS || res == -EBUSY) { | |
186 | BUG_ON(req->base.data != &ecr); | |
187 | wait_for_completion(&ecr.completion); | |
188 | res = ecr.res; | |
189 | } | |
d5d0e8c7 MH |
190 | ablkcipher_request_free(req); |
191 | if (res < 0) { | |
192 | printk_ratelimited( | |
193 | KERN_ERR "%s: Error in ext4_fname_encrypt (error code %d)\n", | |
194 | __func__, res); | |
195 | return res; | |
196 | } | |
197 | ||
198 | oname->len = strnlen(oname->name, iname->len); | |
199 | return oname->len; | |
200 | } | |
201 | ||
5de0b4d0 TT |
202 | static const char *lookup_table = |
203 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; | |
204 | ||
d5d0e8c7 MH |
205 | /** |
206 | * ext4_fname_encode_digest() - | |
207 | * | |
208 | * Encodes the input digest using characters from the set [a-zA-Z0-9_+]. | |
209 | * The encoded string is roughly 4/3 times the size of the input string. | |
210 | */ | |
5de0b4d0 | 211 | static int digest_encode(const char *src, int len, char *dst) |
d5d0e8c7 | 212 | { |
5de0b4d0 TT |
213 | int i = 0, bits = 0, ac = 0; |
214 | char *cp = dst; | |
215 | ||
216 | while (i < len) { | |
217 | ac += (((unsigned char) src[i]) << bits); | |
218 | bits += 8; | |
219 | do { | |
220 | *cp++ = lookup_table[ac & 0x3f]; | |
221 | ac >>= 6; | |
222 | bits -= 6; | |
223 | } while (bits >= 6); | |
d5d0e8c7 MH |
224 | i++; |
225 | } | |
5de0b4d0 TT |
226 | if (bits) |
227 | *cp++ = lookup_table[ac & 0x3f]; | |
228 | return cp - dst; | |
d5d0e8c7 MH |
229 | } |
230 | ||
5de0b4d0 | 231 | static int digest_decode(const char *src, int len, char *dst) |
d5d0e8c7 | 232 | { |
5de0b4d0 TT |
233 | int i = 0, bits = 0, ac = 0; |
234 | const char *p; | |
235 | char *cp = dst; | |
236 | ||
237 | while (i < len) { | |
238 | p = strchr(lookup_table, src[i]); | |
239 | if (p == NULL || src[i] == 0) | |
240 | return -2; | |
241 | ac += (p - lookup_table) << bits; | |
242 | bits += 6; | |
243 | if (bits >= 8) { | |
244 | *cp++ = ac & 0xff; | |
245 | ac >>= 8; | |
246 | bits -= 8; | |
247 | } | |
248 | i++; | |
d5d0e8c7 | 249 | } |
5de0b4d0 TT |
250 | if (ac) |
251 | return -1; | |
252 | return cp - dst; | |
d5d0e8c7 MH |
253 | } |
254 | ||
d5d0e8c7 MH |
255 | /** |
256 | * ext4_fname_crypto_round_up() - | |
257 | * | |
258 | * Return: The next multiple of block size | |
259 | */ | |
260 | u32 ext4_fname_crypto_round_up(u32 size, u32 blksize) | |
261 | { | |
262 | return ((size+blksize-1)/blksize)*blksize; | |
263 | } | |
264 | ||
4d3c4e5b TT |
265 | unsigned ext4_fname_encrypted_size(struct inode *inode, u32 ilen) |
266 | { | |
267 | struct ext4_crypt_info *ci = EXT4_I(inode)->i_crypt_info; | |
268 | int padding = 32; | |
269 | ||
270 | if (ci) | |
271 | padding = 4 << (ci->ci_flags & EXT4_POLICY_FLAGS_PAD_MASK); | |
272 | if (ilen < EXT4_CRYPTO_BLOCK_SIZE) | |
273 | ilen = EXT4_CRYPTO_BLOCK_SIZE; | |
274 | return ext4_fname_crypto_round_up(ilen, padding); | |
275 | } | |
276 | ||
277 | /* | |
278 | * ext4_fname_crypto_alloc_buffer() - | |
d5d0e8c7 MH |
279 | * |
280 | * Allocates an output buffer that is sufficient for the crypto operation | |
281 | * specified by the context and the direction. | |
282 | */ | |
b7236e21 | 283 | int ext4_fname_crypto_alloc_buffer(struct inode *inode, |
d5d0e8c7 MH |
284 | u32 ilen, struct ext4_str *crypto_str) |
285 | { | |
4d3c4e5b | 286 | unsigned int olen = ext4_fname_encrypted_size(inode, ilen); |
d5d0e8c7 | 287 | |
d5d0e8c7 MH |
288 | crypto_str->len = olen; |
289 | if (olen < EXT4_FNAME_CRYPTO_DIGEST_SIZE*2) | |
290 | olen = EXT4_FNAME_CRYPTO_DIGEST_SIZE*2; | |
291 | /* Allocated buffer can hold one more character to null-terminate the | |
292 | * string */ | |
293 | crypto_str->name = kmalloc(olen+1, GFP_NOFS); | |
294 | if (!(crypto_str->name)) | |
295 | return -ENOMEM; | |
296 | return 0; | |
297 | } | |
298 | ||
299 | /** | |
300 | * ext4_fname_crypto_free_buffer() - | |
301 | * | |
302 | * Frees the buffer allocated for crypto operation. | |
303 | */ | |
304 | void ext4_fname_crypto_free_buffer(struct ext4_str *crypto_str) | |
305 | { | |
306 | if (!crypto_str) | |
307 | return; | |
308 | kfree(crypto_str->name); | |
309 | crypto_str->name = NULL; | |
310 | } | |
311 | ||
312 | /** | |
313 | * ext4_fname_disk_to_usr() - converts a filename from disk space to user space | |
314 | */ | |
b7236e21 | 315 | int _ext4_fname_disk_to_usr(struct inode *inode, |
5de0b4d0 TT |
316 | struct dx_hash_info *hinfo, |
317 | const struct ext4_str *iname, | |
318 | struct ext4_str *oname) | |
d5d0e8c7 | 319 | { |
5de0b4d0 TT |
320 | char buf[24]; |
321 | int ret; | |
322 | ||
d5d0e8c7 MH |
323 | if (iname->len < 3) { |
324 | /*Check for . and .. */ | |
325 | if (iname->name[0] == '.' && iname->name[iname->len-1] == '.') { | |
326 | oname->name[0] = '.'; | |
327 | oname->name[iname->len-1] = '.'; | |
328 | oname->len = iname->len; | |
329 | return oname->len; | |
330 | } | |
331 | } | |
b7236e21 TT |
332 | if (EXT4_I(inode)->i_crypt_info) |
333 | return ext4_fname_decrypt(inode, iname, oname); | |
5de0b4d0 TT |
334 | |
335 | if (iname->len <= EXT4_FNAME_CRYPTO_DIGEST_SIZE) { | |
336 | ret = digest_encode(iname->name, iname->len, oname->name); | |
337 | oname->len = ret; | |
338 | return ret; | |
339 | } | |
340 | if (hinfo) { | |
341 | memcpy(buf, &hinfo->hash, 4); | |
342 | memcpy(buf+4, &hinfo->minor_hash, 4); | |
343 | } else | |
344 | memset(buf, 0, 8); | |
345 | memcpy(buf + 8, iname->name + iname->len - 16, 16); | |
346 | oname->name[0] = '_'; | |
347 | ret = digest_encode(buf, 24, oname->name+1); | |
348 | oname->len = ret + 1; | |
349 | return ret + 1; | |
d5d0e8c7 MH |
350 | } |
351 | ||
b7236e21 | 352 | int ext4_fname_disk_to_usr(struct inode *inode, |
5de0b4d0 | 353 | struct dx_hash_info *hinfo, |
d5d0e8c7 MH |
354 | const struct ext4_dir_entry_2 *de, |
355 | struct ext4_str *oname) | |
356 | { | |
357 | struct ext4_str iname = {.name = (unsigned char *) de->name, | |
358 | .len = de->name_len }; | |
359 | ||
b7236e21 | 360 | return _ext4_fname_disk_to_usr(inode, hinfo, &iname, oname); |
d5d0e8c7 MH |
361 | } |
362 | ||
363 | ||
364 | /** | |
365 | * ext4_fname_usr_to_disk() - converts a filename from user space to disk space | |
366 | */ | |
b7236e21 | 367 | int ext4_fname_usr_to_disk(struct inode *inode, |
d5d0e8c7 MH |
368 | const struct qstr *iname, |
369 | struct ext4_str *oname) | |
370 | { | |
371 | int res; | |
b7236e21 | 372 | struct ext4_crypt_info *ci = EXT4_I(inode)->i_crypt_info; |
d5d0e8c7 | 373 | |
d5d0e8c7 MH |
374 | if (iname->len < 3) { |
375 | /*Check for . and .. */ | |
376 | if (iname->name[0] == '.' && | |
377 | iname->name[iname->len-1] == '.') { | |
378 | oname->name[0] = '.'; | |
379 | oname->name[iname->len-1] = '.'; | |
380 | oname->len = iname->len; | |
381 | return oname->len; | |
382 | } | |
383 | } | |
b7236e21 TT |
384 | if (ci) { |
385 | res = ext4_fname_encrypt(inode, iname, oname); | |
d5d0e8c7 MH |
386 | return res; |
387 | } | |
388 | /* Without a proper key, a user is not allowed to modify the filenames | |
389 | * in a directory. Consequently, a user space name cannot be mapped to | |
390 | * a disk-space name */ | |
391 | return -EACCES; | |
392 | } | |
393 | ||
5b643f9c TT |
394 | int ext4_fname_setup_filename(struct inode *dir, const struct qstr *iname, |
395 | int lookup, struct ext4_filename *fname) | |
d5d0e8c7 | 396 | { |
b7236e21 | 397 | struct ext4_crypt_info *ci; |
5b643f9c TT |
398 | int ret = 0, bigname = 0; |
399 | ||
400 | memset(fname, 0, sizeof(struct ext4_filename)); | |
401 | fname->usr_fname = iname; | |
d5d0e8c7 | 402 | |
b7236e21 | 403 | if (!ext4_encrypted_inode(dir) || |
d5d0e8c7 MH |
404 | ((iname->name[0] == '.') && |
405 | ((iname->len == 1) || | |
406 | ((iname->name[1] == '.') && (iname->len == 2))))) { | |
5b643f9c TT |
407 | fname->disk_name.name = (unsigned char *) iname->name; |
408 | fname->disk_name.len = iname->len; | |
82d0d3e7 | 409 | return 0; |
d5d0e8c7 | 410 | } |
c936e1ec | 411 | ret = ext4_get_encryption_info(dir); |
b7236e21 TT |
412 | if (ret) |
413 | return ret; | |
414 | ci = EXT4_I(dir)->i_crypt_info; | |
415 | if (ci) { | |
416 | ret = ext4_fname_crypto_alloc_buffer(dir, iname->len, | |
5b643f9c TT |
417 | &fname->crypto_buf); |
418 | if (ret < 0) | |
82d0d3e7 | 419 | return ret; |
b7236e21 | 420 | ret = ext4_fname_encrypt(dir, iname, &fname->crypto_buf); |
5b643f9c | 421 | if (ret < 0) |
82d0d3e7 | 422 | goto errout; |
5b643f9c TT |
423 | fname->disk_name.name = fname->crypto_buf.name; |
424 | fname->disk_name.len = fname->crypto_buf.len; | |
82d0d3e7 | 425 | return 0; |
5de0b4d0 | 426 | } |
82d0d3e7 TT |
427 | if (!lookup) |
428 | return -EACCES; | |
5de0b4d0 | 429 | |
5b643f9c TT |
430 | /* We don't have the key and we are doing a lookup; decode the |
431 | * user-supplied name | |
432 | */ | |
433 | if (iname->name[0] == '_') | |
434 | bigname = 1; | |
435 | if ((bigname && (iname->len != 33)) || | |
82d0d3e7 TT |
436 | (!bigname && (iname->len > 43))) |
437 | return -ENOENT; | |
438 | ||
5b643f9c | 439 | fname->crypto_buf.name = kmalloc(32, GFP_KERNEL); |
82d0d3e7 TT |
440 | if (fname->crypto_buf.name == NULL) |
441 | return -ENOMEM; | |
5b643f9c TT |
442 | ret = digest_decode(iname->name + bigname, iname->len - bigname, |
443 | fname->crypto_buf.name); | |
444 | if (ret < 0) { | |
445 | ret = -ENOENT; | |
82d0d3e7 | 446 | goto errout; |
5b643f9c TT |
447 | } |
448 | fname->crypto_buf.len = ret; | |
449 | if (bigname) { | |
450 | memcpy(&fname->hinfo.hash, fname->crypto_buf.name, 4); | |
451 | memcpy(&fname->hinfo.minor_hash, fname->crypto_buf.name + 4, 4); | |
452 | } else { | |
453 | fname->disk_name.name = fname->crypto_buf.name; | |
454 | fname->disk_name.len = fname->crypto_buf.len; | |
455 | } | |
82d0d3e7 TT |
456 | return 0; |
457 | errout: | |
458 | kfree(fname->crypto_buf.name); | |
459 | fname->crypto_buf.name = NULL; | |
d5d0e8c7 MH |
460 | return ret; |
461 | } | |
462 | ||
5b643f9c | 463 | void ext4_fname_free_filename(struct ext4_filename *fname) |
d5d0e8c7 | 464 | { |
5b643f9c TT |
465 | kfree(fname->crypto_buf.name); |
466 | fname->crypto_buf.name = NULL; | |
467 | fname->usr_fname = NULL; | |
468 | fname->disk_name.name = NULL; | |
d5d0e8c7 | 469 | } |