btrfs-progs: check if adding device would overflow while scanning

It's theoretically possible to add multiple devices with sizes that add up
to or exceed 16EiB.  A file system will be created successfully but will
have a superblock with incorrect values for total_bytes and other fields.

Kernels up to v5.0 will crash when they encounter this scenario.

We need to check for overflow and reject the device if it would overflow.

Bugzilla: https://bugzilla.suse.com/show_bug.cgi?id=1099147
Reviewed-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
master
Jeff Mahoney 2019-08-13 21:03:59 -04:00 committed by David Sterba
parent 391b891278
commit d29f475108
1 changed files with 12 additions and 3 deletions

View File

@ -26,6 +26,7 @@
#include <linux/limits.h>
#include <blkid/blkid.h>
#include <uuid/uuid.h>
#include "kernel-lib/overflow.h"
#include "common/path-utils.h"
#include "common/device-scan.h"
#include "common/messages.h"
@ -118,7 +119,8 @@ int btrfs_add_to_fsid(struct btrfs_trans_handle *trans,
struct btrfs_device *device;
struct btrfs_dev_item *dev_item;
char *buf = NULL;
u64 fs_total_bytes;
const u64 old_size = btrfs_super_total_bytes(super);
u64 new_size;
u64 num_devs;
int ret;
@ -156,13 +158,20 @@ int btrfs_add_to_fsid(struct btrfs_trans_handle *trans,
goto out;
}
if (check_add_overflow(old_size, device_total_bytes, &new_size)) {
error(
"adding device of %llu bytes would exceed max file system size",
device->total_bytes);
ret = -EOVERFLOW;
goto out;
}
INIT_LIST_HEAD(&device->dev_list);
ret = btrfs_add_device(trans, fs_info, device);
if (ret)
goto out;
fs_total_bytes = btrfs_super_total_bytes(super) + device_total_bytes;
btrfs_set_super_total_bytes(super, fs_total_bytes);
btrfs_set_super_total_bytes(super, new_size);
num_devs = btrfs_super_num_devices(super) + 1;
btrfs_set_super_num_devices(super, num_devs);