summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorMing Lei <tom.leiming@gmail.com>2026-05-06 16:22:38 +0800
committerJens Axboe <axboe@kernel.dk>2026-05-06 04:42:06 -0600
commit86f33ca9bea30cf011f2b1edad4593faea9c6e98 (patch)
tree96b349eba95eaf2ecd5b82156ce844fb2ce5173f /drivers
parent212ec34e4e726e8cd4af7bea4740db24de8a9dab (diff)
ublk: validate physical_bs_shift, io_min_shift and io_opt_shift
ublk_validate_params() checks logical_bs_shift is within [9, PAGE_SHIFT] but has no upper bound for physical_bs_shift, io_min_shift, or io_opt_shift. A malicious userspace can set any of these to a large value (e.g., 44), causing undefined behavior from `1 << shift` in ublk_ctrl_start_dev() since the result is stored in 32-bit unsigned int. Cap all three at ilog2(SZ_256M) (28). 256M is big enough to cover all practical block sizes, and originates from the maximum physical block size possible in NVMe (lba_size * (1 + npwg), where npwg is 16-bit). Also zero out ub->params with memset() when copy_from_user() fails or ublk_validate_params() returns error, so that no stale or partial params survive for a subsequent START_DEV to consume. Fixes: 71f28f3136af ("ublk_drv: add io_uring based userspace block driver") Signed-off-by: Ming Lei <tom.leiming@gmail.com> Link: https://patch.msgid.link/20260506082238.22363-1-tom.leiming@gmail.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/ublk_drv.c18
1 files changed, 17 insertions, 1 deletions
diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c
index d10460d29e4a..57ec900f0ce0 100644
--- a/drivers/block/ublk_drv.c
+++ b/drivers/block/ublk_drv.c
@@ -900,6 +900,20 @@ static int ublk_validate_params(const struct ublk_device *ub)
if (p->logical_bs_shift > PAGE_SHIFT || p->logical_bs_shift < 9)
return -EINVAL;
+ /*
+ * 256M is a reasonable upper bound for physical block size,
+ * io_min and io_opt; it aligns with the maximum physical
+ * block size possible in NVMe.
+ */
+ if (p->physical_bs_shift > ilog2(SZ_256M))
+ return -EINVAL;
+
+ if (p->io_min_shift > ilog2(SZ_256M))
+ return -EINVAL;
+
+ if (p->io_opt_shift > ilog2(SZ_256M))
+ return -EINVAL;
+
if (p->logical_bs_shift > p->physical_bs_shift)
return -EINVAL;
@@ -4992,13 +5006,15 @@ static int ublk_ctrl_set_params(struct ublk_device *ub,
*/
ret = -EACCES;
} else if (copy_from_user(&ub->params, argp, ph.len)) {
+ /* zero out partial copy so no stale params survive */
+ memset(&ub->params, 0, sizeof(ub->params));
ret = -EFAULT;
} else {
/* clear all we don't support yet */
ub->params.types &= UBLK_PARAM_TYPE_ALL;
ret = ublk_validate_params(ub);
if (ret)
- ub->params.types = 0;
+ memset(&ub->params, 0, sizeof(ub->params));
}
mutex_unlock(&ub->mutex);