Commit 47bdf1d2 authored by Seamus Connor's avatar Seamus Connor Committed by Jens Axboe
Browse files

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: c2c8089f ("ublk: validate ublk server pid")
Signed-off-by: default avatarSeamus Connor <sconnor@purestorage.com>
Reviewed-by: default avatarCaleb Sander Mateos <csander@purestorage.com>
Reviewed-by: default avatarMing Lei <ming.lei@redhat.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 07a1bc5c
Loading
Loading
Loading
Loading
+34 −5
Original line number Diff line number Diff line
@@ -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);