提交 51788b1b 编写于 作者: D Dan Rosenberg 提交者: Chris Mason

btrfs: prevent heap corruption in btrfs_ioctl_space_info()

Commit bf5fc093 refactored
btrfs_ioctl_space_info() and introduced several security issues.

space_args.space_slots is an unsigned 64-bit type controlled by a
possibly unprivileged caller.  The comparison as a signed int type
allows providing values that are treated as negative and cause the
subsequent allocation size calculation to wrap, or be truncated to 0.
By providing a size that's truncated to 0, kmalloc() will return
ZERO_SIZE_PTR.  It's also possible to provide a value smaller than the
slot count.  The subsequent loop ignores the allocation size when
copying data in, resulting in a heap overflow or write to ZERO_SIZE_PTR.

The fix changes the slot count type and comparison typecast to u64,
which prevents truncation or signedness errors, and also ensures that we
don't copy more data than we've allocated in the subsequent loop.  Note
that zero-size allocations are no longer possible since there is already
an explicit check for space_args.space_slots being 0 and truncation of
this value is no longer an issue.
Signed-off-by: NDan Rosenberg <drosenberg@vsecurity.com>
Signed-off-by: NJosef Bacik <josef@redhat.com>
Reviewed-by: NJosef Bacik <josef@redhat.com>
Signed-off-by: NChris Mason <chris.mason@oracle.com>
上级 6848ad64
...@@ -2208,7 +2208,7 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg) ...@@ -2208,7 +2208,7 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
int num_types = 4; int num_types = 4;
int alloc_size; int alloc_size;
int ret = 0; int ret = 0;
int slot_count = 0; u64 slot_count = 0;
int i, c; int i, c;
if (copy_from_user(&space_args, if (copy_from_user(&space_args,
...@@ -2247,7 +2247,7 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg) ...@@ -2247,7 +2247,7 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
goto out; goto out;
} }
slot_count = min_t(int, space_args.space_slots, slot_count); slot_count = min_t(u64, space_args.space_slots, slot_count);
alloc_size = sizeof(*dest) * slot_count; alloc_size = sizeof(*dest) * slot_count;
...@@ -2267,6 +2267,9 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg) ...@@ -2267,6 +2267,9 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
for (i = 0; i < num_types; i++) { for (i = 0; i < num_types; i++) {
struct btrfs_space_info *tmp; struct btrfs_space_info *tmp;
if (!slot_count)
break;
info = NULL; info = NULL;
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(tmp, &root->fs_info->space_info, list_for_each_entry_rcu(tmp, &root->fs_info->space_info,
...@@ -2288,7 +2291,10 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg) ...@@ -2288,7 +2291,10 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
memcpy(dest, &space, sizeof(space)); memcpy(dest, &space, sizeof(space));
dest++; dest++;
space_args.total_spaces++; space_args.total_spaces++;
slot_count--;
} }
if (!slot_count)
break;
} }
up_read(&info->groups_sem); up_read(&info->groups_sem);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册