ublk: fix ublksrv pid handling for pid namespaces

When ublksrv runs inside a pid namespace, START/END_RECOVERY compared
the stored init-ns tgid against the userspace pid (getpid vnr), so the
check failed and control ops could not proceed. Compare against the
caller’s init-ns tgid and store that value, then translate it back to
the caller’s pid namespace when reporting GET_DEV_INFO so ublk list
shows a sensible pid.

Testing: start/recover in a pid namespace; `ublk list` shows
reasonable pid values in init, child, and sibling namespaces.

Fixes: c2c8089f32 ("ublk: validate ublk server pid")
Signed-off-by: Seamus Connor <sconnor@purestorage.com>
Reviewed-by: Caleb Sander Mateos <csander@purestorage.com>
Reviewed-by: Ming Lei <ming.lei@redhat.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
Seamus Connor 2026-01-14 18:59:52 -08:00 committed by Jens Axboe
parent 07a1bc5c14
commit 47bdf1d29c
1 changed files with 34 additions and 5 deletions

View File

@ -2885,6 +2885,15 @@ static struct ublk_device *ublk_get_device_from_id(int idx)
return ub;
}
static bool ublk_validate_user_pid(struct ublk_device *ub, pid_t ublksrv_pid)
{
rcu_read_lock();
ublksrv_pid = pid_nr(find_vpid(ublksrv_pid));
rcu_read_unlock();
return ub->ublksrv_tgid == ublksrv_pid;
}
static int ublk_ctrl_start_dev(struct ublk_device *ub,
const struct ublksrv_ctrl_cmd *header)
{
@ -2953,7 +2962,7 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub,
if (wait_for_completion_interruptible(&ub->completion) != 0)
return -EINTR;
if (ub->ublksrv_tgid != ublksrv_pid)
if (!ublk_validate_user_pid(ub, ublksrv_pid))
return -EINVAL;
mutex_lock(&ub->mutex);
@ -2972,7 +2981,7 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub,
disk->fops = &ub_fops;
disk->private_data = ub;
ub->dev_info.ublksrv_pid = ublksrv_pid;
ub->dev_info.ublksrv_pid = ub->ublksrv_tgid;
ub->ub_disk = disk;
ublk_apply_params(ub);
@ -3320,12 +3329,32 @@ static int ublk_ctrl_stop_dev(struct ublk_device *ub)
static int ublk_ctrl_get_dev_info(struct ublk_device *ub,
const struct ublksrv_ctrl_cmd *header)
{
struct task_struct *p;
struct pid *pid;
struct ublksrv_ctrl_dev_info dev_info;
pid_t init_ublksrv_tgid = ub->dev_info.ublksrv_pid;
void __user *argp = (void __user *)(unsigned long)header->addr;
if (header->len < sizeof(struct ublksrv_ctrl_dev_info) || !header->addr)
return -EINVAL;
if (copy_to_user(argp, &ub->dev_info, sizeof(ub->dev_info)))
memcpy(&dev_info, &ub->dev_info, sizeof(dev_info));
dev_info.ublksrv_pid = -1;
if (init_ublksrv_tgid > 0) {
rcu_read_lock();
pid = find_pid_ns(init_ublksrv_tgid, &init_pid_ns);
p = pid_task(pid, PIDTYPE_TGID);
if (p) {
int vnr = task_tgid_vnr(p);
if (vnr)
dev_info.ublksrv_pid = vnr;
}
rcu_read_unlock();
}
if (copy_to_user(argp, &dev_info, sizeof(dev_info)))
return -EFAULT;
return 0;
@ -3470,7 +3499,7 @@ static int ublk_ctrl_end_recovery(struct ublk_device *ub,
pr_devel("%s: All FETCH_REQs received, dev id %d\n", __func__,
header->dev_id);
if (ub->ublksrv_tgid != ublksrv_pid)
if (!ublk_validate_user_pid(ub, ublksrv_pid))
return -EINVAL;
mutex_lock(&ub->mutex);
@ -3481,7 +3510,7 @@ static int ublk_ctrl_end_recovery(struct ublk_device *ub,
ret = -EBUSY;
goto out_unlock;
}
ub->dev_info.ublksrv_pid = ublksrv_pid;
ub->dev_info.ublksrv_pid = ub->ublksrv_tgid;
ub->dev_info.state = UBLK_S_DEV_LIVE;
pr_devel("%s: new ublksrv_pid %d, dev id %d\n",
__func__, ublksrv_pid, header->dev_id);