[PATCH RFC 3/5] block: validate bio bounds in the queue entered context
Damien Le Moal
dlemoal at kernel.org
Wed May 20 00:22:42 PDT 2026
On 2026/05/19 19:23, Keith Busch wrote:
> From: Keith Busch <kbusch at kernel.org>
>
> bio_check_eod() in submit_bio_noacct() validates that a bio does not
> extend beyond the partition's available sectors. This check runs before
> bio_queue_enter(), so it is not serialized against queue limit updates.
> A driver that freezes the queue, updates limits, changes the capacity,
> and unfreezes can race with a bio that passed the early check under the
> old capacity.
>
> Remove bio_check_eod() and replace it with a bounds check in
> __bio_split_to_limits(), which runs after the queue usage reference has
> been acquired. The check uses partition-aware arithmetic to validate
> both partition bounds and disk capacity in a single comparison that
> works correctly on the post-remap sector values.
>
> Signed-off-by: Keith Busch <kbusch at kernel.org>
[...]
> @@ -423,6 +423,17 @@ static inline bool bio_may_need_split(struct bio *bio,
> static inline struct bio *__bio_split_to_limits(struct bio *bio,
> const struct queue_limits *lim, unsigned int *nr_segs)
> {
> + if (unlikely(bio_end_sector(bio) > bdev_nr_sectors(bio->bi_bdev) +
> + bio->bi_bdev->bd_start_sect)) {
> + pr_info_ratelimited("%s: attempt to access beyond end of device\n"
> + "%pg: rw=%d, sector=%llu, nr_sectors = %u limit=%llu\n",
> + current->comm, bio->bi_bdev, bio->bi_opf,
> + bio->bi_iter.bi_sector, bio_sectors(bio),
> + bdev_nr_sectors(bio->bi_bdev) +
> + bio->bi_bdev->bd_start_sect);
Should this be a pr_err_ratelimited() ?
Also, putting this check here means that we are going to redo the check for all
the fragment of the large BIO being split, no ? It would be nice to be able to
do this check only once when the large BIO is submitted.
Moving this check to a helper and calling this new helper higher in the
submission path could avoid that. But I am not 100% sure if a higher placed call
can be a problem.
> + goto ioerr;
> + }
> +
> switch (bio_op(bio)) {
> case REQ_OP_READ:
> case REQ_OP_WRITE:
> @@ -442,6 +453,9 @@ static inline struct bio *__bio_split_to_limits(struct bio *bio,
> *nr_segs = 0;
> return bio;
> }
> +ioerr:
> + bio_io_error(bio);
> + return NULL;
> }
>
> /**
--
Damien Le Moal
Western Digital Research
More information about the Linux-nvme
mailing list