dm: use blkdev_get rather than bdgrab when issuing pass-through ioctl
Otherwise an underlying device's teardown (e.g. SCSI) may race with the DM ioctl or persistent reservation and result in dereferencing driver memory that gets freed when the underlying device's final blkdev_put() occurs. bdgrab() only increases the refcount for the block_device's inode to ensure the block_device struct itself will not be freed, but does not guarantee the block_device will remain associated with the gendisk or its storage. Cc: stable@vger.kernel.org # 4.8+ Reported-by: David Jeffery <djeffery@redhat.com> Suggested-by: David Jeffery <djeffery@redhat.com> Reviewed-by: Ben Marzinski <bmarzins@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
This commit is contained in:
parent
590347e400
commit
519049afea
|
@ -458,7 +458,9 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
|
||||||
return dm_get_geometry(md, geo);
|
return dm_get_geometry(md, geo);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dm_grab_bdev_for_ioctl(struct mapped_device *md,
|
static char *_dm_claim_ptr = "I belong to device-mapper";
|
||||||
|
|
||||||
|
static int dm_get_bdev_for_ioctl(struct mapped_device *md,
|
||||||
struct block_device **bdev,
|
struct block_device **bdev,
|
||||||
fmode_t *mode)
|
fmode_t *mode)
|
||||||
{
|
{
|
||||||
|
@ -490,6 +492,10 @@ static int dm_grab_bdev_for_ioctl(struct mapped_device *md,
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
bdgrab(*bdev);
|
bdgrab(*bdev);
|
||||||
|
r = blkdev_get(*bdev, *mode, _dm_claim_ptr);
|
||||||
|
if (r < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
dm_put_live_table(md, srcu_idx);
|
dm_put_live_table(md, srcu_idx);
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -508,7 +514,7 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
|
||||||
struct mapped_device *md = bdev->bd_disk->private_data;
|
struct mapped_device *md = bdev->bd_disk->private_data;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = dm_grab_bdev_for_ioctl(md, &bdev, &mode);
|
r = dm_get_bdev_for_ioctl(md, &bdev, &mode);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -528,7 +534,7 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
|
||||||
|
|
||||||
r = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
|
r = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
|
||||||
out:
|
out:
|
||||||
bdput(bdev);
|
blkdev_put(bdev, mode);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -708,14 +714,13 @@ static void dm_put_live_table_fast(struct mapped_device *md) __releases(RCU)
|
||||||
static int open_table_device(struct table_device *td, dev_t dev,
|
static int open_table_device(struct table_device *td, dev_t dev,
|
||||||
struct mapped_device *md)
|
struct mapped_device *md)
|
||||||
{
|
{
|
||||||
static char *_claim_ptr = "I belong to device-mapper";
|
|
||||||
struct block_device *bdev;
|
struct block_device *bdev;
|
||||||
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
BUG_ON(td->dm_dev.bdev);
|
BUG_ON(td->dm_dev.bdev);
|
||||||
|
|
||||||
bdev = blkdev_get_by_dev(dev, td->dm_dev.mode | FMODE_EXCL, _claim_ptr);
|
bdev = blkdev_get_by_dev(dev, td->dm_dev.mode | FMODE_EXCL, _dm_claim_ptr);
|
||||||
if (IS_ERR(bdev))
|
if (IS_ERR(bdev))
|
||||||
return PTR_ERR(bdev);
|
return PTR_ERR(bdev);
|
||||||
|
|
||||||
|
@ -3011,7 +3016,7 @@ static int dm_pr_reserve(struct block_device *bdev, u64 key, enum pr_type type,
|
||||||
fmode_t mode;
|
fmode_t mode;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = dm_grab_bdev_for_ioctl(md, &bdev, &mode);
|
r = dm_get_bdev_for_ioctl(md, &bdev, &mode);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -3021,7 +3026,7 @@ static int dm_pr_reserve(struct block_device *bdev, u64 key, enum pr_type type,
|
||||||
else
|
else
|
||||||
r = -EOPNOTSUPP;
|
r = -EOPNOTSUPP;
|
||||||
|
|
||||||
bdput(bdev);
|
blkdev_put(bdev, mode);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3032,7 +3037,7 @@ static int dm_pr_release(struct block_device *bdev, u64 key, enum pr_type type)
|
||||||
fmode_t mode;
|
fmode_t mode;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = dm_grab_bdev_for_ioctl(md, &bdev, &mode);
|
r = dm_get_bdev_for_ioctl(md, &bdev, &mode);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -3042,7 +3047,7 @@ static int dm_pr_release(struct block_device *bdev, u64 key, enum pr_type type)
|
||||||
else
|
else
|
||||||
r = -EOPNOTSUPP;
|
r = -EOPNOTSUPP;
|
||||||
|
|
||||||
bdput(bdev);
|
blkdev_put(bdev, mode);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3054,7 +3059,7 @@ static int dm_pr_preempt(struct block_device *bdev, u64 old_key, u64 new_key,
|
||||||
fmode_t mode;
|
fmode_t mode;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = dm_grab_bdev_for_ioctl(md, &bdev, &mode);
|
r = dm_get_bdev_for_ioctl(md, &bdev, &mode);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -3064,7 +3069,7 @@ static int dm_pr_preempt(struct block_device *bdev, u64 old_key, u64 new_key,
|
||||||
else
|
else
|
||||||
r = -EOPNOTSUPP;
|
r = -EOPNOTSUPP;
|
||||||
|
|
||||||
bdput(bdev);
|
blkdev_put(bdev, mode);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3075,7 +3080,7 @@ static int dm_pr_clear(struct block_device *bdev, u64 key)
|
||||||
fmode_t mode;
|
fmode_t mode;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = dm_grab_bdev_for_ioctl(md, &bdev, &mode);
|
r = dm_get_bdev_for_ioctl(md, &bdev, &mode);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
@ -3085,7 +3090,7 @@ static int dm_pr_clear(struct block_device *bdev, u64 key)
|
||||||
else
|
else
|
||||||
r = -EOPNOTSUPP;
|
r = -EOPNOTSUPP;
|
||||||
|
|
||||||
bdput(bdev);
|
blkdev_put(bdev, mode);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue