[PATCH v2 11/20] btrfs: disable various operations on encrypted inodes

Sweet Tea Dorminy
2022-09-06T00:36:05Z

From: Omar Sandoval <osandov@osandov.com>

Initially, only normal data extents, using the normal (non-direct) IO
path, will be encrypted. This change forbids various other bits:
- allows reflinking only if both inodes have the same encryption status
- disables compressing encrypted inodes
- disables direct IO on encrypted inodes
- disable inline data on encrypted inodes

Signed-off-by: Omar Sandoval <osandov@osandov.com>
Signed-off-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
---
fs/btrfs/btrfs_inode.h | 3 +++
fs/btrfs/file.c | 4 ++--
fs/btrfs/inode.c | 3 ++-
fs/btrfs/reflink.c | 7 +++++++
4 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index b160b8e124e0..ff668686717b 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -400,6 +400,9 @@ static inline bool btrfs_inode_in_log(struct btrfs_inode *inode, u64 generation)
*/
static inline bool btrfs_inode_can_compress(const struct btrfs_inode *inode)
{
+ if (IS_ENCRYPTED(&inode->vfs_inode))
+ return false;
+
if (inode->flags & BTRFS_INODE_NODATACOW ||
inode->flags & BTRFS_INODE_NODATASUM)
return false;
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 0a76ae8b8e96..7216ac1f860c 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1895,7 +1895,7 @@ static ssize_t btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from)
goto relock;
}

- if (check_direct_IO(fs_info, from, pos)) {
+ if (IS_ENCRYPTED(inode) || check_direct_IO(fs_info, from, pos)) {
btrfs_inode_unlock(inode, ilock_flags);
goto buffered;
}
@@ -3729,7 +3729,7 @@ static ssize_t btrfs_direct_read(struct kiocb *iocb, struct iov_iter *to)
ssize_t read = 0;
ssize_t ret;

- if (fsverity_active(inode))
+ if (IS_ENCRYPTED(inode) || fsverity_active(inode))
return 0;

if (check_direct_read(btrfs_sb(inode->i_sb), to, iocb->ki_pos))
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 482c5b3d9e70..fea48c12a33a 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -409,7 +409,8 @@ static noinline int cow_file_range_inline(struct btrfs_inode *inode, u64 size,
* compressed) data fits in a leaf and the configured maximum inline
* size.
*/
- if (size < i_size_read(&inode->vfs_inode) ||
+ if (IS_ENCRYPTED(&inode->vfs_inode) ||
+ size < i_size_read(&inode->vfs_inode) ||
size > fs_info->sectorsize ||
data_len > BTRFS_MAX_INLINE_DATA_SIZE(fs_info) ||
data_len > fs_info->max_inline)
diff --git a/fs/btrfs/reflink.c b/fs/btrfs/reflink.c
index 9acf47b11fe6..d22086e1cbc8 100644
--- a/fs/btrfs/reflink.c
+++ b/fs/btrfs/reflink.c
@@ -805,6 +805,13 @@ static int btrfs_remap_file_range_prep(struct file *file_in, loff_t pos_in,
ASSERT(inode_in->i_sb == inode_out->i_sb);
}

+ /*
+ * Can only reflink encrypted files if both files are encrypted.
+ */
+ if (!fscrypt_have_same_policy(inode_in, inode_out)) {
+ return -EINVAL;
+ }
+
/* Don't make the dst file partly checksummed */
if ((BTRFS_I(inode_in)->flags & BTRFS_INODE_NODATASUM) !=
(BTRFS_I(inode_out)->flags & BTRFS_INODE_NODATASUM)) {
--
2.35.1