]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
RDMA/core: Don't make a dummy ib_udata on the stack in create_qp
authorJason Gunthorpe <jgg@nvidia.com>
Tue, 26 May 2026 16:15:05 +0000 (13:15 -0300)
committerJason Gunthorpe <jgg@nvidia.com>
Wed, 3 Jun 2026 18:12:43 +0000 (15:12 -0300)
Sashiko points out the udata for destruction has to be created using
uverbs_get_cleared_udata(). Move it to ib_core_uverbs.c so that the core
qp code can call it. Rework the call chain to pass the struct
uverbs_attr_bundle right up to the driver op callback.

Fixes a possible wild stack reference in drivers during error unwinding,
mlx5 can call rdma_udata_to_drv_context() from destroy_qp() when
destroying a QP.

Fixes: 00a79d6b996d ("RDMA/core: Configure selinux QP during creation")
Link: https://patch.msgid.link/r/1-v1-922fa8e828ba+f7-ib_udata_stack_jgg@nvidia.com
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
drivers/infiniband/core/core_priv.h
drivers/infiniband/core/ib_core_uverbs.c
drivers/infiniband/core/rdma_core.h
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/core/uverbs_std_types_qp.c
drivers/infiniband/core/verbs.c

index a2c36666e6fcb9e7bad12bf3a2cfa1b57c98daf5..19104c542b270d8c4886c74cbf14dcb7ec2bc9cb 100644 (file)
@@ -321,7 +321,7 @@ void nldev_exit(void);
 
 struct ib_qp *ib_create_qp_user(struct ib_device *dev, struct ib_pd *pd,
                                struct ib_qp_init_attr *attr,
-                               struct ib_udata *udata,
+                               struct uverbs_attr_bundle *uattrs,
                                struct ib_uqp_object *uobj, const char *caller);
 
 void ib_qp_usecnt_inc(struct ib_qp *qp);
index 6e063e05f796cabb174429e7b16d7aa3775d58f1..dbbc0875132a30fa9ff6bf66265e67054553d7a2 100644 (file)
@@ -532,6 +532,18 @@ int uverbs_destroy_def_handler(struct uverbs_attr_bundle *attrs)
 }
 EXPORT_SYMBOL(uverbs_destroy_def_handler);
 
+/*
+ * When calling a destroy function during an error unwind we need to pass in
+ * the udata that is sanitized of all user arguments. Ie from the driver
+ * perspective it looks like no udata was passed.
+ */
+struct ib_udata *uverbs_get_cleared_udata(struct uverbs_attr_bundle *attrs)
+{
+       attrs->driver_udata = (struct ib_udata){};
+       return &attrs->driver_udata;
+}
+EXPORT_SYMBOL_NS_GPL(uverbs_get_cleared_udata, "rdma_core");
+
 /**
  * _uverbs_alloc() - Quickly allocate memory for use with a bundle
  * @bundle: The bundle
index b626d3d24d087dff066029764ea8a7a8362c3ddb..56121103e9f4f5dbac49ce9a14aac51fecd1370f 100644 (file)
@@ -71,7 +71,14 @@ int uverbs_output_written(const struct uverbs_attr_bundle *bundle, size_t idx);
 
 void setup_ufile_idr_uobject(struct ib_uverbs_file *ufile);
 
+#if IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS)
 struct ib_udata *uverbs_get_cleared_udata(struct uverbs_attr_bundle *attrs);
+#else
+static inline struct ib_udata *uverbs_get_cleared_udata(struct uverbs_attr_bundle *attrs)
+{
+       return NULL;
+}
+#endif
 
 /*
  * This is the runtime description of the uverbs API, used by the syscall
index 10bd7cafd976f7a4e7d22dd04207e36bc982cb19..e16eacf40d17af2edeb1d09c5a04b33d14625339 100644 (file)
@@ -163,17 +163,6 @@ static int uverbs_request_finish(struct uverbs_req_iter *iter)
        return 0;
 }
 
-/*
- * When calling a destroy function during an error unwind we need to pass in
- * the udata that is sanitized of all user arguments. Ie from the driver
- * perspective it looks like no udata was passed.
- */
-struct ib_udata *uverbs_get_cleared_udata(struct uverbs_attr_bundle *attrs)
-{
-       attrs->driver_udata = (struct ib_udata){};
-       return &attrs->driver_udata;
-}
-
 static struct ib_uverbs_completion_event_file *
 _ib_uverbs_lookup_comp_file(s32 fd, struct uverbs_attr_bundle *attrs)
 {
@@ -1461,8 +1450,7 @@ static int create_qp(struct uverbs_attr_bundle *attrs,
                attr.source_qpn = cmd->source_qpn;
        }
 
-       qp = ib_create_qp_user(device, pd, &attr, &attrs->driver_udata, obj,
-                              KBUILD_MODNAME);
+       qp = ib_create_qp_user(device, pd, &attr, attrs, obj, KBUILD_MODNAME);
        if (IS_ERR(qp)) {
                ret = PTR_ERR(qp);
                goto err_put;
index e44974abc6b5a07f20247a3dd22d0a101f37d6a6..5767607dd4204d32f634cbf1dac1867eba9c29a5 100644 (file)
@@ -248,8 +248,7 @@ static int UVERBS_HANDLER(UVERBS_METHOD_QP_CREATE)(
        set_caps(&attr, &cap, true);
        mutex_init(&obj->mcast_lock);
 
-       qp = ib_create_qp_user(device, pd, &attr, &attrs->driver_udata, obj,
-                              KBUILD_MODNAME);
+       qp = ib_create_qp_user(device, pd, &attr, attrs, obj, KBUILD_MODNAME);
        if (IS_ERR(qp)) {
                ret = PTR_ERR(qp);
                goto err_put;
index de7d19fabd75951f0c546accbbb97348e756c235..c0ba517297b8f0ada31db224bc52c9b9846d3709 100644 (file)
@@ -53,6 +53,7 @@
 #include <rdma/rw.h>
 #include <rdma/lag.h>
 
+#include "rdma_core.h"
 #include "core_priv.h"
 #include <trace/events/rdma_core.h>
 
@@ -1265,10 +1266,9 @@ static struct ib_qp *create_xrc_qp_user(struct ib_qp *qp,
 
 static struct ib_qp *create_qp(struct ib_device *dev, struct ib_pd *pd,
                               struct ib_qp_init_attr *attr,
-                              struct ib_udata *udata,
+                              struct uverbs_attr_bundle *uattrs,
                               struct ib_uqp_object *uobj, const char *caller)
 {
-       struct ib_udata dummy = {};
        struct ib_qp *qp;
        int ret;
 
@@ -1301,9 +1301,10 @@ static struct ib_qp *create_qp(struct ib_device *dev, struct ib_pd *pd,
        qp->recv_cq = attr->recv_cq;
 
        rdma_restrack_new(&qp->res, RDMA_RESTRACK_QP);
-       WARN_ONCE(!udata && !caller, "Missing kernel QP owner");
-       rdma_restrack_set_name(&qp->res, udata ? NULL : caller);
-       ret = dev->ops.create_qp(qp, attr, udata);
+       WARN_ONCE(!uattrs && !caller, "Missing kernel QP owner");
+       rdma_restrack_set_name(&qp->res, uattrs ? NULL : caller);
+       ret = dev->ops.create_qp(qp, attr,
+                                uattrs ? &uattrs->driver_udata : NULL);
        if (ret)
                goto err_create;
 
@@ -1322,7 +1323,8 @@ static struct ib_qp *create_qp(struct ib_device *dev, struct ib_pd *pd,
        return qp;
 
 err_security:
-       qp->device->ops.destroy_qp(qp, udata ? &dummy : NULL);
+       qp->device->ops.destroy_qp(
+               qp, uattrs ? uverbs_get_cleared_udata(uattrs) : NULL);
 err_create:
        rdma_restrack_put(&qp->res);
        kfree(qp);
@@ -1338,13 +1340,13 @@ err_create:
  * @attr: A list of initial attributes required to create the
  *   QP.  If QP creation succeeds, then the attributes are updated to
  *   the actual capabilities of the created QP.
- * @udata: User data
+ * @uattrs: User ioctl attributes and udata
  * @uobj: uverbs obect
  * @caller: caller's build-time module name
  */
 struct ib_qp *ib_create_qp_user(struct ib_device *dev, struct ib_pd *pd,
                                struct ib_qp_init_attr *attr,
-                               struct ib_udata *udata,
+                               struct uverbs_attr_bundle *uattrs,
                                struct ib_uqp_object *uobj, const char *caller)
 {
        struct ib_qp *qp, *xrc_qp;
@@ -1352,7 +1354,7 @@ struct ib_qp *ib_create_qp_user(struct ib_device *dev, struct ib_pd *pd,
        if (attr->qp_type == IB_QPT_XRC_TGT)
                qp = create_qp(dev, pd, attr, NULL, NULL, caller);
        else
-               qp = create_qp(dev, pd, attr, udata, uobj, NULL);
+               qp = create_qp(dev, pd, attr, uattrs, uobj, NULL);
        if (attr->qp_type != IB_QPT_XRC_TGT || IS_ERR(qp))
                return qp;