mirror of https://github.com/torvalds/linux.git
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:
parent
07a1bc5c14
commit
47bdf1d29c
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue