summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQu Wenruo <quwenruo@cn.fujitsu.com>2015-01-06 17:30:44 +0800
committerDavid Sterba <dsterba@suse.cz>2015-01-09 18:46:16 +0100
commitdbed21e7c20d3f85d6edffe7cd25353af0569278 (patch)
tree3d3f4ce18fce7ab81b26bfe0c87a120e0ab2f6ce
parent74f7b51c749d32f7001faa9492f42c99e42c3b37 (diff)
btrfs-progs: Fix a buffer overflow causing segfault in fstests/btrfs/069
The newly introduced search_chunk_tree_for_fs_info() won't count devid 0 in fi_arg->num_devices, which will cause buffer overflow since later get_device_info() will fill di_args with devid. This can be trigger by fstests/btrfs/069 and any operations needs to iterate over all the devices like 'fi show' or 'dev stat' while replacing. The fix is do an extra probe specifically for devid 0 after search_chunk_tree_for_fs_info() and change num_devices if needed. Reported-by: Tsutomu Itoh <t-itoh@jp.fujitsu.com> Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com> Signed-off-by: Gui Hecheng <guihc.fnst@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.cz>
-rw-r--r--utils.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/utils.c b/utils.c
index 868b15e4..9b08144f 100644
--- a/utils.c
+++ b/utils.c
@@ -1943,8 +1943,10 @@ int get_fs_info(char *path, struct btrfs_ioctl_fs_info_args *fi_args,
int ret = 0;
int ndevs = 0;
int i = 0;
+ int replacing = 0;
struct btrfs_fs_devices *fs_devices_mnt = NULL;
struct btrfs_ioctl_dev_info_args *di_args;
+ struct btrfs_ioctl_dev_info_args tmp;
char mp[BTRFS_PATH_NAME_MAX + 1];
DIR *dirstream = NULL;
@@ -2012,6 +2014,19 @@ int get_fs_info(char *path, struct btrfs_ioctl_fs_info_args *fi_args,
ret = search_chunk_tree_for_fs_info(fd, fi_args);
if (ret)
goto out;
+
+ /*
+ * search_chunk_tree_for_fs_info() will lacks the devid 0
+ * so manual probe for it here.
+ */
+ ret = get_device_info(fd, 0, &tmp);
+ if (!ret) {
+ fi_args->num_devices++;
+ ndevs++;
+ replacing = 1;
+ if (i == 0)
+ i++;
+ }
}
if (!fi_args->num_devices)
@@ -2023,6 +2038,8 @@ int get_fs_info(char *path, struct btrfs_ioctl_fs_info_args *fi_args,
goto out;
}
+ if (replacing)
+ memcpy(di_args, &tmp, sizeof(tmp));
for (; i <= fi_args->max_id; ++i) {
ret = get_device_info(fd, i, &di_args[ndevs]);
if (ret == -ENODEV)