]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ublk: fix ublksrv pid handling for pid namespaces
authorSeamus Connor <sconnor@purestorage.com>
Thu, 15 Jan 2026 02:59:52 +0000 (18:59 -0800)
committerJens Axboe <axboe@kernel.dk>
Wed, 21 Jan 2026 14:46:14 +0000 (07:46 -0700)
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: c2c8089f325e ("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>
drivers/block/ublk_drv.c

index f6e5a076672123bff28df44dd4b577f26019bfbe..cd1e84653002d5699157018e6ed5e8732f25b165 100644 (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);