ublk: enforce ublks_max only for unprivileged devices
[ Upstream commit 80bdfbb3545b6f16680a72c825063d08a6b44c7a ]
Commit 403ebc8778 ("ublk_drv: add module parameter of ublks_max for
limiting max allowed ublk dev"), claimed ublks_max was added to prevent
a DoS situation with an untrusted user creating too many ublk devices.
If that's the case, ublks_max should only restrict the number of
unprivileged ublk devices in the system. Enforce the limit only for
unprivileged ublk devices, and rename variables accordingly. Leave the
external-facing parameter name unchanged, since changing it may break
systems which use it (but still update its documentation to reflect its
new meaning).
As a result of this change, in a system where there are only normal
(non-unprivileged) devices, the maximum number of such devices is
increased to 1 << MINORBITS, or 1048576. That ought to be enough for
anyone, right?
Signed-off-by: Uday Shankar <ushankar@purestorage.com>
Reviewed-by: Ming Lei <ming.lei@redhat.com>
Link: https://lore.kernel.org/r/20250228-ublks_max-v1-1-04b7379190c0@purestorage.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
c4f025a58e
commit
af73c8fd73
+27
-15
@@ -484,15 +484,17 @@ static wait_queue_head_t ublk_idr_wq; /* wait until one idr is freed */
|
|||||||
|
|
||||||
static DEFINE_MUTEX(ublk_ctl_mutex);
|
static DEFINE_MUTEX(ublk_ctl_mutex);
|
||||||
|
|
||||||
|
|
||||||
|
#define UBLK_MAX_UBLKS UBLK_MINORS
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Max ublk devices allowed to add
|
* Max unprivileged ublk devices allowed to add
|
||||||
*
|
*
|
||||||
* It can be extended to one per-user limit in future or even controlled
|
* It can be extended to one per-user limit in future or even controlled
|
||||||
* by cgroup.
|
* by cgroup.
|
||||||
*/
|
*/
|
||||||
#define UBLK_MAX_UBLKS UBLK_MINORS
|
static unsigned int unprivileged_ublks_max = 64;
|
||||||
static unsigned int ublks_max = 64;
|
static unsigned int unprivileged_ublks_added; /* protected by ublk_ctl_mutex */
|
||||||
static unsigned int ublks_added; /* protected by ublk_ctl_mutex */
|
|
||||||
|
|
||||||
static struct miscdevice ublk_misc;
|
static struct miscdevice ublk_misc;
|
||||||
|
|
||||||
@@ -2203,7 +2205,8 @@ static int ublk_add_chdev(struct ublk_device *ub)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
ublks_added++;
|
if (ub->dev_info.flags & UBLK_F_UNPRIVILEGED_DEV)
|
||||||
|
unprivileged_ublks_added++;
|
||||||
return 0;
|
return 0;
|
||||||
fail:
|
fail:
|
||||||
put_device(dev);
|
put_device(dev);
|
||||||
@@ -2241,12 +2244,17 @@ static int ublk_add_tag_set(struct ublk_device *ub)
|
|||||||
|
|
||||||
static void ublk_remove(struct ublk_device *ub)
|
static void ublk_remove(struct ublk_device *ub)
|
||||||
{
|
{
|
||||||
|
bool unprivileged;
|
||||||
|
|
||||||
ublk_stop_dev(ub);
|
ublk_stop_dev(ub);
|
||||||
cancel_work_sync(&ub->stop_work);
|
cancel_work_sync(&ub->stop_work);
|
||||||
cancel_work_sync(&ub->quiesce_work);
|
cancel_work_sync(&ub->quiesce_work);
|
||||||
cdev_device_del(&ub->cdev, &ub->cdev_dev);
|
cdev_device_del(&ub->cdev, &ub->cdev_dev);
|
||||||
|
unprivileged = ub->dev_info.flags & UBLK_F_UNPRIVILEGED_DEV;
|
||||||
ublk_put_device(ub);
|
ublk_put_device(ub);
|
||||||
ublks_added--;
|
|
||||||
|
if (unprivileged)
|
||||||
|
unprivileged_ublks_added--;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ublk_device *ublk_get_device_from_id(int idx)
|
static struct ublk_device *ublk_get_device_from_id(int idx)
|
||||||
@@ -2495,7 +2503,8 @@ static int ublk_ctrl_add_dev(struct io_uring_cmd *cmd)
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = -EACCES;
|
ret = -EACCES;
|
||||||
if (ublks_added >= ublks_max)
|
if ((info.flags & UBLK_F_UNPRIVILEGED_DEV) &&
|
||||||
|
unprivileged_ublks_added >= unprivileged_ublks_max)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
@@ -3123,23 +3132,26 @@ static void __exit ublk_exit(void)
|
|||||||
module_init(ublk_init);
|
module_init(ublk_init);
|
||||||
module_exit(ublk_exit);
|
module_exit(ublk_exit);
|
||||||
|
|
||||||
static int ublk_set_max_ublks(const char *buf, const struct kernel_param *kp)
|
static int ublk_set_max_unprivileged_ublks(const char *buf,
|
||||||
|
const struct kernel_param *kp)
|
||||||
{
|
{
|
||||||
return param_set_uint_minmax(buf, kp, 0, UBLK_MAX_UBLKS);
|
return param_set_uint_minmax(buf, kp, 0, UBLK_MAX_UBLKS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ublk_get_max_ublks(char *buf, const struct kernel_param *kp)
|
static int ublk_get_max_unprivileged_ublks(char *buf,
|
||||||
|
const struct kernel_param *kp)
|
||||||
{
|
{
|
||||||
return sysfs_emit(buf, "%u\n", ublks_max);
|
return sysfs_emit(buf, "%u\n", unprivileged_ublks_max);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct kernel_param_ops ublk_max_ublks_ops = {
|
static const struct kernel_param_ops ublk_max_unprivileged_ublks_ops = {
|
||||||
.set = ublk_set_max_ublks,
|
.set = ublk_set_max_unprivileged_ublks,
|
||||||
.get = ublk_get_max_ublks,
|
.get = ublk_get_max_unprivileged_ublks,
|
||||||
};
|
};
|
||||||
|
|
||||||
module_param_cb(ublks_max, &ublk_max_ublks_ops, &ublks_max, 0644);
|
module_param_cb(ublks_max, &ublk_max_unprivileged_ublks_ops,
|
||||||
MODULE_PARM_DESC(ublks_max, "max number of ublk devices allowed to add(default: 64)");
|
&unprivileged_ublks_max, 0644);
|
||||||
|
MODULE_PARM_DESC(ublks_max, "max number of unprivileged ublk devices allowed to add(default: 64)");
|
||||||
|
|
||||||
MODULE_AUTHOR("Ming Lei <ming.lei@redhat.com>");
|
MODULE_AUTHOR("Ming Lei <ming.lei@redhat.com>");
|
||||||
MODULE_DESCRIPTION("Userspace block device");
|
MODULE_DESCRIPTION("Userspace block device");
|
||||||
|
|||||||
Reference in New Issue
Block a user