|  | // SPDX-License-Identifier: GPL-2.0 | 
|  | /* | 
|  | * This contains functions for filename crypto management | 
|  | * | 
|  | * Copyright (C) 2015, Google, Inc. | 
|  | * Copyright (C) 2015, Motorola Mobility | 
|  | * | 
|  | * Written by Uday Savagaonkar, 2014. | 
|  | * Modified by Jaegeuk Kim, 2015. | 
|  | * | 
|  | * This has not yet undergone a rigorous security audit. | 
|  | */ | 
|  |  | 
|  | #include <linux/scatterlist.h> | 
|  | #include <crypto/skcipher.h> | 
|  | #include "fscrypt_private.h" | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * fname_encrypt() - encrypt a filename | 
|  | * | 
|  | * The output buffer must be at least as large as the input buffer. | 
|  | * Any extra space is filled with NUL padding before encryption. | 
|  | * | 
|  | * Return: 0 on success, -errno on failure | 
|  | */ | 
|  | int fname_encrypt(struct inode *inode, const struct qstr *iname, | 
|  | u8 *out, unsigned int olen) | 
|  | { | 
|  | struct skcipher_request *req = NULL; | 
|  | DECLARE_CRYPTO_WAIT(wait); | 
|  | struct fscrypt_info *ci = inode->i_crypt_info; | 
|  | struct crypto_skcipher *tfm = ci->ci_key.tfm; | 
|  | union fscrypt_iv iv; | 
|  | struct scatterlist sg; | 
|  | int res; | 
|  |  | 
|  | /* | 
|  | * Copy the filename to the output buffer for encrypting in-place and | 
|  | * pad it with the needed number of NUL bytes. | 
|  | */ | 
|  | if (WARN_ON(olen < iname->len)) | 
|  | return -ENOBUFS; | 
|  | memcpy(out, iname->name, iname->len); | 
|  | memset(out + iname->len, 0, olen - iname->len); | 
|  |  | 
|  | /* Initialize the IV */ | 
|  | fscrypt_generate_iv(&iv, 0, ci); | 
|  |  | 
|  | /* Set up the encryption request */ | 
|  | req = skcipher_request_alloc(tfm, GFP_NOFS); | 
|  | if (!req) | 
|  | return -ENOMEM; | 
|  | skcipher_request_set_callback(req, | 
|  | CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, | 
|  | crypto_req_done, &wait); | 
|  | sg_init_one(&sg, out, olen); | 
|  | skcipher_request_set_crypt(req, &sg, &sg, olen, &iv); | 
|  |  | 
|  | /* Do the encryption */ | 
|  | res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait); | 
|  | skcipher_request_free(req); | 
|  | if (res < 0) { | 
|  | fscrypt_err(inode, "Filename encryption failed: %d", res); | 
|  | return res; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * fname_decrypt() - decrypt a filename | 
|  | * | 
|  | * The caller must have allocated sufficient memory for the @oname string. | 
|  | * | 
|  | * Return: 0 on success, -errno on failure | 
|  | */ | 
|  | static int fname_decrypt(struct inode *inode, | 
|  | const struct fscrypt_str *iname, | 
|  | struct fscrypt_str *oname) | 
|  | { | 
|  | struct skcipher_request *req = NULL; | 
|  | DECLARE_CRYPTO_WAIT(wait); | 
|  | struct scatterlist src_sg, dst_sg; | 
|  | struct fscrypt_info *ci = inode->i_crypt_info; | 
|  | struct crypto_skcipher *tfm = ci->ci_key.tfm; | 
|  | union fscrypt_iv iv; | 
|  | int res; | 
|  |  | 
|  | /* Allocate request */ | 
|  | req = skcipher_request_alloc(tfm, GFP_NOFS); | 
|  | if (!req) | 
|  | return -ENOMEM; | 
|  | skcipher_request_set_callback(req, | 
|  | CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, | 
|  | crypto_req_done, &wait); | 
|  |  | 
|  | /* Initialize IV */ | 
|  | fscrypt_generate_iv(&iv, 0, ci); | 
|  |  | 
|  | /* Create decryption request */ | 
|  | sg_init_one(&src_sg, iname->name, iname->len); | 
|  | sg_init_one(&dst_sg, oname->name, oname->len); | 
|  | skcipher_request_set_crypt(req, &src_sg, &dst_sg, iname->len, &iv); | 
|  | res = crypto_wait_req(crypto_skcipher_decrypt(req), &wait); | 
|  | skcipher_request_free(req); | 
|  | if (res < 0) { | 
|  | fscrypt_err(inode, "Filename decryption failed: %d", res); | 
|  | return res; | 
|  | } | 
|  |  | 
|  | oname->len = strnlen(oname->name, iname->len); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static const char lookup_table[65] = | 
|  | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; | 
|  |  | 
|  | #define BASE64_CHARS(nbytes)	DIV_ROUND_UP((nbytes) * 4, 3) | 
|  |  | 
|  | /** | 
|  | * base64_encode() - | 
|  | * | 
|  | * Encodes the input string using characters from the set [A-Za-z0-9+,]. | 
|  | * The encoded string is roughly 4/3 times the size of the input string. | 
|  | * | 
|  | * Return: length of the encoded string | 
|  | */ | 
|  | static int base64_encode(const u8 *src, int len, char *dst) | 
|  | { | 
|  | int i, bits = 0, ac = 0; | 
|  | char *cp = dst; | 
|  |  | 
|  | for (i = 0; i < len; i++) { | 
|  | ac += src[i] << bits; | 
|  | bits += 8; | 
|  | do { | 
|  | *cp++ = lookup_table[ac & 0x3f]; | 
|  | ac >>= 6; | 
|  | bits -= 6; | 
|  | } while (bits >= 6); | 
|  | } | 
|  | if (bits) | 
|  | *cp++ = lookup_table[ac & 0x3f]; | 
|  | return cp - dst; | 
|  | } | 
|  |  | 
|  | static int base64_decode(const char *src, int len, u8 *dst) | 
|  | { | 
|  | int i, bits = 0, ac = 0; | 
|  | const char *p; | 
|  | u8 *cp = dst; | 
|  |  | 
|  | for (i = 0; i < len; i++) { | 
|  | 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; | 
|  | } | 
|  | } | 
|  | if (ac) | 
|  | return -1; | 
|  | return cp - dst; | 
|  | } | 
|  |  | 
|  | bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len, | 
|  | u32 max_len, u32 *encrypted_len_ret) | 
|  | { | 
|  | const struct fscrypt_info *ci = inode->i_crypt_info; | 
|  | int padding = 4 << (fscrypt_policy_flags(&ci->ci_policy) & | 
|  | FSCRYPT_POLICY_FLAGS_PAD_MASK); | 
|  | 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; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * fscrypt_fname_alloc_buffer - allocate a buffer for presented filenames | 
|  | * | 
|  | * 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 | 
|  | */ | 
|  | int fscrypt_fname_alloc_buffer(const struct inode *inode, | 
|  | u32 max_encrypted_len, | 
|  | struct fscrypt_str *crypto_str) | 
|  | { | 
|  | const u32 max_encoded_len = | 
|  | max_t(u32, BASE64_CHARS(FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE), | 
|  | 1 + BASE64_CHARS(sizeof(struct fscrypt_digested_name))); | 
|  | u32 max_presented_len; | 
|  |  | 
|  | max_presented_len = max(max_encoded_len, max_encrypted_len); | 
|  |  | 
|  | crypto_str->name = kmalloc(max_presented_len + 1, GFP_NOFS); | 
|  | if (!crypto_str->name) | 
|  | return -ENOMEM; | 
|  | crypto_str->len = max_presented_len; | 
|  | return 0; | 
|  | } | 
|  | EXPORT_SYMBOL(fscrypt_fname_alloc_buffer); | 
|  |  | 
|  | /** | 
|  | * fscrypt_fname_free_buffer - free the buffer for presented filenames | 
|  | * | 
|  | * Free the buffer allocated by fscrypt_fname_alloc_buffer(). | 
|  | */ | 
|  | void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str) | 
|  | { | 
|  | if (!crypto_str) | 
|  | return; | 
|  | kfree(crypto_str->name); | 
|  | crypto_str->name = NULL; | 
|  | } | 
|  | EXPORT_SYMBOL(fscrypt_fname_free_buffer); | 
|  |  | 
|  | /** | 
|  | * fscrypt_fname_disk_to_usr() - converts a filename from disk space to user | 
|  | * space | 
|  | * | 
|  | * The caller must have allocated sufficient memory for the @oname string. | 
|  | * | 
|  | * 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. | 
|  | * | 
|  | * Return: 0 on success, -errno on failure | 
|  | */ | 
|  | int fscrypt_fname_disk_to_usr(struct inode *inode, | 
|  | u32 hash, u32 minor_hash, | 
|  | const struct fscrypt_str *iname, | 
|  | struct fscrypt_str *oname) | 
|  | { | 
|  | const struct qstr qname = FSTR_TO_QSTR(iname); | 
|  | struct fscrypt_digested_name digested_name; | 
|  |  | 
|  | if (fscrypt_is_dot_dotdot(&qname)) { | 
|  | oname->name[0] = '.'; | 
|  | oname->name[iname->len - 1] = '.'; | 
|  | oname->len = iname->len; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if (iname->len < FS_CRYPTO_BLOCK_SIZE) | 
|  | return -EUCLEAN; | 
|  |  | 
|  | if (fscrypt_has_encryption_key(inode)) | 
|  | return fname_decrypt(inode, iname, oname); | 
|  |  | 
|  | if (iname->len <= FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE) { | 
|  | oname->len = base64_encode(iname->name, iname->len, | 
|  | oname->name); | 
|  | return 0; | 
|  | } | 
|  | if (hash) { | 
|  | digested_name.hash = hash; | 
|  | digested_name.minor_hash = minor_hash; | 
|  | } else { | 
|  | digested_name.hash = 0; | 
|  | digested_name.minor_hash = 0; | 
|  | } | 
|  | memcpy(digested_name.digest, | 
|  | FSCRYPT_FNAME_DIGEST(iname->name, iname->len), | 
|  | FSCRYPT_FNAME_DIGEST_SIZE); | 
|  | oname->name[0] = '_'; | 
|  | oname->len = 1 + base64_encode((const u8 *)&digested_name, | 
|  | sizeof(digested_name), oname->name + 1); | 
|  | return 0; | 
|  | } | 
|  | EXPORT_SYMBOL(fscrypt_fname_disk_to_usr); | 
|  |  | 
|  | /** | 
|  | * 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 | 
|  | */ | 
|  | int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, | 
|  | int lookup, struct fscrypt_name *fname) | 
|  | { | 
|  | int ret; | 
|  | int digested; | 
|  |  | 
|  | memset(fname, 0, sizeof(struct fscrypt_name)); | 
|  | fname->usr_fname = iname; | 
|  |  | 
|  | if (!IS_ENCRYPTED(dir) || fscrypt_is_dot_dotdot(iname)) { | 
|  | fname->disk_name.name = (unsigned char *)iname->name; | 
|  | fname->disk_name.len = iname->len; | 
|  | return 0; | 
|  | } | 
|  | ret = fscrypt_get_encryption_info(dir); | 
|  | if (ret) | 
|  | return ret; | 
|  |  | 
|  | if (fscrypt_has_encryption_key(dir)) { | 
|  | if (!fscrypt_fname_encrypted_size(dir, iname->len, | 
|  | dir->i_sb->s_cop->max_namelen, | 
|  | &fname->crypto_buf.len)) | 
|  | return -ENAMETOOLONG; | 
|  | fname->crypto_buf.name = kmalloc(fname->crypto_buf.len, | 
|  | GFP_NOFS); | 
|  | if (!fname->crypto_buf.name) | 
|  | return -ENOMEM; | 
|  |  | 
|  | ret = fname_encrypt(dir, iname, fname->crypto_buf.name, | 
|  | fname->crypto_buf.len); | 
|  | if (ret) | 
|  | goto errout; | 
|  | fname->disk_name.name = fname->crypto_buf.name; | 
|  | fname->disk_name.len = fname->crypto_buf.len; | 
|  | return 0; | 
|  | } | 
|  | if (!lookup) | 
|  | return -ENOKEY; | 
|  | fname->is_ciphertext_name = true; | 
|  |  | 
|  | /* | 
|  | * We don't have the key and we are doing a lookup; decode the | 
|  | * user-supplied name | 
|  | */ | 
|  | 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; | 
|  | } | 
|  |  | 
|  | fname->crypto_buf.name = | 
|  | kmalloc(max_t(size_t, FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE, | 
|  | sizeof(struct fscrypt_digested_name)), | 
|  | GFP_KERNEL); | 
|  | if (fname->crypto_buf.name == NULL) | 
|  | return -ENOMEM; | 
|  |  | 
|  | ret = base64_decode(iname->name + digested, iname->len - digested, | 
|  | fname->crypto_buf.name); | 
|  | if (ret < 0) { | 
|  | ret = -ENOENT; | 
|  | goto errout; | 
|  | } | 
|  | fname->crypto_buf.len = ret; | 
|  | if (digested) { | 
|  | const struct fscrypt_digested_name *n = | 
|  | (const void *)fname->crypto_buf.name; | 
|  | fname->hash = n->hash; | 
|  | fname->minor_hash = n->minor_hash; | 
|  | } else { | 
|  | fname->disk_name.name = fname->crypto_buf.name; | 
|  | fname->disk_name.len = fname->crypto_buf.len; | 
|  | } | 
|  | return 0; | 
|  |  | 
|  | errout: | 
|  | kfree(fname->crypto_buf.name); | 
|  | return ret; | 
|  | } | 
|  | EXPORT_SYMBOL(fscrypt_setup_filename); |