mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-15 23:41:35 -04:00
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: 71f28f3136 ("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>
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user