Refactor support for encrypted symlinks to move common code to fscrypt.
-----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEK2m5VNv+CHkogTfJ8vlZVpUNgaMFAlp2R3AACgkQ8vlZVpUN gaOIdAgApEdlFR2Gf93z2hMj5HxVL5rjkuPJVtVkKu0eH2HMQJyxNmjymrRfuFmM 8W1CrEvVKi5Aj6r8q4KHIdVV247Ya0SVEhLwKM0LX4CvlZUXmwgCmZ/MPDTXA1eq C4vPVuJAuSNGNVYDlDs3+NiMHINGNVnBVQQFSPBP9P+iNWPD7o486712qaF8maVn RbfbQ2rWtOIRdlAOD1U5WqgQku59lOsmHk2pc0+X4LHCZFpMoaO80JVjENPAw+BF daRt6TX+WljMyx6DRIaszqau876CJhe/tqlZcCLOkpXZP0jJS13yodp26dVQmjCh w8YdiY7uHK2D+S/8eyj7h7DIwzu3vg== =ZjQP -----END PGP SIGNATURE----- Merge tag 'fscrypt_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/fscrypt Pull fscrypt updates from Ted Ts'o: "Refactor support for encrypted symlinks to move common code to fscrypt" Ted also points out about the merge: "This makes the f2fs symlink code use the fscrypt_encrypt_symlink() from the fscrypt tree. This will end up dropping the kzalloc() -> f2fs_kzalloc() change, which means the fscrypt-specific allocation won't get tested by f2fs's kmalloc error injection system; which is fine" * tag 'fscrypt_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/fscrypt: (26 commits) fscrypt: fix build with pre-4.6 gcc versions fscrypt: remove 'ci' parameter from fscrypt_put_encryption_info() fscrypt: document symlink length restriction fscrypt: fix up fscrypt_fname_encrypted_size() for internal use fscrypt: define fscrypt_fname_alloc_buffer() to be for presented names fscrypt: calculate NUL-padding length in one place only fscrypt: move fscrypt_symlink_data to fscrypt_private.h fscrypt: remove fscrypt_fname_usr_to_disk() ubifs: switch to fscrypt_get_symlink() ubifs: switch to fscrypt ->symlink() helper functions ubifs: free the encrypted symlink target f2fs: switch to fscrypt_get_symlink() f2fs: switch to fscrypt ->symlink() helper functions ext4: switch to fscrypt_get_symlink() ext4: switch to fscrypt ->symlink() helper functions fscrypt: new helper function - fscrypt_get_symlink() fscrypt: new helper functions for ->symlink() fscrypt: trim down fscrypt.h includes fscrypt: move fscrypt_is_dot_dotdot() to fs/crypto/fname.c fscrypt: move fscrypt_valid_enc_modes() to fscrypt_private.h ...
This commit is contained in:
		
						commit
						3462ac5703
					
				| @ -448,8 +448,14 @@ astute users may notice some differences in behavior: | ||||
| 
 | ||||
| - The st_size of an encrypted symlink will not necessarily give the | ||||
|   length of the symlink target as required by POSIX.  It will actually | ||||
|   give the length of the ciphertext, which may be slightly longer than | ||||
|   the plaintext due to the NUL-padding. | ||||
|   give the length of the ciphertext, which will be slightly longer | ||||
|   than the plaintext due to NUL-padding and an extra 2-byte overhead. | ||||
| 
 | ||||
| - The maximum length of an encrypted symlink is 2 bytes shorter than | ||||
|   the maximum length of an unencrypted symlink.  For example, on an | ||||
|   EXT4 filesystem with a 4K block size, unencrypted symlinks can be up | ||||
|   to 4095 bytes long, while encrypted symlinks can only be up to 4093 | ||||
|   bytes long (both lengths excluding the terminating null). | ||||
| 
 | ||||
| Note that mmap *is* supported.  This is possible because the pagecache | ||||
| for an encrypted file contains the plaintext, not the ciphertext. | ||||
|  | ||||
| @ -27,6 +27,7 @@ | ||||
| #include <linux/dcache.h> | ||||
| #include <linux/namei.h> | ||||
| #include <crypto/aes.h> | ||||
| #include <crypto/skcipher.h> | ||||
| #include "fscrypt_private.h" | ||||
| 
 | ||||
| static unsigned int num_prealloc_crypto_pages = 32; | ||||
|  | ||||
| @ -13,42 +13,46 @@ | ||||
| 
 | ||||
| #include <linux/scatterlist.h> | ||||
| #include <linux/ratelimit.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 caller must have allocated sufficient memory for the @oname string. | ||||
|  * 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 | ||||
|  */ | ||||
| static int fname_encrypt(struct inode *inode, | ||||
| 			const struct qstr *iname, struct fscrypt_str *oname) | ||||
| 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_ctfm; | ||||
| 	struct crypto_skcipher *tfm = inode->i_crypt_info->ci_ctfm; | ||||
| 	int res = 0; | ||||
| 	char iv[FS_CRYPTO_BLOCK_SIZE]; | ||||
| 	struct scatterlist sg; | ||||
| 	int padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK); | ||||
| 	unsigned int lim; | ||||
| 	unsigned int cryptlen; | ||||
| 
 | ||||
| 	lim = inode->i_sb->s_cop->max_namelen(inode); | ||||
| 	if (iname->len <= 0 || iname->len > lim) | ||||
| 		return -EIO; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * 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); | ||||
| 	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 */ | ||||
| 	memset(iv, 0, FS_CRYPTO_BLOCK_SIZE); | ||||
| @ -63,8 +67,8 @@ static int fname_encrypt(struct inode *inode, | ||||
| 	skcipher_request_set_callback(req, | ||||
| 			CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, | ||||
| 			crypto_req_done, &wait); | ||||
| 	sg_init_one(&sg, oname->name, cryptlen); | ||||
| 	skcipher_request_set_crypt(req, &sg, &sg, cryptlen, iv); | ||||
| 	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); | ||||
| @ -75,7 +79,6 @@ static int fname_encrypt(struct inode *inode, | ||||
| 		return res; | ||||
| 	} | ||||
| 
 | ||||
| 	oname->len = cryptlen; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| @ -188,50 +191,52 @@ static int digest_decode(const char *src, int len, char *dst) | ||||
| 	return cp - dst; | ||||
| } | ||||
| 
 | ||||
| u32 fscrypt_fname_encrypted_size(const struct inode *inode, u32 ilen) | ||||
| bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len, | ||||
| 				  u32 max_len, u32 *encrypted_len_ret) | ||||
| { | ||||
| 	int padding = 32; | ||||
| 	struct fscrypt_info *ci = inode->i_crypt_info; | ||||
| 	int padding = 4 << (inode->i_crypt_info->ci_flags & | ||||
| 			    FS_POLICY_FLAGS_PAD_MASK); | ||||
| 	u32 encrypted_len; | ||||
| 
 | ||||
| 	if (ci) | ||||
| 		padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK); | ||||
| 	ilen = max(ilen, (u32)FS_CRYPTO_BLOCK_SIZE); | ||||
| 	return round_up(ilen, padding); | ||||
| 	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; | ||||
| } | ||||
| EXPORT_SYMBOL(fscrypt_fname_encrypted_size); | ||||
| 
 | ||||
| /**
 | ||||
|  * fscrypt_fname_crypto_alloc_obuff() - | ||||
|  * fscrypt_fname_alloc_buffer - allocate a buffer for presented filenames | ||||
|  * | ||||
|  * Allocates an output buffer that is sufficient for the crypto operation | ||||
|  * specified by the context and the direction. | ||||
|  * 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 ilen, struct fscrypt_str *crypto_str) | ||||
| 			       u32 max_encrypted_len, | ||||
| 			       struct fscrypt_str *crypto_str) | ||||
| { | ||||
| 	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))); | ||||
| 	u32 max_presented_len; | ||||
| 
 | ||||
| 	crypto_str->len = olen; | ||||
| 	olen = max(olen, max_encoded_len); | ||||
| 	max_presented_len = max(max_encoded_len, max_encrypted_len); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Allocated buffer can hold one more character to null-terminate the | ||||
| 	 * string | ||||
| 	 */ | ||||
| 	crypto_str->name = kmalloc(olen + 1, GFP_NOFS); | ||||
| 	if (!(crypto_str->name)) | ||||
| 	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_crypto_free_buffer() - | ||||
|  * fscrypt_fname_free_buffer - free the buffer for presented filenames | ||||
|  * | ||||
|  * Frees the buffer allocated for crypto operation. | ||||
|  * Free the buffer allocated by fscrypt_fname_alloc_buffer(). | ||||
|  */ | ||||
| void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str) | ||||
| { | ||||
| @ -297,35 +302,6 @@ int fscrypt_fname_disk_to_usr(struct inode *inode, | ||||
| } | ||||
| EXPORT_SYMBOL(fscrypt_fname_disk_to_usr); | ||||
| 
 | ||||
| /**
 | ||||
|  * fscrypt_fname_usr_to_disk() - converts a filename from user space to disk | ||||
|  * space | ||||
|  * | ||||
|  * The caller must have allocated sufficient memory for the @oname string. | ||||
|  * | ||||
|  * Return: 0 on success, -errno on failure | ||||
|  */ | ||||
| int fscrypt_fname_usr_to_disk(struct inode *inode, | ||||
| 			const struct qstr *iname, | ||||
| 			struct fscrypt_str *oname) | ||||
| { | ||||
| 	if (fscrypt_is_dot_dotdot(iname)) { | ||||
| 		oname->name[0] = '.'; | ||||
| 		oname->name[iname->len - 1] = '.'; | ||||
| 		oname->len = iname->len; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	if (inode->i_crypt_info) | ||||
| 		return fname_encrypt(inode, iname, oname); | ||||
| 	/*
 | ||||
| 	 * Without a proper key, a user is not allowed to modify the filenames | ||||
| 	 * in a directory. Consequently, a user space name cannot be mapped to | ||||
| 	 * a disk-space name | ||||
| 	 */ | ||||
| 	return -ENOKEY; | ||||
| } | ||||
| EXPORT_SYMBOL(fscrypt_fname_usr_to_disk); | ||||
| 
 | ||||
| /**
 | ||||
|  * fscrypt_setup_filename() - prepare to search a possibly encrypted directory | ||||
|  * @dir: the directory that will be searched | ||||
| @ -369,11 +345,17 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, | ||||
| 		return ret; | ||||
| 
 | ||||
| 	if (dir->i_crypt_info) { | ||||
| 		ret = fscrypt_fname_alloc_buffer(dir, iname->len, | ||||
| 							&fname->crypto_buf); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| 		ret = fname_encrypt(dir, iname, &fname->crypto_buf); | ||||
| 		if (!fscrypt_fname_encrypted_size(dir, iname->len, | ||||
| 						  dir->i_sb->s_cop->max_namelen(dir), | ||||
| 						  &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; | ||||
| @ -425,7 +407,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, | ||||
| 	return 0; | ||||
| 
 | ||||
| errout: | ||||
| 	fscrypt_fname_free_buffer(&fname->crypto_buf); | ||||
| 	kfree(fname->crypto_buf.name); | ||||
| 	return ret; | ||||
| } | ||||
| EXPORT_SYMBOL(fscrypt_setup_filename); | ||||
|  | ||||
| @ -50,6 +50,15 @@ struct fscrypt_context { | ||||
| 
 | ||||
| #define FS_ENCRYPTION_CONTEXT_FORMAT_V1		1 | ||||
| 
 | ||||
| /**
 | ||||
|  * For encrypted symlinks, the ciphertext length is stored at the beginning | ||||
|  * of the string in little-endian format. | ||||
|  */ | ||||
| struct fscrypt_symlink_data { | ||||
| 	__le16 len; | ||||
| 	char encrypted_path[1]; | ||||
| } __packed; | ||||
| 
 | ||||
| /*
 | ||||
|  * A pointer to this structure is stored in the file system's in-core | ||||
|  * representation of an inode. | ||||
| @ -71,7 +80,22 @@ typedef enum { | ||||
| #define FS_CTX_REQUIRES_FREE_ENCRYPT_FL		0x00000001 | ||||
| #define FS_CTX_HAS_BOUNCE_BUFFER_FL		0x00000002 | ||||
| 
 | ||||
| static inline bool fscrypt_valid_enc_modes(u32 contents_mode, | ||||
| 					   u32 filenames_mode) | ||||
| { | ||||
| 	if (contents_mode == FS_ENCRYPTION_MODE_AES_128_CBC && | ||||
| 	    filenames_mode == FS_ENCRYPTION_MODE_AES_128_CTS) | ||||
| 		return true; | ||||
| 
 | ||||
| 	if (contents_mode == FS_ENCRYPTION_MODE_AES_256_XTS && | ||||
| 	    filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS) | ||||
| 		return true; | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /* crypto.c */ | ||||
| extern struct kmem_cache *fscrypt_info_cachep; | ||||
| extern int fscrypt_initialize(unsigned int cop_flags); | ||||
| extern struct workqueue_struct *fscrypt_read_workqueue; | ||||
| extern int fscrypt_do_page_crypto(const struct inode *inode, | ||||
| @ -83,6 +107,13 @@ extern int fscrypt_do_page_crypto(const struct inode *inode, | ||||
| extern struct page *fscrypt_alloc_bounce_page(struct fscrypt_ctx *ctx, | ||||
| 					      gfp_t gfp_flags); | ||||
| 
 | ||||
| /* fname.c */ | ||||
| extern int fname_encrypt(struct inode *inode, const struct qstr *iname, | ||||
| 			 u8 *out, unsigned int olen); | ||||
| extern bool fscrypt_fname_encrypted_size(const struct inode *inode, | ||||
| 					 u32 orig_len, u32 max_len, | ||||
| 					 u32 *encrypted_len_ret); | ||||
| 
 | ||||
| /* keyinfo.c */ | ||||
| extern void __exit fscrypt_essiv_cleanup(void); | ||||
| 
 | ||||
|  | ||||
| @ -110,3 +110,161 @@ int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry) | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(__fscrypt_prepare_lookup); | ||||
| 
 | ||||
| int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len, | ||||
| 			      unsigned int max_len, | ||||
| 			      struct fscrypt_str *disk_link) | ||||
| { | ||||
| 	int err; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * To calculate the size of the encrypted symlink target we need to know | ||||
| 	 * the amount of NUL padding, which is determined by the flags set in | ||||
| 	 * the encryption policy which will be inherited from the directory. | ||||
| 	 * The easiest way to get access to this is to just load the directory's | ||||
| 	 * fscrypt_info, since we'll need it to create the dir_entry anyway. | ||||
| 	 * | ||||
| 	 * Note: in test_dummy_encryption mode, @dir may be unencrypted. | ||||
| 	 */ | ||||
| 	err = fscrypt_get_encryption_info(dir); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 	if (!fscrypt_has_encryption_key(dir)) | ||||
| 		return -ENOKEY; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Calculate the size of the encrypted symlink and verify it won't | ||||
| 	 * exceed max_len.  Note that for historical reasons, encrypted symlink | ||||
| 	 * targets are prefixed with the ciphertext length, despite this | ||||
| 	 * actually being redundant with i_size.  This decreases by 2 bytes the | ||||
| 	 * longest symlink target we can accept. | ||||
| 	 * | ||||
| 	 * We could recover 1 byte by not counting a null terminator, but | ||||
| 	 * counting it (even though it is meaningless for ciphertext) is simpler | ||||
| 	 * for now since filesystems will assume it is there and subtract it. | ||||
| 	 */ | ||||
| 	if (!fscrypt_fname_encrypted_size(dir, len, | ||||
| 					  max_len - sizeof(struct fscrypt_symlink_data), | ||||
| 					  &disk_link->len)) | ||||
| 		return -ENAMETOOLONG; | ||||
| 	disk_link->len += sizeof(struct fscrypt_symlink_data); | ||||
| 
 | ||||
| 	disk_link->name = NULL; | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(__fscrypt_prepare_symlink); | ||||
| 
 | ||||
| int __fscrypt_encrypt_symlink(struct inode *inode, const char *target, | ||||
| 			      unsigned int len, struct fscrypt_str *disk_link) | ||||
| { | ||||
| 	int err; | ||||
| 	struct qstr iname = QSTR_INIT(target, len); | ||||
| 	struct fscrypt_symlink_data *sd; | ||||
| 	unsigned int ciphertext_len; | ||||
| 
 | ||||
| 	err = fscrypt_require_key(inode); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 
 | ||||
| 	if (disk_link->name) { | ||||
| 		/* filesystem-provided buffer */ | ||||
| 		sd = (struct fscrypt_symlink_data *)disk_link->name; | ||||
| 	} else { | ||||
| 		sd = kmalloc(disk_link->len, GFP_NOFS); | ||||
| 		if (!sd) | ||||
| 			return -ENOMEM; | ||||
| 	} | ||||
| 	ciphertext_len = disk_link->len - sizeof(*sd); | ||||
| 	sd->len = cpu_to_le16(ciphertext_len); | ||||
| 
 | ||||
| 	err = fname_encrypt(inode, &iname, sd->encrypted_path, ciphertext_len); | ||||
| 	if (err) { | ||||
| 		if (!disk_link->name) | ||||
| 			kfree(sd); | ||||
| 		return err; | ||||
| 	} | ||||
| 	/*
 | ||||
| 	 * Null-terminating the ciphertext doesn't make sense, but we still | ||||
| 	 * count the null terminator in the length, so we might as well | ||||
| 	 * initialize it just in case the filesystem writes it out. | ||||
| 	 */ | ||||
| 	sd->encrypted_path[ciphertext_len] = '\0'; | ||||
| 
 | ||||
| 	if (!disk_link->name) | ||||
| 		disk_link->name = (unsigned char *)sd; | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(__fscrypt_encrypt_symlink); | ||||
| 
 | ||||
| /**
 | ||||
|  * fscrypt_get_symlink - get the target of an encrypted symlink | ||||
|  * @inode: the symlink inode | ||||
|  * @caddr: the on-disk contents of the symlink | ||||
|  * @max_size: size of @caddr buffer | ||||
|  * @done: if successful, will be set up to free the returned target | ||||
|  * | ||||
|  * If the symlink's encryption key is available, we decrypt its target. | ||||
|  * Otherwise, we encode its target for presentation. | ||||
|  * | ||||
|  * This may sleep, so the filesystem must have dropped out of RCU mode already. | ||||
|  * | ||||
|  * Return: the presentable symlink target or an ERR_PTR() | ||||
|  */ | ||||
| const char *fscrypt_get_symlink(struct inode *inode, const void *caddr, | ||||
| 				unsigned int max_size, | ||||
| 				struct delayed_call *done) | ||||
| { | ||||
| 	const struct fscrypt_symlink_data *sd; | ||||
| 	struct fscrypt_str cstr, pstr; | ||||
| 	int err; | ||||
| 
 | ||||
| 	/* This is for encrypted symlinks only */ | ||||
| 	if (WARN_ON(!IS_ENCRYPTED(inode))) | ||||
| 		return ERR_PTR(-EINVAL); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Try to set up the symlink's encryption key, but we can continue | ||||
| 	 * regardless of whether the key is available or not. | ||||
| 	 */ | ||||
| 	err = fscrypt_get_encryption_info(inode); | ||||
| 	if (err) | ||||
| 		return ERR_PTR(err); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * For historical reasons, encrypted symlink targets are prefixed with | ||||
| 	 * the ciphertext length, even though this is redundant with i_size. | ||||
| 	 */ | ||||
| 
 | ||||
| 	if (max_size < sizeof(*sd)) | ||||
| 		return ERR_PTR(-EUCLEAN); | ||||
| 	sd = caddr; | ||||
| 	cstr.name = (unsigned char *)sd->encrypted_path; | ||||
| 	cstr.len = le16_to_cpu(sd->len); | ||||
| 
 | ||||
| 	if (cstr.len == 0) | ||||
| 		return ERR_PTR(-EUCLEAN); | ||||
| 
 | ||||
| 	if (cstr.len + sizeof(*sd) - 1 > max_size) | ||||
| 		return ERR_PTR(-EUCLEAN); | ||||
| 
 | ||||
| 	err = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr); | ||||
| 	if (err) | ||||
| 		return ERR_PTR(err); | ||||
| 
 | ||||
| 	err = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr); | ||||
| 	if (err) | ||||
| 		goto err_kfree; | ||||
| 
 | ||||
| 	err = -EUCLEAN; | ||||
| 	if (pstr.name[0] == '\0') | ||||
| 		goto err_kfree; | ||||
| 
 | ||||
| 	pstr.name[pstr.len] = '\0'; | ||||
| 	set_delayed_call(done, kfree_link, pstr.name); | ||||
| 	return pstr.name; | ||||
| 
 | ||||
| err_kfree: | ||||
| 	kfree(pstr.name); | ||||
| 	return ERR_PTR(err); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(fscrypt_get_symlink); | ||||
|  | ||||
| @ -14,6 +14,7 @@ | ||||
| #include <linux/ratelimit.h> | ||||
| #include <crypto/aes.h> | ||||
| #include <crypto/sha.h> | ||||
| #include <crypto/skcipher.h> | ||||
| #include "fscrypt_private.h" | ||||
| 
 | ||||
| static struct crypto_shash *essiv_hash_tfm; | ||||
| @ -354,19 +355,9 @@ out: | ||||
| } | ||||
| EXPORT_SYMBOL(fscrypt_get_encryption_info); | ||||
| 
 | ||||
| void fscrypt_put_encryption_info(struct inode *inode, struct fscrypt_info *ci) | ||||
| void fscrypt_put_encryption_info(struct inode *inode) | ||||
| { | ||||
| 	struct fscrypt_info *prev; | ||||
| 
 | ||||
| 	if (ci == NULL) | ||||
| 		ci = READ_ONCE(inode->i_crypt_info); | ||||
| 	if (ci == NULL) | ||||
| 		return; | ||||
| 
 | ||||
| 	prev = cmpxchg(&inode->i_crypt_info, ci, NULL); | ||||
| 	if (prev != ci) | ||||
| 		return; | ||||
| 
 | ||||
| 	put_crypt_info(ci); | ||||
| 	put_crypt_info(inode->i_crypt_info); | ||||
| 	inode->i_crypt_info = NULL; | ||||
| } | ||||
| EXPORT_SYMBOL(fscrypt_put_encryption_info); | ||||
|  | ||||
| @ -3057,39 +3057,19 @@ static int ext4_symlink(struct inode *dir, | ||||
| 	struct inode *inode; | ||||
| 	int err, len = strlen(symname); | ||||
| 	int credits; | ||||
| 	bool encryption_required; | ||||
| 	struct fscrypt_str disk_link; | ||||
| 	struct fscrypt_symlink_data *sd = NULL; | ||||
| 
 | ||||
| 	if (unlikely(ext4_forced_shutdown(EXT4_SB(dir->i_sb)))) | ||||
| 		return -EIO; | ||||
| 
 | ||||
| 	disk_link.len = len + 1; | ||||
| 	disk_link.name = (char *) symname; | ||||
| 
 | ||||
| 	encryption_required = (ext4_encrypted_inode(dir) || | ||||
| 			       DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb))); | ||||
| 	if (encryption_required) { | ||||
| 		err = fscrypt_get_encryption_info(dir); | ||||
| 		if (err) | ||||
| 			return err; | ||||
| 		if (!fscrypt_has_encryption_key(dir)) | ||||
| 			return -ENOKEY; | ||||
| 		disk_link.len = (fscrypt_fname_encrypted_size(dir, len) + | ||||
| 				 sizeof(struct fscrypt_symlink_data)); | ||||
| 		sd = kzalloc(disk_link.len, GFP_KERNEL); | ||||
| 		if (!sd) | ||||
| 			return -ENOMEM; | ||||
| 	} | ||||
| 
 | ||||
| 	if (disk_link.len > dir->i_sb->s_blocksize) { | ||||
| 		err = -ENAMETOOLONG; | ||||
| 		goto err_free_sd; | ||||
| 	} | ||||
| 	err = fscrypt_prepare_symlink(dir, symname, len, dir->i_sb->s_blocksize, | ||||
| 				      &disk_link); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 
 | ||||
| 	err = dquot_initialize(dir); | ||||
| 	if (err) | ||||
| 		goto err_free_sd; | ||||
| 		return err; | ||||
| 
 | ||||
| 	if ((disk_link.len > EXT4_N_BLOCKS * 4)) { | ||||
| 		/*
 | ||||
| @ -3118,27 +3098,18 @@ static int ext4_symlink(struct inode *dir, | ||||
| 	if (IS_ERR(inode)) { | ||||
| 		if (handle) | ||||
| 			ext4_journal_stop(handle); | ||||
| 		err = PTR_ERR(inode); | ||||
| 		goto err_free_sd; | ||||
| 		return PTR_ERR(inode); | ||||
| 	} | ||||
| 
 | ||||
| 	if (encryption_required) { | ||||
| 		struct qstr istr; | ||||
| 		struct fscrypt_str ostr = | ||||
| 			FSTR_INIT(sd->encrypted_path, disk_link.len); | ||||
| 
 | ||||
| 		istr.name = (const unsigned char *) symname; | ||||
| 		istr.len = len; | ||||
| 		err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr); | ||||
| 	if (IS_ENCRYPTED(inode)) { | ||||
| 		err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link); | ||||
| 		if (err) | ||||
| 			goto err_drop_inode; | ||||
| 		sd->len = cpu_to_le16(ostr.len); | ||||
| 		disk_link.name = (char *) sd; | ||||
| 		inode->i_op = &ext4_encrypted_symlink_inode_operations; | ||||
| 	} | ||||
| 
 | ||||
| 	if ((disk_link.len > EXT4_N_BLOCKS * 4)) { | ||||
| 		if (!encryption_required) | ||||
| 		if (!IS_ENCRYPTED(inode)) | ||||
| 			inode->i_op = &ext4_symlink_inode_operations; | ||||
| 		inode_nohighmem(inode); | ||||
| 		ext4_set_aops(inode); | ||||
| @ -3180,7 +3151,7 @@ static int ext4_symlink(struct inode *dir, | ||||
| 	} else { | ||||
| 		/* clear the extent format for fast symlink */ | ||||
| 		ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS); | ||||
| 		if (!encryption_required) { | ||||
| 		if (!IS_ENCRYPTED(inode)) { | ||||
| 			inode->i_op = &ext4_fast_symlink_inode_operations; | ||||
| 			inode->i_link = (char *)&EXT4_I(inode)->i_data; | ||||
| 		} | ||||
| @ -3195,16 +3166,17 @@ static int ext4_symlink(struct inode *dir, | ||||
| 
 | ||||
| 	if (handle) | ||||
| 		ext4_journal_stop(handle); | ||||
| 	kfree(sd); | ||||
| 	return err; | ||||
| 	goto out_free_encrypted_link; | ||||
| 
 | ||||
| err_drop_inode: | ||||
| 	if (handle) | ||||
| 		ext4_journal_stop(handle); | ||||
| 	clear_nlink(inode); | ||||
| 	unlock_new_inode(inode); | ||||
| 	iput(inode); | ||||
| err_free_sd: | ||||
| 	kfree(sd); | ||||
| out_free_encrypted_link: | ||||
| 	if (disk_link.name != (unsigned char *)symname) | ||||
| 		kfree(disk_link.name); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1073,9 +1073,7 @@ void ext4_clear_inode(struct inode *inode) | ||||
| 		jbd2_free_inode(EXT4_I(inode)->jinode); | ||||
| 		EXT4_I(inode)->jinode = NULL; | ||||
| 	} | ||||
| #ifdef CONFIG_EXT4_FS_ENCRYPTION | ||||
| 	fscrypt_put_encryption_info(inode, NULL); | ||||
| #endif | ||||
| 	fscrypt_put_encryption_info(inode); | ||||
| } | ||||
| 
 | ||||
| static struct inode *ext4_nfs_get_inode(struct super_block *sb, | ||||
|  | ||||
| @ -28,59 +28,28 @@ static const char *ext4_encrypted_get_link(struct dentry *dentry, | ||||
| 					   struct delayed_call *done) | ||||
| { | ||||
| 	struct page *cpage = NULL; | ||||
| 	char *caddr, *paddr = NULL; | ||||
| 	struct fscrypt_str cstr, pstr; | ||||
| 	struct fscrypt_symlink_data *sd; | ||||
| 	int res; | ||||
| 	u32 max_size = inode->i_sb->s_blocksize; | ||||
| 	const void *caddr; | ||||
| 	unsigned int max_size; | ||||
| 	const char *paddr; | ||||
| 
 | ||||
| 	if (!dentry) | ||||
| 		return ERR_PTR(-ECHILD); | ||||
| 
 | ||||
| 	res = fscrypt_get_encryption_info(inode); | ||||
| 	if (res) | ||||
| 		return ERR_PTR(res); | ||||
| 
 | ||||
| 	if (ext4_inode_is_fast_symlink(inode)) { | ||||
| 		caddr = (char *) EXT4_I(inode)->i_data; | ||||
| 		caddr = EXT4_I(inode)->i_data; | ||||
| 		max_size = sizeof(EXT4_I(inode)->i_data); | ||||
| 	} else { | ||||
| 		cpage = read_mapping_page(inode->i_mapping, 0, NULL); | ||||
| 		if (IS_ERR(cpage)) | ||||
| 			return ERR_CAST(cpage); | ||||
| 		caddr = page_address(cpage); | ||||
| 		max_size = inode->i_sb->s_blocksize; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Symlink is encrypted */ | ||||
| 	sd = (struct fscrypt_symlink_data *)caddr; | ||||
| 	cstr.name = sd->encrypted_path; | ||||
| 	cstr.len  = le16_to_cpu(sd->len); | ||||
| 	if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > max_size) { | ||||
| 		/* Symlink data on the disk is corrupted */ | ||||
| 		res = -EFSCORRUPTED; | ||||
| 		goto errout; | ||||
| 	} | ||||
| 
 | ||||
| 	res = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr); | ||||
| 	if (res) | ||||
| 		goto errout; | ||||
| 	paddr = pstr.name; | ||||
| 
 | ||||
| 	res = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr); | ||||
| 	if (res) | ||||
| 		goto errout; | ||||
| 
 | ||||
| 	/* Null-terminate the name */ | ||||
| 	paddr[pstr.len] = '\0'; | ||||
| 	paddr = fscrypt_get_symlink(inode, caddr, max_size, done); | ||||
| 	if (cpage) | ||||
| 		put_page(cpage); | ||||
| 	set_delayed_call(done, kfree_link, paddr); | ||||
| 	return paddr; | ||||
| errout: | ||||
| 	if (cpage) | ||||
| 		put_page(cpage); | ||||
| 	kfree(paddr); | ||||
| 	return ERR_PTR(res); | ||||
| } | ||||
| 
 | ||||
| const struct inode_operations ext4_encrypted_symlink_inode_operations = { | ||||
|  | ||||
| @ -585,7 +585,7 @@ no_delete: | ||||
| 			!exist_written_data(sbi, inode->i_ino, ORPHAN_INO)); | ||||
| 	} | ||||
| out_clear: | ||||
| 	fscrypt_put_encryption_info(inode, NULL); | ||||
| 	fscrypt_put_encryption_info(inode); | ||||
| 	clear_inode(inode); | ||||
| } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										132
									
								
								fs/f2fs/namei.c
									
									
									
									
									
								
							
							
						
						
									
										132
									
								
								fs/f2fs/namei.c
									
									
									
									
									
								
							| @ -486,27 +486,16 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, | ||||
| 	struct f2fs_sb_info *sbi = F2FS_I_SB(dir); | ||||
| 	struct inode *inode; | ||||
| 	size_t len = strlen(symname); | ||||
| 	struct fscrypt_str disk_link = FSTR_INIT((char *)symname, len + 1); | ||||
| 	struct fscrypt_symlink_data *sd = NULL; | ||||
| 	struct fscrypt_str disk_link; | ||||
| 	int err; | ||||
| 
 | ||||
| 	if (unlikely(f2fs_cp_error(sbi))) | ||||
| 		return -EIO; | ||||
| 
 | ||||
| 	if (f2fs_encrypted_inode(dir)) { | ||||
| 		err = fscrypt_get_encryption_info(dir); | ||||
| 		if (err) | ||||
| 			return err; | ||||
| 
 | ||||
| 		if (!fscrypt_has_encryption_key(dir)) | ||||
| 			return -ENOKEY; | ||||
| 
 | ||||
| 		disk_link.len = (fscrypt_fname_encrypted_size(dir, len) + | ||||
| 				sizeof(struct fscrypt_symlink_data)); | ||||
| 	} | ||||
| 
 | ||||
| 	if (disk_link.len > dir->i_sb->s_blocksize) | ||||
| 		return -ENAMETOOLONG; | ||||
| 	err = fscrypt_prepare_symlink(dir, symname, len, dir->i_sb->s_blocksize, | ||||
| 				      &disk_link); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 
 | ||||
| 	err = dquot_initialize(dir); | ||||
| 	if (err) | ||||
| @ -516,7 +505,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, | ||||
| 	if (IS_ERR(inode)) | ||||
| 		return PTR_ERR(inode); | ||||
| 
 | ||||
| 	if (f2fs_encrypted_inode(inode)) | ||||
| 	if (IS_ENCRYPTED(inode)) | ||||
| 		inode->i_op = &f2fs_encrypted_symlink_inode_operations; | ||||
| 	else | ||||
| 		inode->i_op = &f2fs_symlink_inode_operations; | ||||
| @ -526,38 +515,13 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, | ||||
| 	f2fs_lock_op(sbi); | ||||
| 	err = f2fs_add_link(dentry, inode); | ||||
| 	if (err) | ||||
| 		goto out; | ||||
| 		goto out_handle_failed_inode; | ||||
| 	f2fs_unlock_op(sbi); | ||||
| 	alloc_nid_done(sbi, inode->i_ino); | ||||
| 
 | ||||
| 	if (f2fs_encrypted_inode(inode)) { | ||||
| 		struct qstr istr = QSTR_INIT(symname, len); | ||||
| 		struct fscrypt_str ostr; | ||||
| 
 | ||||
| 		sd = f2fs_kzalloc(sbi, disk_link.len, GFP_NOFS); | ||||
| 		if (!sd) { | ||||
| 			err = -ENOMEM; | ||||
| 			goto err_out; | ||||
| 		} | ||||
| 
 | ||||
| 		err = fscrypt_get_encryption_info(inode); | ||||
| 		if (err) | ||||
| 			goto err_out; | ||||
| 
 | ||||
| 		if (!fscrypt_has_encryption_key(inode)) { | ||||
| 			err = -ENOKEY; | ||||
| 			goto err_out; | ||||
| 		} | ||||
| 
 | ||||
| 		ostr.name = sd->encrypted_path; | ||||
| 		ostr.len = disk_link.len; | ||||
| 		err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr); | ||||
| 		if (err) | ||||
| 			goto err_out; | ||||
| 
 | ||||
| 		sd->len = cpu_to_le16(ostr.len); | ||||
| 		disk_link.name = (char *)sd; | ||||
| 	} | ||||
| 	err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link); | ||||
| 	if (err) | ||||
| 		goto err_out; | ||||
| 
 | ||||
| 	err = page_symlink(inode, disk_link.name, disk_link.len); | ||||
| 
 | ||||
| @ -584,12 +548,14 @@ err_out: | ||||
| 		f2fs_unlink(dir, dentry); | ||||
| 	} | ||||
| 
 | ||||
| 	kfree(sd); | ||||
| 
 | ||||
| 	f2fs_balance_fs(sbi, true); | ||||
| 	return err; | ||||
| out: | ||||
| 	goto out_free_encrypted_link; | ||||
| 
 | ||||
| out_handle_failed_inode: | ||||
| 	handle_failed_inode(inode); | ||||
| out_free_encrypted_link: | ||||
| 	if (disk_link.name != (unsigned char *)symname) | ||||
| 		kfree(disk_link.name); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| @ -1148,68 +1114,20 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry, | ||||
| 					   struct inode *inode, | ||||
| 					   struct delayed_call *done) | ||||
| { | ||||
| 	struct page *cpage = NULL; | ||||
| 	char *caddr, *paddr = NULL; | ||||
| 	struct fscrypt_str cstr = FSTR_INIT(NULL, 0); | ||||
| 	struct fscrypt_str pstr = FSTR_INIT(NULL, 0); | ||||
| 	struct fscrypt_symlink_data *sd; | ||||
| 	u32 max_size = inode->i_sb->s_blocksize; | ||||
| 	int res; | ||||
| 	struct page *page; | ||||
| 	const char *target; | ||||
| 
 | ||||
| 	if (!dentry) | ||||
| 		return ERR_PTR(-ECHILD); | ||||
| 
 | ||||
| 	res = fscrypt_get_encryption_info(inode); | ||||
| 	if (res) | ||||
| 		return ERR_PTR(res); | ||||
| 	page = read_mapping_page(inode->i_mapping, 0, NULL); | ||||
| 	if (IS_ERR(page)) | ||||
| 		return ERR_CAST(page); | ||||
| 
 | ||||
| 	cpage = read_mapping_page(inode->i_mapping, 0, NULL); | ||||
| 	if (IS_ERR(cpage)) | ||||
| 		return ERR_CAST(cpage); | ||||
| 	caddr = page_address(cpage); | ||||
| 
 | ||||
| 	/* Symlink is encrypted */ | ||||
| 	sd = (struct fscrypt_symlink_data *)caddr; | ||||
| 	cstr.name = sd->encrypted_path; | ||||
| 	cstr.len = le16_to_cpu(sd->len); | ||||
| 
 | ||||
| 	/* this is broken symlink case */ | ||||
| 	if (unlikely(cstr.len == 0)) { | ||||
| 		res = -ENOENT; | ||||
| 		goto errout; | ||||
| 	} | ||||
| 
 | ||||
| 	if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > max_size) { | ||||
| 		/* Symlink data on the disk is corrupted */ | ||||
| 		res = -EIO; | ||||
| 		goto errout; | ||||
| 	} | ||||
| 	res = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr); | ||||
| 	if (res) | ||||
| 		goto errout; | ||||
| 
 | ||||
| 	res = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr); | ||||
| 	if (res) | ||||
| 		goto errout; | ||||
| 
 | ||||
| 	/* this is broken symlink case */ | ||||
| 	if (unlikely(pstr.name[0] == 0)) { | ||||
| 		res = -ENOENT; | ||||
| 		goto errout; | ||||
| 	} | ||||
| 
 | ||||
| 	paddr = pstr.name; | ||||
| 
 | ||||
| 	/* Null-terminate the name */ | ||||
| 	paddr[pstr.len] = '\0'; | ||||
| 
 | ||||
| 	put_page(cpage); | ||||
| 	set_delayed_call(done, kfree_link, paddr); | ||||
| 	return paddr; | ||||
| errout: | ||||
| 	fscrypt_fname_free_buffer(&pstr); | ||||
| 	put_page(cpage); | ||||
| 	return ERR_PTR(res); | ||||
| 	target = fscrypt_get_symlink(inode, page_address(page), | ||||
| 				     inode->i_sb->s_blocksize, done); | ||||
| 	put_page(page); | ||||
| 	return target; | ||||
| } | ||||
| 
 | ||||
| const struct inode_operations f2fs_encrypted_symlink_inode_operations = { | ||||
|  | ||||
| @ -1138,38 +1138,24 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry, | ||||
| 	struct ubifs_info *c = dir->i_sb->s_fs_info; | ||||
| 	int err, len = strlen(symname); | ||||
| 	int sz_change = CALC_DENT_SIZE(len); | ||||
| 	struct fscrypt_str disk_link = FSTR_INIT((char *)symname, len + 1); | ||||
| 	struct fscrypt_symlink_data *sd = NULL; | ||||
| 	struct fscrypt_str disk_link; | ||||
| 	struct ubifs_budget_req req = { .new_ino = 1, .new_dent = 1, | ||||
| 					.new_ino_d = ALIGN(len, 8), | ||||
| 					.dirtied_ino = 1 }; | ||||
| 	struct fscrypt_name nm; | ||||
| 
 | ||||
| 	if (ubifs_crypt_is_encrypted(dir)) { | ||||
| 		err = fscrypt_get_encryption_info(dir); | ||||
| 		if (err) | ||||
| 			goto out_budg; | ||||
| 	dbg_gen("dent '%pd', target '%s' in dir ino %lu", dentry, | ||||
| 		symname, dir->i_ino); | ||||
| 
 | ||||
| 		if (!fscrypt_has_encryption_key(dir)) { | ||||
| 			err = -EPERM; | ||||
| 			goto out_budg; | ||||
| 		} | ||||
| 
 | ||||
| 		disk_link.len = (fscrypt_fname_encrypted_size(dir, len) + | ||||
| 				sizeof(struct fscrypt_symlink_data)); | ||||
| 	} | ||||
| 	err = fscrypt_prepare_symlink(dir, symname, len, UBIFS_MAX_INO_DATA, | ||||
| 				      &disk_link); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Budget request settings: new inode, new direntry and changing parent | ||||
| 	 * directory inode. | ||||
| 	 */ | ||||
| 
 | ||||
| 	dbg_gen("dent '%pd', target '%s' in dir ino %lu", dentry, | ||||
| 		symname, dir->i_ino); | ||||
| 
 | ||||
| 	if (disk_link.len > UBIFS_MAX_INO_DATA) | ||||
| 		return -ENAMETOOLONG; | ||||
| 
 | ||||
| 	err = ubifs_budget_space(c, &req); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| @ -1191,38 +1177,20 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry, | ||||
| 		goto out_inode; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ubifs_crypt_is_encrypted(dir)) { | ||||
| 		struct qstr istr = QSTR_INIT(symname, len); | ||||
| 		struct fscrypt_str ostr; | ||||
| 
 | ||||
| 		sd = kzalloc(disk_link.len, GFP_NOFS); | ||||
| 		if (!sd) { | ||||
| 			err = -ENOMEM; | ||||
| 	if (IS_ENCRYPTED(inode)) { | ||||
| 		disk_link.name = ui->data; /* encrypt directly into ui->data */ | ||||
| 		err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link); | ||||
| 		if (err) | ||||
| 			goto out_inode; | ||||
| 		} | ||||
| 
 | ||||
| 		ostr.name = sd->encrypted_path; | ||||
| 		ostr.len = disk_link.len; | ||||
| 
 | ||||
| 		err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr); | ||||
| 		if (err) { | ||||
| 			kfree(sd); | ||||
| 			goto out_inode; | ||||
| 		} | ||||
| 
 | ||||
| 		sd->len = cpu_to_le16(ostr.len); | ||||
| 		disk_link.name = (char *)sd; | ||||
| 	} else { | ||||
| 		memcpy(ui->data, disk_link.name, disk_link.len); | ||||
| 		inode->i_link = ui->data; | ||||
| 	} | ||||
| 
 | ||||
| 	memcpy(ui->data, disk_link.name, disk_link.len); | ||||
| 	((char *)ui->data)[disk_link.len - 1] = '\0'; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * The terminating zero byte is not written to the flash media and it | ||||
| 	 * is put just to make later in-memory string processing simpler. Thus, | ||||
| 	 * data length is @len, not @len + %1. | ||||
| 	 * data length is @disk_link.len - 1, not @disk_link.len. | ||||
| 	 */ | ||||
| 	ui->data_len = disk_link.len - 1; | ||||
| 	inode->i_size = ubifs_inode(inode)->ui_size = disk_link.len - 1; | ||||
| @ -1240,11 +1208,10 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry, | ||||
| 		goto out_cancel; | ||||
| 	mutex_unlock(&dir_ui->ui_mutex); | ||||
| 
 | ||||
| 	ubifs_release_budget(c, &req); | ||||
| 	insert_inode_hash(inode); | ||||
| 	d_instantiate(dentry, inode); | ||||
| 	fscrypt_free_filename(&nm); | ||||
| 	return 0; | ||||
| 	err = 0; | ||||
| 	goto out_fname; | ||||
| 
 | ||||
| out_cancel: | ||||
| 	dir->i_size -= sz_change; | ||||
|  | ||||
| @ -1629,49 +1629,17 @@ static const char *ubifs_get_link(struct dentry *dentry, | ||||
| 					    struct inode *inode, | ||||
| 					    struct delayed_call *done) | ||||
| { | ||||
| 	int err; | ||||
| 	struct fscrypt_symlink_data *sd; | ||||
| 	struct ubifs_inode *ui = ubifs_inode(inode); | ||||
| 	struct fscrypt_str cstr; | ||||
| 	struct fscrypt_str pstr; | ||||
| 
 | ||||
| 	if (!ubifs_crypt_is_encrypted(inode)) | ||||
| 	if (!IS_ENCRYPTED(inode)) | ||||
| 		return ui->data; | ||||
| 
 | ||||
| 	if (!dentry) | ||||
| 		return ERR_PTR(-ECHILD); | ||||
| 
 | ||||
| 	err = fscrypt_get_encryption_info(inode); | ||||
| 	if (err) | ||||
| 		return ERR_PTR(err); | ||||
| 
 | ||||
| 	sd = (struct fscrypt_symlink_data *)ui->data; | ||||
| 	cstr.name = sd->encrypted_path; | ||||
| 	cstr.len = le16_to_cpu(sd->len); | ||||
| 
 | ||||
| 	if (cstr.len == 0) | ||||
| 		return ERR_PTR(-ENOENT); | ||||
| 
 | ||||
| 	if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > ui->data_len) | ||||
| 		return ERR_PTR(-EIO); | ||||
| 
 | ||||
| 	err = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr); | ||||
| 	if (err) | ||||
| 		return ERR_PTR(err); | ||||
| 
 | ||||
| 	err = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr); | ||||
| 	if (err) { | ||||
| 		fscrypt_fname_free_buffer(&pstr); | ||||
| 		return ERR_PTR(err); | ||||
| 	} | ||||
| 
 | ||||
| 	pstr.name[pstr.len] = '\0'; | ||||
| 
 | ||||
| 	set_delayed_call(done, kfree_link, pstr.name); | ||||
| 	return pstr.name; | ||||
| 	return fscrypt_get_symlink(inode, ui->data, ui->data_len, done); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| const struct address_space_operations ubifs_file_address_operations = { | ||||
| 	.readpage       = ubifs_readpage, | ||||
| 	.writepage      = ubifs_writepage, | ||||
|  | ||||
| @ -379,9 +379,7 @@ out: | ||||
| 	} | ||||
| done: | ||||
| 	clear_inode(inode); | ||||
| #ifdef CONFIG_UBIFS_FS_ENCRYPTION | ||||
| 	fscrypt_put_encryption_info(inode, NULL); | ||||
| #endif | ||||
| 	fscrypt_put_encryption_info(inode); | ||||
| } | ||||
| 
 | ||||
| static void ubifs_dirty_inode(struct inode *inode, int flags) | ||||
|  | ||||
| @ -14,42 +14,13 @@ | ||||
| #ifndef _LINUX_FSCRYPT_H | ||||
| #define _LINUX_FSCRYPT_H | ||||
| 
 | ||||
| #include <linux/key.h> | ||||
| #include <linux/fs.h> | ||||
| #include <linux/mm.h> | ||||
| #include <linux/bio.h> | ||||
| #include <linux/dcache.h> | ||||
| #include <crypto/skcipher.h> | ||||
| #include <uapi/linux/fs.h> | ||||
| 
 | ||||
| #define FS_CRYPTO_BLOCK_SIZE		16 | ||||
| 
 | ||||
| struct fscrypt_ctx; | ||||
| struct fscrypt_info; | ||||
| 
 | ||||
| struct fscrypt_ctx { | ||||
| 	union { | ||||
| 		struct { | ||||
| 			struct page *bounce_page;	/* Ciphertext page */ | ||||
| 			struct page *control_page;	/* Original page  */ | ||||
| 		} w; | ||||
| 		struct { | ||||
| 			struct bio *bio; | ||||
| 			struct work_struct work; | ||||
| 		} r; | ||||
| 		struct list_head free_list;	/* Free list */ | ||||
| 	}; | ||||
| 	u8 flags;				/* Flags */ | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * For encrypted symlinks, the ciphertext length is stored at the beginning | ||||
|  * of the string in little-endian format. | ||||
|  */ | ||||
| struct fscrypt_symlink_data { | ||||
| 	__le16 len; | ||||
| 	char encrypted_path[1]; | ||||
| } __packed; | ||||
| 
 | ||||
| struct fscrypt_str { | ||||
| 	unsigned char *name; | ||||
| 	u32 len; | ||||
| @ -68,89 +39,14 @@ struct fscrypt_name { | ||||
| #define fname_name(p)		((p)->disk_name.name) | ||||
| #define fname_len(p)		((p)->disk_name.len) | ||||
| 
 | ||||
| /*
 | ||||
|  * fscrypt superblock flags | ||||
|  */ | ||||
| #define FS_CFLG_OWN_PAGES (1U << 1) | ||||
| 
 | ||||
| /*
 | ||||
|  * crypto opertions for filesystems | ||||
|  */ | ||||
| struct fscrypt_operations { | ||||
| 	unsigned int flags; | ||||
| 	const char *key_prefix; | ||||
| 	int (*get_context)(struct inode *, void *, size_t); | ||||
| 	int (*set_context)(struct inode *, const void *, size_t, void *); | ||||
| 	bool (*dummy_context)(struct inode *); | ||||
| 	bool (*empty_dir)(struct inode *); | ||||
| 	unsigned (*max_namelen)(struct inode *); | ||||
| }; | ||||
| 
 | ||||
| /* Maximum value for the third parameter of fscrypt_operations.set_context(). */ | ||||
| #define FSCRYPT_SET_CONTEXT_MAX_SIZE	28 | ||||
| 
 | ||||
| static inline bool fscrypt_dummy_context_enabled(struct inode *inode) | ||||
| { | ||||
| 	if (inode->i_sb->s_cop->dummy_context && | ||||
| 				inode->i_sb->s_cop->dummy_context(inode)) | ||||
| 		return true; | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| static inline bool fscrypt_valid_enc_modes(u32 contents_mode, | ||||
| 					u32 filenames_mode) | ||||
| { | ||||
| 	if (contents_mode == FS_ENCRYPTION_MODE_AES_128_CBC && | ||||
| 	    filenames_mode == FS_ENCRYPTION_MODE_AES_128_CTS) | ||||
| 		return true; | ||||
| 
 | ||||
| 	if (contents_mode == FS_ENCRYPTION_MODE_AES_256_XTS && | ||||
| 	    filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS) | ||||
| 		return true; | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| } | ||||
| 
 | ||||
| #if __FS_HAS_ENCRYPTION | ||||
| 
 | ||||
| static inline struct page *fscrypt_control_page(struct page *page) | ||||
| { | ||||
| 	return ((struct fscrypt_ctx *)page_private(page))->w.control_page; | ||||
| } | ||||
| 
 | ||||
| static inline bool fscrypt_has_encryption_key(const struct inode *inode) | ||||
| { | ||||
| 	return (inode->i_crypt_info != NULL); | ||||
| } | ||||
| 
 | ||||
| #include <linux/fscrypt_supp.h> | ||||
| 
 | ||||
| #else /* !__FS_HAS_ENCRYPTION */ | ||||
| 
 | ||||
| static inline struct page *fscrypt_control_page(struct page *page) | ||||
| { | ||||
| 	WARN_ON_ONCE(1); | ||||
| 	return ERR_PTR(-EINVAL); | ||||
| } | ||||
| 
 | ||||
| static inline bool fscrypt_has_encryption_key(const struct inode *inode) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #else | ||||
| #include <linux/fscrypt_notsupp.h> | ||||
| #endif /* __FS_HAS_ENCRYPTION */ | ||||
| #endif | ||||
| 
 | ||||
| /**
 | ||||
|  * fscrypt_require_key - require an inode's encryption key | ||||
| @ -291,4 +187,68 @@ static inline int fscrypt_prepare_setattr(struct dentry *dentry, | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * fscrypt_prepare_symlink - prepare to create a possibly-encrypted symlink | ||||
|  * @dir: directory in which the symlink is being created | ||||
|  * @target: plaintext symlink target | ||||
|  * @len: length of @target excluding null terminator | ||||
|  * @max_len: space the filesystem has available to store the symlink target | ||||
|  * @disk_link: (out) the on-disk symlink target being prepared | ||||
|  * | ||||
|  * This function computes the size the symlink target will require on-disk, | ||||
|  * stores it in @disk_link->len, and validates it against @max_len.  An | ||||
|  * encrypted symlink may be longer than the original. | ||||
|  * | ||||
|  * Additionally, @disk_link->name is set to @target if the symlink will be | ||||
|  * unencrypted, but left NULL if the symlink will be encrypted.  For encrypted | ||||
|  * symlinks, the filesystem must call fscrypt_encrypt_symlink() to create the | ||||
|  * on-disk target later.  (The reason for the two-step process is that some | ||||
|  * filesystems need to know the size of the symlink target before creating the | ||||
|  * inode, e.g. to determine whether it will be a "fast" or "slow" symlink.) | ||||
|  * | ||||
|  * Return: 0 on success, -ENAMETOOLONG if the symlink target is too long, | ||||
|  * -ENOKEY if the encryption key is missing, or another -errno code if a problem | ||||
|  * occurred while setting up the encryption key. | ||||
|  */ | ||||
| static inline int fscrypt_prepare_symlink(struct inode *dir, | ||||
| 					  const char *target, | ||||
| 					  unsigned int len, | ||||
| 					  unsigned int max_len, | ||||
| 					  struct fscrypt_str *disk_link) | ||||
| { | ||||
| 	if (IS_ENCRYPTED(dir) || fscrypt_dummy_context_enabled(dir)) | ||||
| 		return __fscrypt_prepare_symlink(dir, len, max_len, disk_link); | ||||
| 
 | ||||
| 	disk_link->name = (unsigned char *)target; | ||||
| 	disk_link->len = len + 1; | ||||
| 	if (disk_link->len > max_len) | ||||
| 		return -ENAMETOOLONG; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * fscrypt_encrypt_symlink - encrypt the symlink target if needed | ||||
|  * @inode: symlink inode | ||||
|  * @target: plaintext symlink target | ||||
|  * @len: length of @target excluding null terminator | ||||
|  * @disk_link: (in/out) the on-disk symlink target being prepared | ||||
|  * | ||||
|  * If the symlink target needs to be encrypted, then this function encrypts it | ||||
|  * into @disk_link->name.  fscrypt_prepare_symlink() must have been called | ||||
|  * previously to compute @disk_link->len.  If the filesystem did not allocate a | ||||
|  * buffer for @disk_link->name after calling fscrypt_prepare_link(), then one | ||||
|  * will be kmalloc()'ed and the filesystem will be responsible for freeing it. | ||||
|  * | ||||
|  * Return: 0 on success, -errno on failure | ||||
|  */ | ||||
| static inline int fscrypt_encrypt_symlink(struct inode *inode, | ||||
| 					  const char *target, | ||||
| 					  unsigned int len, | ||||
| 					  struct fscrypt_str *disk_link) | ||||
| { | ||||
| 	if (IS_ENCRYPTED(inode)) | ||||
| 		return __fscrypt_encrypt_symlink(inode, target, len, disk_link); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #endif	/* _LINUX_FSCRYPT_H */ | ||||
|  | ||||
| @ -14,6 +14,16 @@ | ||||
| #ifndef _LINUX_FSCRYPT_NOTSUPP_H | ||||
| #define _LINUX_FSCRYPT_NOTSUPP_H | ||||
| 
 | ||||
| static inline bool fscrypt_has_encryption_key(const struct inode *inode) | ||||
| { | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| static inline bool fscrypt_dummy_context_enabled(struct inode *inode) | ||||
| { | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| /* crypto.c */ | ||||
| static inline struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode, | ||||
| 						  gfp_t gfp_flags) | ||||
| @ -43,6 +53,11 @@ static inline int fscrypt_decrypt_page(const struct inode *inode, | ||||
| 	return -EOPNOTSUPP; | ||||
| } | ||||
| 
 | ||||
| static inline struct page *fscrypt_control_page(struct page *page) | ||||
| { | ||||
| 	WARN_ON_ONCE(1); | ||||
| 	return ERR_PTR(-EINVAL); | ||||
| } | ||||
| 
 | ||||
| static inline void fscrypt_restore_control_page(struct page *page) | ||||
| { | ||||
| @ -90,8 +105,7 @@ static inline int fscrypt_get_encryption_info(struct inode *inode) | ||||
| 	return -EOPNOTSUPP; | ||||
| } | ||||
| 
 | ||||
| static inline void fscrypt_put_encryption_info(struct inode *inode, | ||||
| 					       struct fscrypt_info *ci) | ||||
| static inline void fscrypt_put_encryption_info(struct inode *inode) | ||||
| { | ||||
| 	return; | ||||
| } | ||||
| @ -116,16 +130,8 @@ static inline void fscrypt_free_filename(struct fscrypt_name *fname) | ||||
| 	return; | ||||
| } | ||||
| 
 | ||||
| static inline u32 fscrypt_fname_encrypted_size(const struct inode *inode, | ||||
| 					       u32 ilen) | ||||
| { | ||||
| 	/* never happens */ | ||||
| 	WARN_ON(1); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static inline int fscrypt_fname_alloc_buffer(const struct inode *inode, | ||||
| 					     u32 ilen, | ||||
| 					     u32 max_encrypted_len, | ||||
| 					     struct fscrypt_str *crypto_str) | ||||
| { | ||||
| 	return -EOPNOTSUPP; | ||||
| @ -144,13 +150,6 @@ static inline int fscrypt_fname_disk_to_usr(struct inode *inode, | ||||
| 	return -EOPNOTSUPP; | ||||
| } | ||||
| 
 | ||||
| static inline int fscrypt_fname_usr_to_disk(struct inode *inode, | ||||
| 					    const struct qstr *iname, | ||||
| 					    struct fscrypt_str *oname) | ||||
| { | ||||
| 	return -EOPNOTSUPP; | ||||
| } | ||||
| 
 | ||||
| static inline bool fscrypt_match_name(const struct fscrypt_name *fname, | ||||
| 				      const u8 *de_name, u32 de_name_len) | ||||
| { | ||||
| @ -208,4 +207,28 @@ static inline int __fscrypt_prepare_lookup(struct inode *dir, | ||||
| 	return -EOPNOTSUPP; | ||||
| } | ||||
| 
 | ||||
| static inline int __fscrypt_prepare_symlink(struct inode *dir, | ||||
| 					    unsigned int len, | ||||
| 					    unsigned int max_len, | ||||
| 					    struct fscrypt_str *disk_link) | ||||
| { | ||||
| 	return -EOPNOTSUPP; | ||||
| } | ||||
| 
 | ||||
| static inline int __fscrypt_encrypt_symlink(struct inode *inode, | ||||
| 					    const char *target, | ||||
| 					    unsigned int len, | ||||
| 					    struct fscrypt_str *disk_link) | ||||
| { | ||||
| 	return -EOPNOTSUPP; | ||||
| } | ||||
| 
 | ||||
| static inline const char *fscrypt_get_symlink(struct inode *inode, | ||||
| 					      const void *caddr, | ||||
| 					      unsigned int max_size, | ||||
| 					      struct delayed_call *done) | ||||
| { | ||||
| 	return ERR_PTR(-EOPNOTSUPP); | ||||
| } | ||||
| 
 | ||||
| #endif	/* _LINUX_FSCRYPT_NOTSUPP_H */ | ||||
|  | ||||
| @ -11,8 +11,54 @@ | ||||
| #ifndef _LINUX_FSCRYPT_SUPP_H | ||||
| #define _LINUX_FSCRYPT_SUPP_H | ||||
| 
 | ||||
| #include <linux/mm.h> | ||||
| #include <linux/slab.h> | ||||
| 
 | ||||
| /*
 | ||||
|  * fscrypt superblock flags | ||||
|  */ | ||||
| #define FS_CFLG_OWN_PAGES (1U << 1) | ||||
| 
 | ||||
| /*
 | ||||
|  * crypto operations for filesystems | ||||
|  */ | ||||
| struct fscrypt_operations { | ||||
| 	unsigned int flags; | ||||
| 	const char *key_prefix; | ||||
| 	int (*get_context)(struct inode *, void *, size_t); | ||||
| 	int (*set_context)(struct inode *, const void *, size_t, void *); | ||||
| 	bool (*dummy_context)(struct inode *); | ||||
| 	bool (*empty_dir)(struct inode *); | ||||
| 	unsigned (*max_namelen)(struct inode *); | ||||
| }; | ||||
| 
 | ||||
| struct fscrypt_ctx { | ||||
| 	union { | ||||
| 		struct { | ||||
| 			struct page *bounce_page;	/* Ciphertext page */ | ||||
| 			struct page *control_page;	/* Original page  */ | ||||
| 		} w; | ||||
| 		struct { | ||||
| 			struct bio *bio; | ||||
| 			struct work_struct work; | ||||
| 		} r; | ||||
| 		struct list_head free_list;	/* Free list */ | ||||
| 	}; | ||||
| 	u8 flags;				/* Flags */ | ||||
| }; | ||||
| 
 | ||||
| static inline bool fscrypt_has_encryption_key(const struct inode *inode) | ||||
| { | ||||
| 	return (inode->i_crypt_info != NULL); | ||||
| } | ||||
| 
 | ||||
| static inline bool fscrypt_dummy_context_enabled(struct inode *inode) | ||||
| { | ||||
| 	return inode->i_sb->s_cop->dummy_context && | ||||
| 		inode->i_sb->s_cop->dummy_context(inode); | ||||
| } | ||||
| 
 | ||||
| /* crypto.c */ | ||||
| extern struct kmem_cache *fscrypt_info_cachep; | ||||
| extern struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *, gfp_t); | ||||
| extern void fscrypt_release_ctx(struct fscrypt_ctx *); | ||||
| extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *, | ||||
| @ -20,6 +66,12 @@ extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *, | ||||
| 						u64, gfp_t); | ||||
| extern int fscrypt_decrypt_page(const struct inode *, struct page *, unsigned int, | ||||
| 				unsigned int, u64); | ||||
| 
 | ||||
| static inline struct page *fscrypt_control_page(struct page *page) | ||||
| { | ||||
| 	return ((struct fscrypt_ctx *)page_private(page))->w.control_page; | ||||
| } | ||||
| 
 | ||||
| extern void fscrypt_restore_control_page(struct page *); | ||||
| 
 | ||||
| extern const struct dentry_operations fscrypt_d_ops; | ||||
| @ -44,7 +96,7 @@ extern int fscrypt_inherit_context(struct inode *, struct inode *, | ||||
| 					void *, bool); | ||||
| /* keyinfo.c */ | ||||
| extern int fscrypt_get_encryption_info(struct inode *); | ||||
| extern void fscrypt_put_encryption_info(struct inode *, struct fscrypt_info *); | ||||
| extern void fscrypt_put_encryption_info(struct inode *); | ||||
| 
 | ||||
| /* fname.c */ | ||||
| extern int fscrypt_setup_filename(struct inode *, const struct qstr *, | ||||
| @ -55,14 +107,11 @@ static inline void fscrypt_free_filename(struct fscrypt_name *fname) | ||||
| 	kfree(fname->crypto_buf.name); | ||||
| } | ||||
| 
 | ||||
| extern u32 fscrypt_fname_encrypted_size(const struct inode *, u32); | ||||
| extern int fscrypt_fname_alloc_buffer(const struct inode *, u32, | ||||
| 				struct fscrypt_str *); | ||||
| extern void fscrypt_fname_free_buffer(struct fscrypt_str *); | ||||
| extern int fscrypt_fname_disk_to_usr(struct inode *, u32, u32, | ||||
| 			const struct fscrypt_str *, struct fscrypt_str *); | ||||
| extern int fscrypt_fname_usr_to_disk(struct inode *, const struct qstr *, | ||||
| 			struct fscrypt_str *); | ||||
| 
 | ||||
| #define FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE	32 | ||||
| 
 | ||||
| @ -153,5 +202,14 @@ extern int __fscrypt_prepare_rename(struct inode *old_dir, | ||||
| 				    struct dentry *new_dentry, | ||||
| 				    unsigned int flags); | ||||
| extern int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry); | ||||
| extern int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len, | ||||
| 				     unsigned int max_len, | ||||
| 				     struct fscrypt_str *disk_link); | ||||
| extern int __fscrypt_encrypt_symlink(struct inode *inode, const char *target, | ||||
| 				     unsigned int len, | ||||
| 				     struct fscrypt_str *disk_link); | ||||
| extern const char *fscrypt_get_symlink(struct inode *inode, const void *caddr, | ||||
| 				       unsigned int max_size, | ||||
| 				       struct delayed_call *done); | ||||
| 
 | ||||
| #endif	/* _LINUX_FSCRYPT_SUPP_H */ | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user