summaryrefslogtreecommitdiff
path: root/fs/verity/enable.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/verity/enable.c')
-rw-r--r--fs/verity/enable.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/fs/verity/enable.c b/fs/verity/enable.c
index 7a0e3a84d370..fc4c50e5219d 100644
--- a/fs/verity/enable.c
+++ b/fs/verity/enable.c
@@ -13,6 +13,7 @@
struct block_buffer {
u32 filled;
+ bool is_root_hash;
u8 *data;
};
@@ -24,6 +25,14 @@ static int hash_one_block(struct inode *inode,
struct block_buffer *next = cur + 1;
int err;
+ /*
+ * Safety check to prevent a buffer overflow in case of a filesystem bug
+ * that allows the file size to change despite deny_write_access(), or a
+ * bug in the Merkle tree logic itself
+ */
+ if (WARN_ON_ONCE(next->is_root_hash && next->filled != 0))
+ return -EINVAL;
+
/* Zero-pad the block if it's shorter than the block size. */
memset(&cur->data[cur->filled], 0, params->block_size - cur->filled);
@@ -97,6 +106,7 @@ static int build_merkle_tree(struct file *filp,
}
}
buffers[num_levels].data = root_hash;
+ buffers[num_levels].is_root_hash = true;
BUILD_BUG_ON(sizeof(level_offset) != sizeof(params->level_start));
memcpy(level_offset, params->level_start, sizeof(level_offset));
@@ -165,7 +175,7 @@ static int build_merkle_tree(struct file *filp,
}
}
/* The root hash was filled by the last call to hash_one_block(). */
- if (WARN_ON(buffers[num_levels].filled != params->digest_size)) {
+ if (WARN_ON_ONCE(buffers[num_levels].filled != params->digest_size)) {
err = -EINVAL;
goto out;
}
@@ -277,7 +287,7 @@ static int enable_verity(struct file *filp,
fsverity_err(inode, "%ps() failed with err %d",
vops->end_enable_verity, err);
fsverity_free_info(vi);
- } else if (WARN_ON(!IS_VERITY(inode))) {
+ } else if (WARN_ON_ONCE(!IS_VERITY(inode))) {
err = -EINVAL;
fsverity_free_info(vi);
} else {
@@ -347,6 +357,13 @@ int fsverity_ioctl_enable(struct file *filp, const void __user *uarg)
err = file_permission(filp, MAY_WRITE);
if (err)
return err;
+ /*
+ * __kernel_read() is used while building the Merkle tree. So, we can't
+ * allow file descriptors that were opened for ioctl access only, using
+ * the special nonstandard access mode 3. O_RDONLY only, please!
+ */
+ if (!(filp->f_mode & FMODE_READ))
+ return -EBADF;
if (IS_APPEND(inode))
return -EPERM;