Re: [PATCH v2 07/17] btrfs: adapt readdir for encrypted and nokey names

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Sweet Tea Dorminy <sweettea-kernel@xxxxxxxxxx> writes:

> From: Omar Sandoval <osandov@xxxxxxxxxxx>
> @@ -5793,13 +5787,18 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
>  	struct btrfs_root *root = BTRFS_I(dir)->root;
>  	struct btrfs_root *sub_root = root;
>  	struct btrfs_key location;
> +	struct fscrypt_name fname;
>  	u8 di_type = 0;
>  	int ret = 0;
>  
>  	if (dentry->d_name.len > BTRFS_NAME_LEN)
>  		return ERR_PTR(-ENAMETOOLONG);
>  
> -	ret = btrfs_inode_by_name(BTRFS_I(dir), dentry, &location, &di_type);
> +	ret = fscrypt_prepare_lookup(dir, dentry, &fname);
> +	if (ret)
> +		return ERR_PTR(ret);
> +

I _think_ these error paths below need to be changed in order to invoke
fscrypt_free_lookup().

Cheers,
-- 
Luís

> 
> +	ret = btrfs_inode_by_name(BTRFS_I(dir), &fname, &location, &di_type);
>  	if (ret < 0)
>  		return ERR_PTR(ret);
>  
> @@ -5940,18 +5939,32 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
>  	struct list_head del_list;
>  	int ret;
>  	char *name_ptr;
> -	int name_len;
> +	u32 name_len;
>  	int entries = 0;
>  	int total_len = 0;
>  	bool put = false;
>  	struct btrfs_key location;
> +	struct fscrypt_str fstr = FSTR_INIT(NULL, 0);
> +	u32 fstr_len = 0;
>  
>  	if (!dir_emit_dots(file, ctx))
>  		return 0;
>  
> +	if (BTRFS_I(inode)->flags & BTRFS_INODE_ENCRYPT) {
> +		ret = fscrypt_prepare_readdir(inode);
> +		if (ret)
> +			return ret;
> +		ret = fscrypt_fname_alloc_buffer(BTRFS_NAME_LEN, &fstr);
> +		if (ret)
> +			return ret;
> +		fstr_len = fstr.len;
> +	}
> +
>  	path = btrfs_alloc_path();
> -	if (!path)
> -		return -ENOMEM;
> +	if (!path) {
> +		ret = -ENOMEM;
> +		goto err_fstr;
> +	}
>  
>  	addr = private->filldir_buf;
>  	path->reada = READA_FORWARD;
> @@ -5969,6 +5982,7 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
>  		struct dir_entry *entry;
>  		struct extent_buffer *leaf = path->nodes[0];
>  		u8 ftype;
> +		u32 nokey_len;
>  
>  		if (found_key.objectid != key.objectid)
>  			break;
> @@ -5980,8 +5994,13 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
>  			continue;
>  		di = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item);
>  		name_len = btrfs_dir_name_len(leaf, di);
> -		if ((total_len + sizeof(struct dir_entry) + name_len) >=
> -		    PAGE_SIZE) {
> +		nokey_len = DIV_ROUND_UP(name_len * 4, 3);
> +		/*
> +		 * If name is encrypted, and we don't have the key, we could
> +		 * need up to 4/3rds the bytes to print it.
> +		 */
> +		if ((total_len + sizeof(struct dir_entry) + nokey_len)
> +		    >= PAGE_SIZE) {
>  			btrfs_release_path(path);
>  			ret = btrfs_filldir(private->filldir_buf, entries, ctx);
>  			if (ret)
> @@ -5995,8 +6014,36 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
>  		ftype = btrfs_dir_flags_to_ftype(btrfs_dir_flags(leaf, di));
>  		entry = addr;
>  		name_ptr = (char *)(entry + 1);
> -		read_extent_buffer(leaf, name_ptr,
> -				   (unsigned long)(di + 1), name_len);
> +		if (btrfs_dir_flags(leaf, di) & BTRFS_FT_ENCRYPTED) {
> +			struct fscrypt_str oname = FSTR_INIT(name_ptr,
> +							     nokey_len);
> +			u32 hash = 0, minor_hash = 0;
> +
> +			read_extent_buffer(leaf, fstr.name,
> +					   (unsigned long)(di + 1), name_len);
> +			fstr.len = name_len;
> +			/*
> +			 * We're iterating through DIR_INDEX items, so we don't
> +			 * have the DIR_ITEM hash handy. Only compute it if
> +			 * we'll need it -- the nokey name stores it, so that
> +			 * we can look up the appropriate item by nokey name
> +			 * later on.
> +			 */
> +			if (!fscrypt_has_encryption_key(inode)) {
> +				u64 name_hash = btrfs_name_hash(fstr.name,
> +								fstr.len);
> +				hash = name_hash;
> +				minor_hash = name_hash >> 32;
> +			}
> +			ret = fscrypt_fname_disk_to_usr(inode, hash, minor_hash,
> +							&fstr, &oname);
> +			if (ret)
> +				goto err;
> +			name_len = oname.len;
> +		} else {
> +			read_extent_buffer(leaf, name_ptr,
> +					   (unsigned long)(di + 1), name_len);
> +		}
>  		put_unaligned(name_len, &entry->name_len);
>  		put_unaligned(fs_ftype_to_dtype(ftype), &entry->type);
>  		btrfs_dir_item_key_to_cpu(leaf, di, &location);
> @@ -6016,7 +6063,8 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
>  	if (ret)
>  		goto nopos;
>  
> -	ret = btrfs_readdir_delayed_dir_index(ctx, &ins_list);
> +	fstr.len = fstr_len;
> +	ret = btrfs_readdir_delayed_dir_index(inode, &fstr, ctx, &ins_list);
>  	if (ret)
>  		goto nopos;
>  
> @@ -6047,6 +6095,8 @@ static int btrfs_real_readdir(struct file *file, struct dir_context *ctx)
>  	if (put)
>  		btrfs_readdir_put_delayed_items(inode, &ins_list, &del_list);
>  	btrfs_free_path(path);
> +err_fstr:
> +	fscrypt_fname_free_buffer(&fstr);
>  	return ret;
>  }
>  
> @@ -6555,6 +6605,7 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
>  	struct btrfs_root *root = parent_inode->root;
>  	u64 ino = btrfs_ino(inode);
>  	u64 parent_ino = btrfs_ino(parent_inode);
> +	struct fscrypt_name fname = { .disk_name = *name };
>  
>  	if (unlikely(ino == BTRFS_FIRST_FREE_OBJECTID)) {
>  		memcpy(&key, &inode->root->root_key, sizeof(key));
> @@ -6612,7 +6663,7 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
>  		int err;
>  		err = btrfs_del_root_ref(trans, key.objectid,
>  					 root->root_key.objectid, parent_ino,
> -					 &local_index, name);
> +					 &local_index, &fname);
>  		if (err)
>  			btrfs_abort_transaction(trans, err);
>  	} else if (add_backref) {
> @@ -8982,7 +9033,7 @@ static int btrfs_rename_exchange(struct inode *old_dir,
>  	} else { /* src is an inode */
>  		ret = __btrfs_unlink_inode(trans, BTRFS_I(old_dir),
>  					   BTRFS_I(old_dentry->d_inode),
> -					   old_name, &old_rename_ctx);
> +					   &old_fname, &old_rename_ctx);
>  		if (!ret)
>  			ret = btrfs_update_inode(trans, root, BTRFS_I(old_inode));
>  	}
> @@ -8997,7 +9048,7 @@ static int btrfs_rename_exchange(struct inode *old_dir,
>  	} else { /* dest is an inode */
>  		ret = __btrfs_unlink_inode(trans, BTRFS_I(new_dir),
>  					   BTRFS_I(new_dentry->d_inode),
> -					   new_name, &new_rename_ctx);
> +					   &new_fname, &new_rename_ctx);
>  		if (!ret)
>  			ret = btrfs_update_inode(trans, dest, BTRFS_I(new_inode));
>  	}
> @@ -9246,7 +9297,7 @@ static int btrfs_rename(struct mnt_idmap *idmap,
>  	} else {
>  		ret = __btrfs_unlink_inode(trans, BTRFS_I(old_dir),
>  					   BTRFS_I(d_inode(old_dentry)),
> -					   &old_fname.disk_name, &rename_ctx);
> +					   &old_fname, &rename_ctx);
>  		if (!ret)
>  			ret = btrfs_update_inode(trans, root, BTRFS_I(old_inode));
>  	}
> @@ -9265,7 +9316,7 @@ static int btrfs_rename(struct mnt_idmap *idmap,
>  		} else {
>  			ret = btrfs_unlink_inode(trans, BTRFS_I(new_dir),
>  						 BTRFS_I(d_inode(new_dentry)),
> -						 &new_fname.disk_name);
> +						 &new_fname);
>  		}
>  		if (!ret && new_inode->i_nlink == 0)
>  			ret = btrfs_orphan_add(trans,
> diff --git a/fs/btrfs/root-tree.c b/fs/btrfs/root-tree.c
> index 859874579456..5fa416ef54ad 100644
> --- a/fs/btrfs/root-tree.c
> +++ b/fs/btrfs/root-tree.c
> @@ -10,6 +10,7 @@
>  #include "messages.h"
>  #include "transaction.h"
>  #include "disk-io.h"
> +#include "fscrypt.h"
>  #include "print-tree.h"
>  #include "qgroup.h"
>  #include "space-info.h"
> @@ -333,7 +334,7 @@ int btrfs_del_root(struct btrfs_trans_handle *trans,
>  
>  int btrfs_del_root_ref(struct btrfs_trans_handle *trans, u64 root_id,
>  		       u64 ref_id, u64 dirid, u64 *sequence,
> -		       const struct fscrypt_str *name)
> +		       struct fscrypt_name *name)
>  {
>  	struct btrfs_root *tree_root = trans->fs_info->tree_root;
>  	struct btrfs_path *path;
> @@ -355,13 +356,14 @@ int btrfs_del_root_ref(struct btrfs_trans_handle *trans, u64 root_id,
>  	if (ret < 0) {
>  		goto out;
>  	} else if (ret == 0) {
> +		u32 name_len;
>  		leaf = path->nodes[0];
>  		ref = btrfs_item_ptr(leaf, path->slots[0],
>  				     struct btrfs_root_ref);
>  		ptr = (unsigned long)(ref + 1);
> +		name_len = btrfs_root_ref_name_len(leaf, ref);
>  		if ((btrfs_root_ref_dirid(leaf, ref) != dirid) ||
> -		    (btrfs_root_ref_name_len(leaf, ref) != name->len) ||
> -		    memcmp_extent_buffer(leaf, name->name, ptr, name->len)) {
> +		    !btrfs_fscrypt_match_name(name, leaf, ptr, name_len)) {
>  			ret = -ENOENT;
>  			goto out;
>  		}
> diff --git a/fs/btrfs/root-tree.h b/fs/btrfs/root-tree.h
> index cbbaca32126e..a57bbf7b0180 100644
> --- a/fs/btrfs/root-tree.h
> +++ b/fs/btrfs/root-tree.h
> @@ -13,7 +13,7 @@ int btrfs_add_root_ref(struct btrfs_trans_handle *trans, u64 root_id,
>  		       const struct fscrypt_str *name);
>  int btrfs_del_root_ref(struct btrfs_trans_handle *trans, u64 root_id,
>  		       u64 ref_id, u64 dirid, u64 *sequence,
> -		       const struct fscrypt_str *name);
> +		       struct fscrypt_name *name);
>  int btrfs_del_root(struct btrfs_trans_handle *trans, const struct btrfs_key *key);
>  int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
>  		      const struct btrfs_key *key,
> diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
> index 8ad7e7e38d18..3bf746668e07 100644
> --- a/fs/btrfs/tree-log.c
> +++ b/fs/btrfs/tree-log.c
> @@ -901,9 +901,10 @@ static int unlink_inode_for_log_replay(struct btrfs_trans_handle *trans,
>  				       struct btrfs_inode *inode,
>  				       const struct fscrypt_str *name)
>  {
> +	struct fscrypt_name fname = { .disk_name = *name, };
>  	int ret;
>  
> -	ret = btrfs_unlink_inode(trans, dir, inode, name);
> +	ret = btrfs_unlink_inode(trans, dir, inode, &fname);
>  	if (ret)
>  		return ret;
>  	/*
> -- 
>
> 2.40.1
>




[Index of Archives]     [linux Cryptography]     [Asterisk App Development]     [PJ SIP]     [Gnu Gatekeeper]     [IETF Sipping]     [Info Cyrus]     [ALSA User]     [Fedora Linux Users]     [Linux SCTP]     [DCCP]     [Gimp]     [Yosemite News]     [Deep Creek Hot Springs]     [Yosemite Campsites]     [ISDN Cause Codes]

  Powered by Linux