Blame view

fs/crypto/fname.c 12.2 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
2
  /*
0b81d0779   Jaegeuk Kim   fs crypto: move p...
3
   * This contains functions for filename crypto management
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
4
5
6
7
   *
   * Copyright (C) 2015, Google, Inc.
   * Copyright (C) 2015, Motorola Mobility
   *
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
8
   * Written by Uday Savagaonkar, 2014.
0b81d0779   Jaegeuk Kim   fs crypto: move p...
9
   * Modified by Jaegeuk Kim, 2015.
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
10
11
12
   *
   * This has not yet undergone a rigorous security audit.
   */
0b81d0779   Jaegeuk Kim   fs crypto: move p...
13

6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
14
  #include <linux/scatterlist.h>
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
15
  #include <linux/ratelimit.h>
3325bea5b   Theodore Ts'o   fscrypt: rename g...
16
  #include "fscrypt_private.h"
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
17

6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
18
  /**
53fd7550e   Eric Biggers   fscrypto: rename ...
19
20
21
   * fname_crypt_complete() - completion callback for filename crypto
   * @req: The asynchronous cipher request context
   * @res: The result of the cipher operation
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
22
   */
53fd7550e   Eric Biggers   fscrypto: rename ...
23
  static void fname_crypt_complete(struct crypto_async_request *req, int res)
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
24
  {
0b81d0779   Jaegeuk Kim   fs crypto: move p...
25
  	struct fscrypt_completion_result *ecr = req->data;
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
26
27
28
29
30
31
  
  	if (res == -EINPROGRESS)
  		return;
  	ecr->res = res;
  	complete(&ecr->completion);
  }
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
32
  /**
ef1eb3aa5   Eric Biggers   fscrypto: make fi...
33
   * fname_encrypt() - encrypt a filename
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
34
   *
ef1eb3aa5   Eric Biggers   fscrypto: make fi...
35
36
37
   * The caller must have allocated sufficient memory for the @oname string.
   *
   * Return: 0 on success, -errno on failure
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
38
   */
0b81d0779   Jaegeuk Kim   fs crypto: move p...
39
40
  static int fname_encrypt(struct inode *inode,
  			const struct qstr *iname, struct fscrypt_str *oname)
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
41
  {
2731a944f   Herbert Xu   f2fs: Use skcipher
42
  	struct skcipher_request *req = NULL;
0b81d0779   Jaegeuk Kim   fs crypto: move p...
43
44
  	DECLARE_FS_COMPLETION_RESULT(ecr);
  	struct fscrypt_info *ci = inode->i_crypt_info;
2731a944f   Herbert Xu   f2fs: Use skcipher
45
  	struct crypto_skcipher *tfm = ci->ci_ctfm;
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
46
  	int res = 0;
0b81d0779   Jaegeuk Kim   fs crypto: move p...
47
  	char iv[FS_CRYPTO_BLOCK_SIZE];
08ae877f4   Eric Biggers   fscrypto: don't u...
48
  	struct scatterlist sg;
0b81d0779   Jaegeuk Kim   fs crypto: move p...
49
  	int padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK);
08ae877f4   Eric Biggers   fscrypto: don't u...
50
51
  	unsigned int lim;
  	unsigned int cryptlen;
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
52

0b81d0779   Jaegeuk Kim   fs crypto: move p...
53
  	lim = inode->i_sb->s_cop->max_namelen(inode);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
54
55
  	if (iname->len <= 0 || iname->len > lim)
  		return -EIO;
08ae877f4   Eric Biggers   fscrypto: don't u...
56
57
58
59
60
61
62
63
64
  	/*
  	 * 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);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
65

08ae877f4   Eric Biggers   fscrypto: don't u...
66
67
  	/* Initialize the IV */
  	memset(iv, 0, FS_CRYPTO_BLOCK_SIZE);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
68

08ae877f4   Eric Biggers   fscrypto: don't u...
69
  	/* Set up the encryption request */
2731a944f   Herbert Xu   f2fs: Use skcipher
70
  	req = skcipher_request_alloc(tfm, GFP_NOFS);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
71
72
  	if (!req) {
  		printk_ratelimited(KERN_ERR
08ae877f4   Eric Biggers   fscrypto: don't u...
73
74
  			"%s: skcipher_request_alloc() failed
  ", __func__);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
75
76
  		return -ENOMEM;
  	}
2731a944f   Herbert Xu   f2fs: Use skcipher
77
  	skcipher_request_set_callback(req,
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
78
  			CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
53fd7550e   Eric Biggers   fscrypto: rename ...
79
  			fname_crypt_complete, &ecr);
08ae877f4   Eric Biggers   fscrypto: don't u...
80
81
  	sg_init_one(&sg, oname->name, cryptlen);
  	skcipher_request_set_crypt(req, &sg, &sg, cryptlen, iv);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
82

08ae877f4   Eric Biggers   fscrypto: don't u...
83
  	/* Do the encryption */
2731a944f   Herbert Xu   f2fs: Use skcipher
84
  	res = crypto_skcipher_encrypt(req);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
85
  	if (res == -EINPROGRESS || res == -EBUSY) {
08ae877f4   Eric Biggers   fscrypto: don't u...
86
  		/* Request is being completed asynchronously; wait for it */
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
87
88
89
  		wait_for_completion(&ecr.completion);
  		res = ecr.res;
  	}
2731a944f   Herbert Xu   f2fs: Use skcipher
90
  	skcipher_request_free(req);
ef1eb3aa5   Eric Biggers   fscrypto: make fi...
91
  	if (res < 0) {
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
92
93
94
  		printk_ratelimited(KERN_ERR
  				"%s: Error (error code %d)
  ", __func__, res);
ef1eb3aa5   Eric Biggers   fscrypto: make fi...
95
96
  		return res;
  	}
0b81d0779   Jaegeuk Kim   fs crypto: move p...
97

08ae877f4   Eric Biggers   fscrypto: don't u...
98
  	oname->len = cryptlen;
ef1eb3aa5   Eric Biggers   fscrypto: make fi...
99
  	return 0;
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
100
  }
ef1eb3aa5   Eric Biggers   fscrypto: make fi...
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
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
107
   */
0b81d0779   Jaegeuk Kim   fs crypto: move p...
108
109
110
  static int fname_decrypt(struct inode *inode,
  				const struct fscrypt_str *iname,
  				struct fscrypt_str *oname)
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
111
  {
2731a944f   Herbert Xu   f2fs: Use skcipher
112
  	struct skcipher_request *req = NULL;
0b81d0779   Jaegeuk Kim   fs crypto: move p...
113
  	DECLARE_FS_COMPLETION_RESULT(ecr);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
114
  	struct scatterlist src_sg, dst_sg;
0b81d0779   Jaegeuk Kim   fs crypto: move p...
115
  	struct fscrypt_info *ci = inode->i_crypt_info;
2731a944f   Herbert Xu   f2fs: Use skcipher
116
  	struct crypto_skcipher *tfm = ci->ci_ctfm;
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
117
  	int res = 0;
0b81d0779   Jaegeuk Kim   fs crypto: move p...
118
119
  	char iv[FS_CRYPTO_BLOCK_SIZE];
  	unsigned lim;
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
120

0b81d0779   Jaegeuk Kim   fs crypto: move p...
121
  	lim = inode->i_sb->s_cop->max_namelen(inode);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
122
123
124
125
  	if (iname->len <= 0 || iname->len > lim)
  		return -EIO;
  
  	/* Allocate request */
2731a944f   Herbert Xu   f2fs: Use skcipher
126
  	req = skcipher_request_alloc(tfm, GFP_NOFS);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
127
128
129
130
131
132
  	if (!req) {
  		printk_ratelimited(KERN_ERR
  			"%s: crypto_request_alloc() failed
  ",  __func__);
  		return -ENOMEM;
  	}
2731a944f   Herbert Xu   f2fs: Use skcipher
133
  	skcipher_request_set_callback(req,
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
134
  		CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
53fd7550e   Eric Biggers   fscrypto: rename ...
135
  		fname_crypt_complete, &ecr);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
136
137
  
  	/* Initialize IV */
0b81d0779   Jaegeuk Kim   fs crypto: move p...
138
  	memset(iv, 0, FS_CRYPTO_BLOCK_SIZE);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
139
140
141
142
  
  	/* Create decryption request */
  	sg_init_one(&src_sg, iname->name, iname->len);
  	sg_init_one(&dst_sg, oname->name, oname->len);
2731a944f   Herbert Xu   f2fs: Use skcipher
143
144
  	skcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, iv);
  	res = crypto_skcipher_decrypt(req);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
145
  	if (res == -EINPROGRESS || res == -EBUSY) {
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
146
147
148
  		wait_for_completion(&ecr.completion);
  		res = ecr.res;
  	}
2731a944f   Herbert Xu   f2fs: Use skcipher
149
  	skcipher_request_free(req);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
150
151
  	if (res < 0) {
  		printk_ratelimited(KERN_ERR
0b81d0779   Jaegeuk Kim   fs crypto: move p...
152
153
  				"%s: Error (error code %d)
  ", __func__, res);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
154
155
156
157
  		return res;
  	}
  
  	oname->len = strnlen(oname->name, iname->len);
ef1eb3aa5   Eric Biggers   fscrypto: make fi...
158
  	return 0;
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
159
160
161
162
  }
  
  static const char *lookup_table =
  	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
17159420a   Eric Biggers   fscrypt: introduc...
163
  #define BASE64_CHARS(nbytes)	DIV_ROUND_UP((nbytes) * 4, 3)
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
164
  /**
0b81d0779   Jaegeuk Kim   fs crypto: move p...
165
   * digest_encode() -
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
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
212
   *
   * 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;
  }
0b93e1b94   David Gstir   fscrypt: Constify...
213
  u32 fscrypt_fname_encrypted_size(const struct inode *inode, u32 ilen)
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
214
  {
922ec355f   Chao Yu   f2fs crypto: avoi...
215
  	int padding = 32;
0b81d0779   Jaegeuk Kim   fs crypto: move p...
216
  	struct fscrypt_info *ci = inode->i_crypt_info;
922ec355f   Chao Yu   f2fs crypto: avoi...
217
218
  
  	if (ci)
0b81d0779   Jaegeuk Kim   fs crypto: move p...
219
  		padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK);
55be3145d   Eric Biggers   fscrypto: use sta...
220
221
  	ilen = max(ilen, (u32)FS_CRYPTO_BLOCK_SIZE);
  	return round_up(ilen, padding);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
222
  }
0b81d0779   Jaegeuk Kim   fs crypto: move p...
223
  EXPORT_SYMBOL(fscrypt_fname_encrypted_size);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
224
225
  
  /**
0b81d0779   Jaegeuk Kim   fs crypto: move p...
226
   * fscrypt_fname_crypto_alloc_obuff() -
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
227
228
229
230
   *
   * Allocates an output buffer that is sufficient for the crypto operation
   * specified by the context and the direction.
   */
0b93e1b94   David Gstir   fscrypt: Constify...
231
  int fscrypt_fname_alloc_buffer(const struct inode *inode,
0b81d0779   Jaegeuk Kim   fs crypto: move p...
232
  				u32 ilen, struct fscrypt_str *crypto_str)
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
233
  {
17159420a   Eric Biggers   fscrypt: introduc...
234
235
236
237
  	u32 olen = fscrypt_fname_encrypted_size(inode, ilen);
  	const u32 max_encoded_len =
  		max_t(u32, BASE64_CHARS(FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE),
  		      1 + BASE64_CHARS(sizeof(struct fscrypt_digested_name)));
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
238

6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
239
  	crypto_str->len = olen;
17159420a   Eric Biggers   fscrypt: introduc...
240
  	olen = max(olen, max_encoded_len);
0b81d0779   Jaegeuk Kim   fs crypto: move p...
241
242
243
244
  	/*
  	 * Allocated buffer can hold one more character to null-terminate the
  	 * string
  	 */
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
245
246
247
248
249
  	crypto_str->name = kmalloc(olen + 1, GFP_NOFS);
  	if (!(crypto_str->name))
  		return -ENOMEM;
  	return 0;
  }
0b81d0779   Jaegeuk Kim   fs crypto: move p...
250
  EXPORT_SYMBOL(fscrypt_fname_alloc_buffer);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
251
252
  
  /**
0b81d0779   Jaegeuk Kim   fs crypto: move p...
253
   * fscrypt_fname_crypto_free_buffer() -
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
254
255
256
   *
   * Frees the buffer allocated for crypto operation.
   */
0b81d0779   Jaegeuk Kim   fs crypto: move p...
257
  void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str)
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
258
259
260
261
262
263
  {
  	if (!crypto_str)
  		return;
  	kfree(crypto_str->name);
  	crypto_str->name = NULL;
  }
0b81d0779   Jaegeuk Kim   fs crypto: move p...
264
  EXPORT_SYMBOL(fscrypt_fname_free_buffer);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
265
266
  
  /**
0b81d0779   Jaegeuk Kim   fs crypto: move p...
267
268
   * fscrypt_fname_disk_to_usr() - converts a filename from disk space to user
   * space
ef1eb3aa5   Eric Biggers   fscrypto: make fi...
269
270
271
   *
   * The caller must have allocated sufficient memory for the @oname string.
   *
17159420a   Eric Biggers   fscrypt: introduc...
272
273
274
275
   * If the key is available, we'll decrypt the disk name; otherwise, we'll encode
   * it for presentation.  Short names are directly base64-encoded, while long
   * names are encoded in fscrypt_digested_name format.
   *
ef1eb3aa5   Eric Biggers   fscrypto: make fi...
276
   * Return: 0 on success, -errno on failure
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
277
   */
0b81d0779   Jaegeuk Kim   fs crypto: move p...
278
279
280
281
  int fscrypt_fname_disk_to_usr(struct inode *inode,
  			u32 hash, u32 minor_hash,
  			const struct fscrypt_str *iname,
  			struct fscrypt_str *oname)
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
282
283
  {
  	const struct qstr qname = FSTR_TO_QSTR(iname);
17159420a   Eric Biggers   fscrypt: introduc...
284
  	struct fscrypt_digested_name digested_name;
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
285

0b81d0779   Jaegeuk Kim   fs crypto: move p...
286
  	if (fscrypt_is_dot_dotdot(&qname)) {
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
287
288
289
  		oname->name[0] = '.';
  		oname->name[iname->len - 1] = '.';
  		oname->len = iname->len;
ef1eb3aa5   Eric Biggers   fscrypto: make fi...
290
  		return 0;
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
291
  	}
0b81d0779   Jaegeuk Kim   fs crypto: move p...
292
  	if (iname->len < FS_CRYPTO_BLOCK_SIZE)
1dafa51d4   Jaegeuk Kim   f2fs crypto: chec...
293
  		return -EUCLEAN;
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
294

0b81d0779   Jaegeuk Kim   fs crypto: move p...
295
296
  	if (inode->i_crypt_info)
  		return fname_decrypt(inode, iname, oname);
17159420a   Eric Biggers   fscrypt: introduc...
297
  	if (iname->len <= FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE) {
ef1eb3aa5   Eric Biggers   fscrypto: make fi...
298
299
300
  		oname->len = digest_encode(iname->name, iname->len,
  					   oname->name);
  		return 0;
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
301
302
  	}
  	if (hash) {
17159420a   Eric Biggers   fscrypt: introduc...
303
304
  		digested_name.hash = hash;
  		digested_name.minor_hash = minor_hash;
0b81d0779   Jaegeuk Kim   fs crypto: move p...
305
  	} else {
17159420a   Eric Biggers   fscrypt: introduc...
306
307
  		digested_name.hash = 0;
  		digested_name.minor_hash = 0;
0b81d0779   Jaegeuk Kim   fs crypto: move p...
308
  	}
17159420a   Eric Biggers   fscrypt: introduc...
309
310
311
  	memcpy(digested_name.digest,
  	       FSCRYPT_FNAME_DIGEST(iname->name, iname->len),
  	       FSCRYPT_FNAME_DIGEST_SIZE);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
312
  	oname->name[0] = '_';
17159420a   Eric Biggers   fscrypt: introduc...
313
314
  	oname->len = 1 + digest_encode((const char *)&digested_name,
  				       sizeof(digested_name), oname->name + 1);
ef1eb3aa5   Eric Biggers   fscrypto: make fi...
315
  	return 0;
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
316
  }
0b81d0779   Jaegeuk Kim   fs crypto: move p...
317
  EXPORT_SYMBOL(fscrypt_fname_disk_to_usr);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
318
319
  
  /**
0b81d0779   Jaegeuk Kim   fs crypto: move p...
320
321
   * fscrypt_fname_usr_to_disk() - converts a filename from user space to disk
   * space
ef1eb3aa5   Eric Biggers   fscrypto: make fi...
322
323
324
325
   *
   * The caller must have allocated sufficient memory for the @oname string.
   *
   * Return: 0 on success, -errno on failure
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
326
   */
0b81d0779   Jaegeuk Kim   fs crypto: move p...
327
  int fscrypt_fname_usr_to_disk(struct inode *inode,
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
328
  			const struct qstr *iname,
0b81d0779   Jaegeuk Kim   fs crypto: move p...
329
  			struct fscrypt_str *oname)
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
330
  {
0b81d0779   Jaegeuk Kim   fs crypto: move p...
331
  	if (fscrypt_is_dot_dotdot(iname)) {
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
332
333
334
  		oname->name[0] = '.';
  		oname->name[iname->len - 1] = '.';
  		oname->len = iname->len;
ef1eb3aa5   Eric Biggers   fscrypto: make fi...
335
  		return 0;
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
336
  	}
0b81d0779   Jaegeuk Kim   fs crypto: move p...
337
338
339
340
  	if (inode->i_crypt_info)
  		return fname_encrypt(inode, iname, oname);
  	/*
  	 * Without a proper key, a user is not allowed to modify the filenames
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
341
  	 * in a directory. Consequently, a user space name cannot be mapped to
0b81d0779   Jaegeuk Kim   fs crypto: move p...
342
343
  	 * a disk-space name
  	 */
54475f531   Eric Biggers   fscrypt: use ENOK...
344
  	return -ENOKEY;
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
345
  }
0b81d0779   Jaegeuk Kim   fs crypto: move p...
346
  EXPORT_SYMBOL(fscrypt_fname_usr_to_disk);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
347

17159420a   Eric Biggers   fscrypt: introduc...
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
  /**
   * fscrypt_setup_filename() - prepare to search a possibly encrypted directory
   * @dir: the directory that will be searched
   * @iname: the user-provided filename being searched for
   * @lookup: 1 if we're allowed to proceed without the key because it's
   *	->lookup() or we're finding the dir_entry for deletion; 0 if we cannot
   *	proceed without the key because we're going to create the dir_entry.
   * @fname: the filename information to be filled in
   *
   * Given a user-provided filename @iname, this function sets @fname->disk_name
   * to the name that would be stored in the on-disk directory entry, if possible.
   * If the directory is unencrypted this is simply @iname.  Else, if we have the
   * directory's encryption key, then @iname is the plaintext, so we encrypt it to
   * get the disk_name.
   *
   * Else, for keyless @lookup operations, @iname is the presented ciphertext, so
   * we decode it to get either the ciphertext disk_name (for short names) or the
   * fscrypt_digested_name (for long names).  Non-@lookup operations will be
   * impossible in this case, so we fail them with ENOKEY.
   *
   * If successful, fscrypt_free_filename() must be called later to clean up.
   *
   * Return: 0 on success, -errno on failure
   */
0b81d0779   Jaegeuk Kim   fs crypto: move p...
372
373
  int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname,
  			      int lookup, struct fscrypt_name *fname)
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
374
  {
17159420a   Eric Biggers   fscrypt: introduc...
375
376
  	int ret;
  	int digested;
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
377

0b81d0779   Jaegeuk Kim   fs crypto: move p...
378
  	memset(fname, 0, sizeof(struct fscrypt_name));
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
379
  	fname->usr_fname = iname;
0b81d0779   Jaegeuk Kim   fs crypto: move p...
380
381
  	if (!dir->i_sb->s_cop->is_encrypted(dir) ||
  				fscrypt_is_dot_dotdot(iname)) {
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
382
383
  		fname->disk_name.name = (unsigned char *)iname->name;
  		fname->disk_name.len = iname->len;
7bf4b5576   Chao Yu   f2fs crypto: fix ...
384
  		return 0;
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
385
  	}
1b53cf981   Eric Biggers   fscrypt: remove b...
386
  	ret = fscrypt_get_encryption_info(dir);
0b81d0779   Jaegeuk Kim   fs crypto: move p...
387
  	if (ret && ret != -EOPNOTSUPP)
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
388
  		return ret;
0b81d0779   Jaegeuk Kim   fs crypto: move p...
389
390
391
392
  
  	if (dir->i_crypt_info) {
  		ret = fscrypt_fname_alloc_buffer(dir, iname->len,
  							&fname->crypto_buf);
ef1eb3aa5   Eric Biggers   fscrypto: make fi...
393
  		if (ret)
7bf4b5576   Chao Yu   f2fs crypto: fix ...
394
  			return ret;
0b81d0779   Jaegeuk Kim   fs crypto: move p...
395
  		ret = fname_encrypt(dir, iname, &fname->crypto_buf);
ef1eb3aa5   Eric Biggers   fscrypto: make fi...
396
  		if (ret)
e5e0906b6   Jaegeuk Kim   f2fs crypto: clea...
397
  			goto errout;
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
398
399
  		fname->disk_name.name = fname->crypto_buf.name;
  		fname->disk_name.len = fname->crypto_buf.len;
7bf4b5576   Chao Yu   f2fs crypto: fix ...
400
  		return 0;
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
401
  	}
e5e0906b6   Jaegeuk Kim   f2fs crypto: clea...
402
  	if (!lookup)
54475f531   Eric Biggers   fscrypt: use ENOK...
403
  		return -ENOKEY;
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
404

0b81d0779   Jaegeuk Kim   fs crypto: move p...
405
406
  	/*
  	 * We don't have the key and we are doing a lookup; decode the
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
407
408
  	 * user-supplied name
  	 */
17159420a   Eric Biggers   fscrypt: introduc...
409
410
411
412
413
414
415
416
417
418
419
  	if (iname->name[0] == '_') {
  		if (iname->len !=
  		    1 + BASE64_CHARS(sizeof(struct fscrypt_digested_name)))
  			return -ENOENT;
  		digested = 1;
  	} else {
  		if (iname->len >
  		    BASE64_CHARS(FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE))
  			return -ENOENT;
  		digested = 0;
  	}
e5e0906b6   Jaegeuk Kim   f2fs crypto: clea...
420

17159420a   Eric Biggers   fscrypt: introduc...
421
422
423
424
  	fname->crypto_buf.name =
  		kmalloc(max_t(size_t, FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE,
  			      sizeof(struct fscrypt_digested_name)),
  			GFP_KERNEL);
e5e0906b6   Jaegeuk Kim   f2fs crypto: clea...
425
426
  	if (fname->crypto_buf.name == NULL)
  		return -ENOMEM;
0b81d0779   Jaegeuk Kim   fs crypto: move p...
427

17159420a   Eric Biggers   fscrypt: introduc...
428
  	ret = digest_decode(iname->name + digested, iname->len - digested,
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
429
430
431
  				fname->crypto_buf.name);
  	if (ret < 0) {
  		ret = -ENOENT;
e5e0906b6   Jaegeuk Kim   f2fs crypto: clea...
432
  		goto errout;
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
433
434
  	}
  	fname->crypto_buf.len = ret;
17159420a   Eric Biggers   fscrypt: introduc...
435
436
437
438
439
  	if (digested) {
  		const struct fscrypt_digested_name *n =
  			(const void *)fname->crypto_buf.name;
  		fname->hash = n->hash;
  		fname->minor_hash = n->minor_hash;
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
440
441
442
443
  	} else {
  		fname->disk_name.name = fname->crypto_buf.name;
  		fname->disk_name.len = fname->crypto_buf.len;
  	}
7bf4b5576   Chao Yu   f2fs crypto: fix ...
444
  	return 0;
0b81d0779   Jaegeuk Kim   fs crypto: move p...
445

e5e0906b6   Jaegeuk Kim   f2fs crypto: clea...
446
  errout:
0b81d0779   Jaegeuk Kim   fs crypto: move p...
447
  	fscrypt_fname_free_buffer(&fname->crypto_buf);
6b3bd08f9   Jaegeuk Kim   f2fs crypto: file...
448
449
  	return ret;
  }
0b81d0779   Jaegeuk Kim   fs crypto: move p...
450
  EXPORT_SYMBOL(fscrypt_setup_filename);