Blame view
fs/crypto/fname.c
18.5 KB
b24413180 License cleanup: ... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
6b3bd08f9 f2fs crypto: file... |
2 |
/* |
0b81d0779 fs crypto: move p... |
3 |
* This contains functions for filename crypto management |
6b3bd08f9 f2fs crypto: file... |
4 5 6 7 |
* * Copyright (C) 2015, Google, Inc. * Copyright (C) 2015, Motorola Mobility * |
6b3bd08f9 f2fs crypto: file... |
8 |
* Written by Uday Savagaonkar, 2014. |
0b81d0779 fs crypto: move p... |
9 |
* Modified by Jaegeuk Kim, 2015. |
6b3bd08f9 f2fs crypto: file... |
10 11 12 |
* * This has not yet undergone a rigorous security audit. */ |
0b81d0779 fs crypto: move p... |
13 |
|
2ebdef6d8 fscrypt: move fsc... |
14 |
#include <linux/namei.h> |
6b3bd08f9 f2fs crypto: file... |
15 |
#include <linux/scatterlist.h> |
edc440e3d fscrypt: improve ... |
16 17 |
#include <crypto/hash.h> #include <crypto/sha.h> |
a575784c6 fscrypt: trim dow... |
18 |
#include <crypto/skcipher.h> |
3325bea5b fscrypt: rename g... |
19 |
#include "fscrypt_private.h" |
6b3bd08f9 f2fs crypto: file... |
20 |
|
d2fe97545 fscrypt: fix all ... |
21 |
/* |
edc440e3d fscrypt: improve ... |
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
* struct fscrypt_nokey_name - identifier for directory entry when key is absent * * When userspace lists an encrypted directory without access to the key, the * filesystem must present a unique "no-key name" for each filename that allows * it to find the directory entry again if requested. Naively, that would just * mean using the ciphertext filenames. However, since the ciphertext filenames * can contain illegal characters ('\0' and '/'), they must be encoded in some * way. We use base64. But that can cause names to exceed NAME_MAX (255 * bytes), so we also need to use a strong hash to abbreviate long names. * * The filesystem may also need another kind of hash, the "dirhash", to quickly * find the directory entry. Since filesystems normally compute the dirhash * over the on-disk filename (i.e. the ciphertext), it's not computable from * no-key names that abbreviate the ciphertext using the strong hash to fit in * NAME_MAX. It's also not computable if it's a keyed hash taken over the * plaintext (but it may still be available in the on-disk directory entry); * casefolded directories use this type of dirhash. At least in these cases, * each no-key name must include the name's dirhash too. * * To meet all these requirements, we base64-encode the following * variable-length structure. It contains the dirhash, or 0's if the filesystem * didn't provide one; up to 149 bytes of the ciphertext name; and for * ciphertexts longer than 149 bytes, also the SHA-256 of the remaining bytes. * * This ensures that each no-key name contains everything needed to find the * directory entry again, contains only legal characters, doesn't exceed * NAME_MAX, is unambiguous unless there's a SHA-256 collision, and that we only * take the performance hit of SHA-256 on very long filenames (which are rare). */ struct fscrypt_nokey_name { u32 dirhash[2]; u8 bytes[149]; u8 sha256[SHA256_DIGEST_SIZE]; }; /* 189 bytes => 252 bytes base64-encoded, which is <= NAME_MAX (255) */ /* * Decoded size of max-size nokey name, i.e. a name that was abbreviated using * the strong hash and thus includes the 'sha256' field. This isn't simply * sizeof(struct fscrypt_nokey_name), as the padding at the end isn't included. */ #define FSCRYPT_NOKEY_NAME_MAX offsetofend(struct fscrypt_nokey_name, sha256) |
dcf0db9e5 fscrypt: move fsc... |
63 64 65 66 67 68 69 70 71 72 |
static inline bool fscrypt_is_dot_dotdot(const struct qstr *str) { if (str->len == 1 && str->name[0] == '.') return true; if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.') return true; return false; } |
6b3bd08f9 f2fs crypto: file... |
73 |
/** |
1b3b827ee fscrypt: add "fsc... |
74 |
* fscrypt_fname_encrypt() - encrypt a filename |
d2fe97545 fscrypt: fix all ... |
75 76 77 78 79 80 |
* @inode: inode of the parent directory (for regular filenames) * or of the symlink (for symlink targets) * @iname: the filename to encrypt * @out: (output) the encrypted filename * @olen: size of the encrypted filename. It must be at least @iname->len. * Any extra space is filled with NUL padding before encryption. |
ef1eb3aa5 fscrypto: make fi... |
81 82 |
* * Return: 0 on success, -errno on failure |
6b3bd08f9 f2fs crypto: file... |
83 |
*/ |
1b3b827ee fscrypt: add "fsc... |
84 85 |
int fscrypt_fname_encrypt(const struct inode *inode, const struct qstr *iname, u8 *out, unsigned int olen) |
6b3bd08f9 f2fs crypto: file... |
86 |
{ |
2731a944f f2fs: Use skcipher |
87 |
struct skcipher_request *req = NULL; |
d0082e1a7 fscrypt: move to ... |
88 |
DECLARE_CRYPTO_WAIT(wait); |
8a4ab0b86 fscrypt: constify... |
89 |
const struct fscrypt_info *ci = inode->i_crypt_info; |
5fee36095 fscrypt: add inli... |
90 |
struct crypto_skcipher *tfm = ci->ci_enc_key.tfm; |
8094c3ceb fscrypt: add Adia... |
91 |
union fscrypt_iv iv; |
08ae877f4 fscrypto: don't u... |
92 |
struct scatterlist sg; |
8094c3ceb fscrypt: add Adia... |
93 |
int res; |
6b3bd08f9 f2fs crypto: file... |
94 |
|
08ae877f4 fscrypto: don't u... |
95 96 97 98 |
/* * Copy the filename to the output buffer for encrypting in-place and * pad it with the needed number of NUL bytes. */ |
50c961de5 fscrypt: calculat... |
99 |
if (WARN_ON(olen < iname->len)) |
76e81d6d5 fscrypt: new help... |
100 |
return -ENOBUFS; |
50c961de5 fscrypt: calculat... |
101 102 |
memcpy(out, iname->name, iname->len); memset(out + iname->len, 0, olen - iname->len); |
6b3bd08f9 f2fs crypto: file... |
103 |
|
08ae877f4 fscrypto: don't u... |
104 |
/* Initialize the IV */ |
8094c3ceb fscrypt: add Adia... |
105 |
fscrypt_generate_iv(&iv, 0, ci); |
6b3bd08f9 f2fs crypto: file... |
106 |
|
08ae877f4 fscrypto: don't u... |
107 |
/* Set up the encryption request */ |
2731a944f f2fs: Use skcipher |
108 |
req = skcipher_request_alloc(tfm, GFP_NOFS); |
c90fd7756 fscrypt: remove e... |
109 |
if (!req) |
6b3bd08f9 f2fs crypto: file... |
110 |
return -ENOMEM; |
2731a944f f2fs: Use skcipher |
111 |
skcipher_request_set_callback(req, |
6b3bd08f9 f2fs crypto: file... |
112 |
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, |
d0082e1a7 fscrypt: move to ... |
113 |
crypto_req_done, &wait); |
50c961de5 fscrypt: calculat... |
114 |
sg_init_one(&sg, out, olen); |
8094c3ceb fscrypt: add Adia... |
115 |
skcipher_request_set_crypt(req, &sg, &sg, olen, &iv); |
6b3bd08f9 f2fs crypto: file... |
116 |
|
08ae877f4 fscrypto: don't u... |
117 |
/* Do the encryption */ |
d0082e1a7 fscrypt: move to ... |
118 |
res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait); |
2731a944f f2fs: Use skcipher |
119 |
skcipher_request_free(req); |
ef1eb3aa5 fscrypto: make fi... |
120 |
if (res < 0) { |
886da8b39 fscrypt: make fsc... |
121 |
fscrypt_err(inode, "Filename encryption failed: %d", res); |
ef1eb3aa5 fscrypto: make fi... |
122 123 |
return res; } |
0b81d0779 fs crypto: move p... |
124 |
|
ef1eb3aa5 fscrypto: make fi... |
125 |
return 0; |
6b3bd08f9 f2fs crypto: file... |
126 |
} |
ef1eb3aa5 fscrypto: make fi... |
127 128 |
/** * fname_decrypt() - decrypt a filename |
d2fe97545 fscrypt: fix all ... |
129 130 131 132 133 |
* @inode: inode of the parent directory (for regular filenames) * or of the symlink (for symlink targets) * @iname: the encrypted filename to decrypt * @oname: (output) the decrypted filename. The caller must have allocated * enough space for this, e.g. using fscrypt_fname_alloc_buffer(). |
ef1eb3aa5 fscrypto: make fi... |
134 135 |
* * Return: 0 on success, -errno on failure |
6b3bd08f9 f2fs crypto: file... |
136 |
*/ |
8a4ab0b86 fscrypt: constify... |
137 138 139 |
static int fname_decrypt(const struct inode *inode, const struct fscrypt_str *iname, struct fscrypt_str *oname) |
6b3bd08f9 f2fs crypto: file... |
140 |
{ |
2731a944f f2fs: Use skcipher |
141 |
struct skcipher_request *req = NULL; |
d0082e1a7 fscrypt: move to ... |
142 |
DECLARE_CRYPTO_WAIT(wait); |
6b3bd08f9 f2fs crypto: file... |
143 |
struct scatterlist src_sg, dst_sg; |
8a4ab0b86 fscrypt: constify... |
144 |
const struct fscrypt_info *ci = inode->i_crypt_info; |
5fee36095 fscrypt: add inli... |
145 |
struct crypto_skcipher *tfm = ci->ci_enc_key.tfm; |
8094c3ceb fscrypt: add Adia... |
146 147 |
union fscrypt_iv iv; int res; |
6b3bd08f9 f2fs crypto: file... |
148 |
|
6b3bd08f9 f2fs crypto: file... |
149 |
/* Allocate request */ |
2731a944f f2fs: Use skcipher |
150 |
req = skcipher_request_alloc(tfm, GFP_NOFS); |
c90fd7756 fscrypt: remove e... |
151 |
if (!req) |
6b3bd08f9 f2fs crypto: file... |
152 |
return -ENOMEM; |
2731a944f f2fs: Use skcipher |
153 |
skcipher_request_set_callback(req, |
6b3bd08f9 f2fs crypto: file... |
154 |
CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, |
d0082e1a7 fscrypt: move to ... |
155 |
crypto_req_done, &wait); |
6b3bd08f9 f2fs crypto: file... |
156 157 |
/* Initialize IV */ |
8094c3ceb fscrypt: add Adia... |
158 |
fscrypt_generate_iv(&iv, 0, ci); |
6b3bd08f9 f2fs crypto: file... |
159 160 161 162 |
/* Create decryption request */ sg_init_one(&src_sg, iname->name, iname->len); sg_init_one(&dst_sg, oname->name, oname->len); |
8094c3ceb fscrypt: add Adia... |
163 |
skcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, &iv); |
d0082e1a7 fscrypt: move to ... |
164 |
res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait); |
2731a944f f2fs: Use skcipher |
165 |
skcipher_request_free(req); |
6b3bd08f9 f2fs crypto: file... |
166 |
if (res < 0) { |
886da8b39 fscrypt: make fsc... |
167 |
fscrypt_err(inode, "Filename decryption failed: %d", res); |
6b3bd08f9 f2fs crypto: file... |
168 169 170 171 |
return res; } oname->len = strnlen(oname->name, iname->len); |
ef1eb3aa5 fscrypto: make fi... |
172 |
return 0; |
6b3bd08f9 f2fs crypto: file... |
173 |
} |
1c5100a2a fscrypt: clean up... |
174 |
static const char lookup_table[65] = |
6b3bd08f9 f2fs crypto: file... |
175 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; |
17159420a fscrypt: introduc... |
176 |
#define BASE64_CHARS(nbytes) DIV_ROUND_UP((nbytes) * 4, 3) |
6b3bd08f9 f2fs crypto: file... |
177 |
/** |
d2fe97545 fscrypt: fix all ... |
178 179 180 181 |
* base64_encode() - base64-encode some bytes * @src: the bytes to encode * @len: number of bytes to encode * @dst: (output) the base64-encoded string. Not NUL-terminated. |
6b3bd08f9 f2fs crypto: file... |
182 |
* |
1c5100a2a fscrypt: clean up... |
183 |
* Encodes the input string using characters from the set [A-Za-z0-9+,]. |
6b3bd08f9 f2fs crypto: file... |
184 |
* The encoded string is roughly 4/3 times the size of the input string. |
1c5100a2a fscrypt: clean up... |
185 186 |
* * Return: length of the encoded string |
6b3bd08f9 f2fs crypto: file... |
187 |
*/ |
1c5100a2a fscrypt: clean up... |
188 |
static int base64_encode(const u8 *src, int len, char *dst) |
6b3bd08f9 f2fs crypto: file... |
189 |
{ |
1c5100a2a fscrypt: clean up... |
190 |
int i, bits = 0, ac = 0; |
6b3bd08f9 f2fs crypto: file... |
191 |
char *cp = dst; |
1c5100a2a fscrypt: clean up... |
192 193 |
for (i = 0; i < len; i++) { ac += src[i] << bits; |
6b3bd08f9 f2fs crypto: file... |
194 195 196 197 198 199 |
bits += 8; do { *cp++ = lookup_table[ac & 0x3f]; ac >>= 6; bits -= 6; } while (bits >= 6); |
6b3bd08f9 f2fs crypto: file... |
200 201 202 203 204 |
} if (bits) *cp++ = lookup_table[ac & 0x3f]; return cp - dst; } |
1c5100a2a fscrypt: clean up... |
205 |
static int base64_decode(const char *src, int len, u8 *dst) |
6b3bd08f9 f2fs crypto: file... |
206 |
{ |
1c5100a2a fscrypt: clean up... |
207 |
int i, bits = 0, ac = 0; |
6b3bd08f9 f2fs crypto: file... |
208 |
const char *p; |
1c5100a2a fscrypt: clean up... |
209 |
u8 *cp = dst; |
6b3bd08f9 f2fs crypto: file... |
210 |
|
1c5100a2a fscrypt: clean up... |
211 |
for (i = 0; i < len; i++) { |
6b3bd08f9 f2fs crypto: file... |
212 213 214 215 216 217 218 219 220 221 |
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; } |
6b3bd08f9 f2fs crypto: file... |
222 223 224 225 226 |
} if (ac) return -1; return cp - dst; } |
ac4acb1f4 fscrypt: handle t... |
227 228 229 |
bool fscrypt_fname_encrypted_size(const union fscrypt_policy *policy, u32 orig_len, u32 max_len, u32 *encrypted_len_ret) |
6b3bd08f9 f2fs crypto: file... |
230 |
{ |
ac4acb1f4 fscrypt: handle t... |
231 |
int padding = 4 << (fscrypt_policy_flags(policy) & |
3b6df59bc fscrypt: use FSCR... |
232 |
FSCRYPT_POLICY_FLAGS_PAD_MASK); |
b9db0b4a6 fscrypt: fix up f... |
233 234 235 236 237 238 239 240 |
u32 encrypted_len; if (orig_len > max_len) return false; encrypted_len = max(orig_len, (u32)FS_CRYPTO_BLOCK_SIZE); encrypted_len = round_up(encrypted_len, padding); *encrypted_len_ret = min(encrypted_len, max_len); return true; |
6b3bd08f9 f2fs crypto: file... |
241 242 243 |
} /** |
d2fe97545 fscrypt: fix all ... |
244 |
* fscrypt_fname_alloc_buffer() - allocate a buffer for presented filenames |
d2fe97545 fscrypt: fix all ... |
245 246 247 |
* @max_encrypted_len: maximum length of encrypted filenames the buffer will be * used to present * @crypto_str: (output) buffer to allocate |
6b3bd08f9 f2fs crypto: file... |
248 |
* |
2cbadadcf fscrypt: define f... |
249 250 251 252 |
* Allocate a buffer that is large enough to hold any decrypted or encoded * filename (null-terminated), for the given maximum encrypted filename length. * * Return: 0 on success, -errno on failure |
6b3bd08f9 f2fs crypto: file... |
253 |
*/ |
8b10fe689 fscrypt: drop unu... |
254 |
int fscrypt_fname_alloc_buffer(u32 max_encrypted_len, |
2cbadadcf fscrypt: define f... |
255 |
struct fscrypt_str *crypto_str) |
6b3bd08f9 f2fs crypto: file... |
256 |
{ |
edc440e3d fscrypt: improve ... |
257 |
const u32 max_encoded_len = BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX); |
2cbadadcf fscrypt: define f... |
258 |
u32 max_presented_len; |
6b3bd08f9 f2fs crypto: file... |
259 |
|
2cbadadcf fscrypt: define f... |
260 |
max_presented_len = max(max_encoded_len, max_encrypted_len); |
17159420a fscrypt: introduc... |
261 |
|
2cbadadcf fscrypt: define f... |
262 263 |
crypto_str->name = kmalloc(max_presented_len + 1, GFP_NOFS); if (!crypto_str->name) |
6b3bd08f9 f2fs crypto: file... |
264 |
return -ENOMEM; |
2cbadadcf fscrypt: define f... |
265 |
crypto_str->len = max_presented_len; |
6b3bd08f9 f2fs crypto: file... |
266 267 |
return 0; } |
0b81d0779 fs crypto: move p... |
268 |
EXPORT_SYMBOL(fscrypt_fname_alloc_buffer); |
6b3bd08f9 f2fs crypto: file... |
269 270 |
/** |
d2fe97545 fscrypt: fix all ... |
271 272 |
* fscrypt_fname_free_buffer() - free a buffer for presented filenames * @crypto_str: the buffer to free |
6b3bd08f9 f2fs crypto: file... |
273 |
* |
d2fe97545 fscrypt: fix all ... |
274 |
* Free a buffer that was allocated by fscrypt_fname_alloc_buffer(). |
6b3bd08f9 f2fs crypto: file... |
275 |
*/ |
0b81d0779 fs crypto: move p... |
276 |
void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str) |
6b3bd08f9 f2fs crypto: file... |
277 278 279 280 281 282 |
{ if (!crypto_str) return; kfree(crypto_str->name); crypto_str->name = NULL; } |
0b81d0779 fs crypto: move p... |
283 |
EXPORT_SYMBOL(fscrypt_fname_free_buffer); |
6b3bd08f9 f2fs crypto: file... |
284 285 |
/** |
d2fe97545 fscrypt: fix all ... |
286 287 288 289 290 291 292 293 294 295 296 297 298 |
* fscrypt_fname_disk_to_usr() - convert an encrypted filename to * user-presentable form * @inode: inode of the parent directory (for regular filenames) * or of the symlink (for symlink targets) * @hash: first part of the name's dirhash, if applicable. This only needs to * be provided if the filename is located in an indexed directory whose * encryption key may be unavailable. Not needed for symlink targets. * @minor_hash: second part of the name's dirhash, if applicable * @iname: encrypted filename to convert. May also be "." or "..", which * aren't actually encrypted. * @oname: output buffer for the user-presentable filename. The caller must * have allocated enough space for this, e.g. using * fscrypt_fname_alloc_buffer(). |
ef1eb3aa5 fscrypto: make fi... |
299 |
* |
edc440e3d fscrypt: improve ... |
300 301 302 |
* If the key is available, we'll decrypt the disk name. Otherwise, we'll * encode it for presentation in fscrypt_nokey_name format. * See struct fscrypt_nokey_name for details. |
17159420a fscrypt: introduc... |
303 |
* |
ef1eb3aa5 fscrypto: make fi... |
304 |
* Return: 0 on success, -errno on failure |
6b3bd08f9 f2fs crypto: file... |
305 |
*/ |
8a4ab0b86 fscrypt: constify... |
306 307 308 309 |
int fscrypt_fname_disk_to_usr(const struct inode *inode, u32 hash, u32 minor_hash, const struct fscrypt_str *iname, struct fscrypt_str *oname) |
6b3bd08f9 f2fs crypto: file... |
310 311 |
{ const struct qstr qname = FSTR_TO_QSTR(iname); |
edc440e3d fscrypt: improve ... |
312 313 |
struct fscrypt_nokey_name nokey_name; u32 size; /* size of the unencoded no-key name */ |
6b3bd08f9 f2fs crypto: file... |
314 |
|
0b81d0779 fs crypto: move p... |
315 |
if (fscrypt_is_dot_dotdot(&qname)) { |
6b3bd08f9 f2fs crypto: file... |
316 317 318 |
oname->name[0] = '.'; oname->name[iname->len - 1] = '.'; oname->len = iname->len; |
ef1eb3aa5 fscrypto: make fi... |
319 |
return 0; |
6b3bd08f9 f2fs crypto: file... |
320 |
} |
0b81d0779 fs crypto: move p... |
321 |
if (iname->len < FS_CRYPTO_BLOCK_SIZE) |
1dafa51d4 f2fs crypto: chec... |
322 |
return -EUCLEAN; |
6b3bd08f9 f2fs crypto: file... |
323 |
|
e37a784d8 fscrypt: use READ... |
324 |
if (fscrypt_has_encryption_key(inode)) |
0b81d0779 fs crypto: move p... |
325 |
return fname_decrypt(inode, iname, oname); |
edc440e3d fscrypt: improve ... |
326 327 328 329 330 331 332 333 334 |
/* * Sanity check that struct fscrypt_nokey_name doesn't have padding * between fields and that its encoded size never exceeds NAME_MAX. */ BUILD_BUG_ON(offsetofend(struct fscrypt_nokey_name, dirhash) != offsetof(struct fscrypt_nokey_name, bytes)); BUILD_BUG_ON(offsetofend(struct fscrypt_nokey_name, bytes) != offsetof(struct fscrypt_nokey_name, sha256)); BUILD_BUG_ON(BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX) > NAME_MAX); |
6b3bd08f9 f2fs crypto: file... |
335 |
if (hash) { |
edc440e3d fscrypt: improve ... |
336 337 |
nokey_name.dirhash[0] = hash; nokey_name.dirhash[1] = minor_hash; |
0b81d0779 fs crypto: move p... |
338 |
} else { |
edc440e3d fscrypt: improve ... |
339 340 |
nokey_name.dirhash[0] = 0; nokey_name.dirhash[1] = 0; |
0b81d0779 fs crypto: move p... |
341 |
} |
edc440e3d fscrypt: improve ... |
342 343 344 345 346 347 |
if (iname->len <= sizeof(nokey_name.bytes)) { memcpy(nokey_name.bytes, iname->name, iname->len); size = offsetof(struct fscrypt_nokey_name, bytes[iname->len]); } else { memcpy(nokey_name.bytes, iname->name, sizeof(nokey_name.bytes)); /* Compute strong hash of remaining part of name. */ |
0c6a113b2 fscrypt: use sha2... |
348 349 350 |
sha256(&iname->name[sizeof(nokey_name.bytes)], iname->len - sizeof(nokey_name.bytes), nokey_name.sha256); |
edc440e3d fscrypt: improve ... |
351 352 353 |
size = FSCRYPT_NOKEY_NAME_MAX; } oname->len = base64_encode((const u8 *)&nokey_name, size, oname->name); |
ef1eb3aa5 fscrypto: make fi... |
354 |
return 0; |
6b3bd08f9 f2fs crypto: file... |
355 |
} |
0b81d0779 fs crypto: move p... |
356 |
EXPORT_SYMBOL(fscrypt_fname_disk_to_usr); |
6b3bd08f9 f2fs crypto: file... |
357 358 |
/** |
17159420a fscrypt: introduc... |
359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
* 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. * |
70fb2612a fscrypt: don't ca... |
373 374 375 |
* Else, for keyless @lookup operations, @iname should be a no-key name, so we * decode it to get the struct fscrypt_nokey_name. Non-@lookup operations will * be impossible in this case, so we fail them with ENOKEY. |
17159420a fscrypt: introduc... |
376 377 378 379 380 |
* * If successful, fscrypt_free_filename() must be called later to clean up. * * Return: 0 on success, -errno on failure */ |
0b81d0779 fs crypto: move p... |
381 382 |
int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, int lookup, struct fscrypt_name *fname) |
6b3bd08f9 f2fs crypto: file... |
383 |
{ |
edc440e3d fscrypt: improve ... |
384 |
struct fscrypt_nokey_name *nokey_name; |
17159420a fscrypt: introduc... |
385 |
int ret; |
6b3bd08f9 f2fs crypto: file... |
386 |
|
0b81d0779 fs crypto: move p... |
387 |
memset(fname, 0, sizeof(struct fscrypt_name)); |
6b3bd08f9 f2fs crypto: file... |
388 |
fname->usr_fname = iname; |
e0428a266 fscrypt: switch f... |
389 |
if (!IS_ENCRYPTED(dir) || fscrypt_is_dot_dotdot(iname)) { |
6b3bd08f9 f2fs crypto: file... |
390 391 |
fname->disk_name.name = (unsigned char *)iname->name; fname->disk_name.len = iname->len; |
7bf4b5576 f2fs crypto: fix ... |
392 |
return 0; |
6b3bd08f9 f2fs crypto: file... |
393 |
} |
1b53cf981 fscrypt: remove b... |
394 |
ret = fscrypt_get_encryption_info(dir); |
17bfde609 fscrypt: don't sp... |
395 |
if (ret) |
6b3bd08f9 f2fs crypto: file... |
396 |
return ret; |
0b81d0779 fs crypto: move p... |
397 |
|
e37a784d8 fscrypt: use READ... |
398 |
if (fscrypt_has_encryption_key(dir)) { |
ac4acb1f4 fscrypt: handle t... |
399 400 |
if (!fscrypt_fname_encrypted_size(&dir->i_crypt_info->ci_policy, iname->len, |
e12ee6836 fscrypt: make fsc... |
401 |
dir->i_sb->s_cop->max_namelen, |
b9db0b4a6 fscrypt: fix up f... |
402 |
&fname->crypto_buf.len)) |
50c961de5 fscrypt: calculat... |
403 |
return -ENAMETOOLONG; |
50c961de5 fscrypt: calculat... |
404 405 406 407 |
fname->crypto_buf.name = kmalloc(fname->crypto_buf.len, GFP_NOFS); if (!fname->crypto_buf.name) return -ENOMEM; |
1b3b827ee fscrypt: add "fsc... |
408 409 |
ret = fscrypt_fname_encrypt(dir, iname, fname->crypto_buf.name, fname->crypto_buf.len); |
ef1eb3aa5 fscrypto: make fi... |
410 |
if (ret) |
e5e0906b6 f2fs crypto: clea... |
411 |
goto errout; |
6b3bd08f9 f2fs crypto: file... |
412 413 |
fname->disk_name.name = fname->crypto_buf.name; fname->disk_name.len = fname->crypto_buf.len; |
7bf4b5576 f2fs crypto: fix ... |
414 |
return 0; |
6b3bd08f9 f2fs crypto: file... |
415 |
} |
e5e0906b6 f2fs crypto: clea... |
416 |
if (!lookup) |
54475f531 fscrypt: use ENOK... |
417 |
return -ENOKEY; |
70fb2612a fscrypt: don't ca... |
418 |
fname->is_nokey_name = true; |
6b3bd08f9 f2fs crypto: file... |
419 |
|
0b81d0779 fs crypto: move p... |
420 421 |
/* * We don't have the key and we are doing a lookup; decode the |
6b3bd08f9 f2fs crypto: file... |
422 423 |
* user-supplied name */ |
e5e0906b6 f2fs crypto: clea... |
424 |
|
edc440e3d fscrypt: improve ... |
425 426 427 428 |
if (iname->len > BASE64_CHARS(FSCRYPT_NOKEY_NAME_MAX)) return -ENOENT; fname->crypto_buf.name = kmalloc(FSCRYPT_NOKEY_NAME_MAX, GFP_KERNEL); |
e5e0906b6 f2fs crypto: clea... |
429 430 |
if (fname->crypto_buf.name == NULL) return -ENOMEM; |
0b81d0779 fs crypto: move p... |
431 |
|
edc440e3d fscrypt: improve ... |
432 433 434 435 |
ret = base64_decode(iname->name, iname->len, fname->crypto_buf.name); if (ret < (int)offsetof(struct fscrypt_nokey_name, bytes[1]) || (ret > offsetof(struct fscrypt_nokey_name, sha256) && ret != FSCRYPT_NOKEY_NAME_MAX)) { |
6b3bd08f9 f2fs crypto: file... |
436 |
ret = -ENOENT; |
e5e0906b6 f2fs crypto: clea... |
437 |
goto errout; |
6b3bd08f9 f2fs crypto: file... |
438 439 |
} fname->crypto_buf.len = ret; |
edc440e3d fscrypt: improve ... |
440 441 442 443 444 445 446 447 448 |
nokey_name = (void *)fname->crypto_buf.name; fname->hash = nokey_name->dirhash[0]; fname->minor_hash = nokey_name->dirhash[1]; if (ret != FSCRYPT_NOKEY_NAME_MAX) { /* The full ciphertext filename is available. */ fname->disk_name.name = nokey_name->bytes; fname->disk_name.len = ret - offsetof(struct fscrypt_nokey_name, bytes); |
6b3bd08f9 f2fs crypto: file... |
449 |
} |
7bf4b5576 f2fs crypto: fix ... |
450 |
return 0; |
0b81d0779 fs crypto: move p... |
451 |
|
e5e0906b6 f2fs crypto: clea... |
452 |
errout: |
50c961de5 fscrypt: calculat... |
453 |
kfree(fname->crypto_buf.name); |
6b3bd08f9 f2fs crypto: file... |
454 455 |
return ret; } |
0b81d0779 fs crypto: move p... |
456 |
EXPORT_SYMBOL(fscrypt_setup_filename); |
2ebdef6d8 fscrypt: move fsc... |
457 |
|
aa408f835 fscrypt: derive d... |
458 |
/** |
edc440e3d fscrypt: improve ... |
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 |
* fscrypt_match_name() - test whether the given name matches a directory entry * @fname: the name being searched for * @de_name: the name from the directory entry * @de_name_len: the length of @de_name in bytes * * Normally @fname->disk_name will be set, and in that case we simply compare * that to the name stored in the directory entry. The only exception is that * if we don't have the key for an encrypted directory and the name we're * looking for is very long, then we won't have the full disk_name and instead * we'll need to match against a fscrypt_nokey_name that includes a strong hash. * * Return: %true if the name matches, otherwise %false. */ bool fscrypt_match_name(const struct fscrypt_name *fname, const u8 *de_name, u32 de_name_len) { const struct fscrypt_nokey_name *nokey_name = (const void *)fname->crypto_buf.name; |
0c6a113b2 fscrypt: use sha2... |
477 |
u8 digest[SHA256_DIGEST_SIZE]; |
edc440e3d fscrypt: improve ... |
478 479 480 481 482 483 484 485 486 487 |
if (likely(fname->disk_name.name)) { if (de_name_len != fname->disk_name.len) return false; return !memcmp(de_name, fname->disk_name.name, de_name_len); } if (de_name_len <= sizeof(nokey_name->bytes)) return false; if (memcmp(de_name, nokey_name->bytes, sizeof(nokey_name->bytes))) return false; |
0c6a113b2 fscrypt: use sha2... |
488 489 490 |
sha256(&de_name[sizeof(nokey_name->bytes)], de_name_len - sizeof(nokey_name->bytes), digest); return !memcmp(digest, nokey_name->sha256, sizeof(digest)); |
edc440e3d fscrypt: improve ... |
491 492 493 494 |
} EXPORT_SYMBOL_GPL(fscrypt_match_name); /** |
aa408f835 fscrypt: derive d... |
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 |
* fscrypt_fname_siphash() - calculate the SipHash of a filename * @dir: the parent directory * @name: the filename to calculate the SipHash of * * Given a plaintext filename @name and a directory @dir which uses SipHash as * its dirhash method and has had its fscrypt key set up, this function * calculates the SipHash of that name using the directory's secret dirhash key. * * Return: the SipHash of @name using the hash key of @dir */ u64 fscrypt_fname_siphash(const struct inode *dir, const struct qstr *name) { const struct fscrypt_info *ci = dir->i_crypt_info; WARN_ON(!ci->ci_dirhash_key_initialized); return siphash(name->name, name->len, &ci->ci_dirhash_key); } EXPORT_SYMBOL_GPL(fscrypt_fname_siphash); |
2ebdef6d8 fscrypt: move fsc... |
514 515 516 517 |
/* * Validate dentries in encrypted directories to make sure we aren't potentially * caching stale dentries after a key has been added. */ |
5b2a828b9 fscrypt: export f... |
518 |
int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags) |
2ebdef6d8 fscrypt: move fsc... |
519 520 521 522 523 524 525 |
{ struct dentry *dir; int err; int valid; /* * Plaintext names are always valid, since fscrypt doesn't support |
70fb2612a fscrypt: don't ca... |
526 |
* reverting to no-key names without evicting the directory's inode |
2ebdef6d8 fscrypt: move fsc... |
527 528 |
* -- which implies eviction of the dentries in the directory. */ |
501e43fbe fscrypt: rename D... |
529 |
if (!(dentry->d_flags & DCACHE_NOKEY_NAME)) |
2ebdef6d8 fscrypt: move fsc... |
530 531 532 |
return 1; /* |
70fb2612a fscrypt: don't ca... |
533 |
* No-key name; valid if the directory's key is still unavailable. |
2ebdef6d8 fscrypt: move fsc... |
534 |
* |
70fb2612a fscrypt: don't ca... |
535 536 |
* Although fscrypt forbids rename() on no-key names, we still must use * dget_parent() here rather than use ->d_parent directly. That's |
2ebdef6d8 fscrypt: move fsc... |
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 |
* because a corrupted fs image may contain directory hard links, which * the VFS handles by moving the directory's dentry tree in the dcache * each time ->lookup() finds the directory and it already has a dentry * elsewhere. Thus ->d_parent can be changing, and we must safely grab * a reference to some ->d_parent to prevent it from being freed. */ if (flags & LOOKUP_RCU) return -ECHILD; dir = dget_parent(dentry); err = fscrypt_get_encryption_info(d_inode(dir)); valid = !fscrypt_has_encryption_key(d_inode(dir)); dput(dir); if (err < 0) return err; return valid; } |
5b2a828b9 fscrypt: export f... |
557 |
EXPORT_SYMBOL_GPL(fscrypt_d_revalidate); |
2ebdef6d8 fscrypt: move fsc... |
558 559 560 561 |
const struct dentry_operations fscrypt_d_ops = { .d_revalidate = fscrypt_d_revalidate, }; |