Skip to content

Commit 519049a

Browse files
committed
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: [email protected] # 4.8+ Reported-by: David Jeffery <[email protected]> Suggested-by: David Jeffery <[email protected]> Reviewed-by: Ben Marzinski <[email protected]> Signed-off-by: Mike Snitzer <[email protected]>
1 parent 590347e commit 519049a

File tree

1 file changed

+20
-15
lines changed

1 file changed

+20
-15
lines changed

drivers/md/dm.c

+20-15
Original file line numberDiff line numberDiff line change
@@ -458,9 +458,11 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
458458
return dm_get_geometry(md, geo);
459459
}
460460

461-
static int dm_grab_bdev_for_ioctl(struct mapped_device *md,
462-
struct block_device **bdev,
463-
fmode_t *mode)
461+
static char *_dm_claim_ptr = "I belong to device-mapper";
462+
463+
static int dm_get_bdev_for_ioctl(struct mapped_device *md,
464+
struct block_device **bdev,
465+
fmode_t *mode)
464466
{
465467
struct dm_target *tgt;
466468
struct dm_table *map;
@@ -490,6 +492,10 @@ static int dm_grab_bdev_for_ioctl(struct mapped_device *md,
490492
goto out;
491493

492494
bdgrab(*bdev);
495+
r = blkdev_get(*bdev, *mode, _dm_claim_ptr);
496+
if (r < 0)
497+
goto out;
498+
493499
dm_put_live_table(md, srcu_idx);
494500
return r;
495501

@@ -508,7 +514,7 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
508514
struct mapped_device *md = bdev->bd_disk->private_data;
509515
int r;
510516

511-
r = dm_grab_bdev_for_ioctl(md, &bdev, &mode);
517+
r = dm_get_bdev_for_ioctl(md, &bdev, &mode);
512518
if (r < 0)
513519
return r;
514520

@@ -528,7 +534,7 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
528534

529535
r = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
530536
out:
531-
bdput(bdev);
537+
blkdev_put(bdev, mode);
532538
return r;
533539
}
534540

@@ -708,14 +714,13 @@ static void dm_put_live_table_fast(struct mapped_device *md) __releases(RCU)
708714
static int open_table_device(struct table_device *td, dev_t dev,
709715
struct mapped_device *md)
710716
{
711-
static char *_claim_ptr = "I belong to device-mapper";
712717
struct block_device *bdev;
713718

714719
int r;
715720

716721
BUG_ON(td->dm_dev.bdev);
717722

718-
bdev = blkdev_get_by_dev(dev, td->dm_dev.mode | FMODE_EXCL, _claim_ptr);
723+
bdev = blkdev_get_by_dev(dev, td->dm_dev.mode | FMODE_EXCL, _dm_claim_ptr);
719724
if (IS_ERR(bdev))
720725
return PTR_ERR(bdev);
721726

@@ -3011,7 +3016,7 @@ static int dm_pr_reserve(struct block_device *bdev, u64 key, enum pr_type type,
30113016
fmode_t mode;
30123017
int r;
30133018

3014-
r = dm_grab_bdev_for_ioctl(md, &bdev, &mode);
3019+
r = dm_get_bdev_for_ioctl(md, &bdev, &mode);
30153020
if (r < 0)
30163021
return r;
30173022

@@ -3021,7 +3026,7 @@ static int dm_pr_reserve(struct block_device *bdev, u64 key, enum pr_type type,
30213026
else
30223027
r = -EOPNOTSUPP;
30233028

3024-
bdput(bdev);
3029+
blkdev_put(bdev, mode);
30253030
return r;
30263031
}
30273032

@@ -3032,7 +3037,7 @@ static int dm_pr_release(struct block_device *bdev, u64 key, enum pr_type type)
30323037
fmode_t mode;
30333038
int r;
30343039

3035-
r = dm_grab_bdev_for_ioctl(md, &bdev, &mode);
3040+
r = dm_get_bdev_for_ioctl(md, &bdev, &mode);
30363041
if (r < 0)
30373042
return r;
30383043

@@ -3042,7 +3047,7 @@ static int dm_pr_release(struct block_device *bdev, u64 key, enum pr_type type)
30423047
else
30433048
r = -EOPNOTSUPP;
30443049

3045-
bdput(bdev);
3050+
blkdev_put(bdev, mode);
30463051
return r;
30473052
}
30483053

@@ -3054,7 +3059,7 @@ static int dm_pr_preempt(struct block_device *bdev, u64 old_key, u64 new_key,
30543059
fmode_t mode;
30553060
int r;
30563061

3057-
r = dm_grab_bdev_for_ioctl(md, &bdev, &mode);
3062+
r = dm_get_bdev_for_ioctl(md, &bdev, &mode);
30583063
if (r < 0)
30593064
return r;
30603065

@@ -3064,7 +3069,7 @@ static int dm_pr_preempt(struct block_device *bdev, u64 old_key, u64 new_key,
30643069
else
30653070
r = -EOPNOTSUPP;
30663071

3067-
bdput(bdev);
3072+
blkdev_put(bdev, mode);
30683073
return r;
30693074
}
30703075

@@ -3075,7 +3080,7 @@ static int dm_pr_clear(struct block_device *bdev, u64 key)
30753080
fmode_t mode;
30763081
int r;
30773082

3078-
r = dm_grab_bdev_for_ioctl(md, &bdev, &mode);
3083+
r = dm_get_bdev_for_ioctl(md, &bdev, &mode);
30793084
if (r < 0)
30803085
return r;
30813086

@@ -3085,7 +3090,7 @@ static int dm_pr_clear(struct block_device *bdev, u64 key)
30853090
else
30863091
r = -EOPNOTSUPP;
30873092

3088-
bdput(bdev);
3093+
blkdev_put(bdev, mode);
30893094
return r;
30903095
}
30913096

0 commit comments

Comments
 (0)