diff options
Diffstat (limited to 'fs/crypto/hooks.c')
| -rw-r--r-- | fs/crypto/hooks.c | 55 | 
1 files changed, 31 insertions, 24 deletions
| diff --git a/fs/crypto/hooks.c b/fs/crypto/hooks.c index 20b0df47fe6a..79570e0e8e61 100644 --- a/fs/crypto/hooks.c +++ b/fs/crypto/hooks.c @@ -54,15 +54,12 @@ EXPORT_SYMBOL_GPL(fscrypt_file_open);  int __fscrypt_prepare_link(struct inode *inode, struct inode *dir,  			   struct dentry *dentry)  { -	int err; - -	err = fscrypt_require_key(dir); -	if (err) -		return err; - -	/* ... in case we looked up no-key name before key was added */ -	if (dentry->d_flags & DCACHE_NOKEY_NAME) +	if (fscrypt_is_nokey_name(dentry))  		return -ENOKEY; +	/* +	 * We don't need to separately check that the directory inode's key is +	 * available, as it's implied by the dentry not being a no-key name. +	 */  	if (!fscrypt_has_permitted_context(dir, inode))  		return -EXDEV; @@ -75,19 +72,13 @@ int __fscrypt_prepare_rename(struct inode *old_dir, struct dentry *old_dentry,  			     struct inode *new_dir, struct dentry *new_dentry,  			     unsigned int flags)  { -	int err; - -	err = fscrypt_require_key(old_dir); -	if (err) -		return err; - -	err = fscrypt_require_key(new_dir); -	if (err) -		return err; - -	/* ... in case we looked up no-key name(s) before key was added */ -	if ((old_dentry->d_flags | new_dentry->d_flags) & DCACHE_NOKEY_NAME) +	if (fscrypt_is_nokey_name(old_dentry) || +	    fscrypt_is_nokey_name(new_dentry))  		return -ENOKEY; +	/* +	 * We don't need to separately check that the directory inodes' keys are +	 * available, as it's implied by the dentries not being no-key names. +	 */  	if (old_dir != new_dir) {  		if (IS_ENCRYPTED(new_dir) && @@ -123,6 +114,20 @@ int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry,  }  EXPORT_SYMBOL_GPL(__fscrypt_prepare_lookup); +int __fscrypt_prepare_readdir(struct inode *dir) +{ +	return fscrypt_get_encryption_info(dir, true); +} +EXPORT_SYMBOL_GPL(__fscrypt_prepare_readdir); + +int __fscrypt_prepare_setattr(struct dentry *dentry, struct iattr *attr) +{ +	if (attr->ia_valid & ATTR_SIZE) +		return fscrypt_require_key(d_inode(dentry)); +	return 0; +} +EXPORT_SYMBOL_GPL(__fscrypt_prepare_setattr); +  /**   * fscrypt_prepare_setflags() - prepare to change flags with FS_IOC_SETFLAGS   * @inode: the inode on which flags are being changed @@ -138,6 +143,7 @@ int fscrypt_prepare_setflags(struct inode *inode,  			     unsigned int oldflags, unsigned int flags)  {  	struct fscrypt_info *ci; +	struct key *key;  	struct fscrypt_master_key *mk;  	int err; @@ -153,13 +159,14 @@ int fscrypt_prepare_setflags(struct inode *inode,  		ci = inode->i_crypt_info;  		if (ci->ci_policy.version != FSCRYPT_POLICY_V2)  			return -EINVAL; -		mk = ci->ci_master_key->payload.data[0]; -		down_read(&mk->mk_secret_sem); +		key = ci->ci_master_key; +		mk = key->payload.data[0]; +		down_read(&key->sem);  		if (is_master_key_secret_present(&mk->mk_secret))  			err = fscrypt_derive_dirhash_key(ci, mk);  		else  			err = -ENOKEY; -		up_read(&mk->mk_secret_sem); +		up_read(&key->sem);  		return err;  	}  	return 0; @@ -325,7 +332,7 @@ const char *fscrypt_get_symlink(struct inode *inode, const void *caddr,  	 * 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); +	err = fscrypt_get_encryption_info(inode, false);  	if (err)  		return ERR_PTR(err);  	has_key = fscrypt_has_encryption_key(inode); | 
