aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Rosenberg <drosenberg@vsecurity.com>2011-02-14 16:04:23 -0500
committerChris Mason <chris.mason@oracle.com>2011-02-14 16:04:23 -0500
commit51788b1bdd0d68345bab0af4301e7fa429277228 (patch)
tree52895ef3c348c2dfa1f1ef2c4557d9f7515dfc3b
parent6848ad6461e551849ba3c32d945d4f45e96453a6 (diff)
btrfs: prevent heap corruption in btrfs_ioctl_space_info()
Commit bf5fc093c5b625e4259203f1cee7ca73488a5620 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: Dan Rosenberg <drosenberg@vsecurity.com> Signed-off-by: Josef Bacik <josef@redhat.com> Reviewed-by: Josef Bacik <josef@redhat.com> Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r--fs/btrfs/ioctl.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 02d224e8c83f..be2d4f6aaa5e 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2208,7 +2208,7 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
2208 int num_types = 4; 2208 int num_types = 4;
2209 int alloc_size; 2209 int alloc_size;
2210 int ret = 0; 2210 int ret = 0;
2211 int slot_count = 0; 2211 u64 slot_count = 0;
2212 int i, c; 2212 int i, c;
2213 2213
2214 if (copy_from_user(&space_args, 2214 if (copy_from_user(&space_args,
@@ -2247,7 +2247,7 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
2247 goto out; 2247 goto out;
2248 } 2248 }
2249 2249
2250 slot_count = min_t(int, space_args.space_slots, slot_count); 2250 slot_count = min_t(u64, space_args.space_slots, slot_count);
2251 2251
2252 alloc_size = sizeof(*dest) * slot_count; 2252 alloc_size = sizeof(*dest) * slot_count;
2253 2253
@@ -2267,6 +2267,9 @@ long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg)
2267 for (i = 0; i < num_types; i++) { 2267 for (i = 0; i < num_types; i++) {
2268 struct btrfs_space_info *tmp; 2268 struct btrfs_space_info *tmp;
2269 2269
2270 if (!slot_count)
2271 break;
2272
2270 info = NULL; 2273 info = NULL;
2271 rcu_read_lock(); 2274 rcu_read_lock();
2272 list_for_each_entry_rcu(tmp, &root->fs_info->space_info, 2275 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 memcpy(dest, &space, sizeof(space)); 2291 memcpy(dest, &space, sizeof(space));
2289 dest++; 2292 dest++;
2290 space_args.total_spaces++; 2293 space_args.total_spaces++;
2294 slot_count--;
2291 } 2295 }
2296 if (!slot_count)
2297 break;
2292 } 2298 }
2293 up_read(&info->groups_sem); 2299 up_read(&info->groups_sem);
2294 } 2300 }