Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a6b0d5c8 authored by Chris Mason's avatar Chris Mason
Browse files

Btrfs: make sure we update latest_bdev



When we are setting up the mount, we close all the
devices that were not actually part of the metadata we found.

But, we don't make sure that one of those devices wasn't
fs_devices->latest_bdev, which means we can do a use after free
on the one we closed.

This updates latest_bdev as it goes.

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent fe66a05a
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -2305,6 +2305,12 @@ struct btrfs_root *open_ctree(struct super_block *sb,

	btrfs_close_extra_devices(fs_devices);

	if (!fs_devices->latest_bdev) {
		printk(KERN_CRIT "btrfs: failed to read devices on %s\n",
		       sb->s_id);
		goto fail_tree_roots;
	}

retry_root_backup:
	blocksize = btrfs_level_size(tree_root,
				     btrfs_super_root_level(disk_super));
+16 −1
Original line number Diff line number Diff line
@@ -459,12 +459,23 @@ int btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices)
{
	struct btrfs_device *device, *next;

	struct block_device *latest_bdev = NULL;
	u64 latest_devid = 0;
	u64 latest_transid = 0;

	mutex_lock(&uuid_mutex);
again:
	/* This is the initialized path, it is safe to release the devices. */
	list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) {
		if (device->in_fs_metadata)
		if (device->in_fs_metadata) {
			if (!latest_transid ||
			    device->generation > latest_transid) {
				latest_devid = device->devid;
				latest_transid = device->generation;
				latest_bdev = device->bdev;
			}
			continue;
		}

		if (device->bdev) {
			blkdev_put(device->bdev, device->mode);
@@ -487,6 +498,10 @@ int btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices)
		goto again;
	}

	fs_devices->latest_bdev = latest_bdev;
	fs_devices->latest_devid = latest_devid;
	fs_devices->latest_trans = latest_transid;

	mutex_unlock(&uuid_mutex);
	return 0;
}