From: Jason Gunthorpe Date: Tue, 26 May 2026 16:15:05 +0000 (-0300) Subject: RDMA/core: Don't make a dummy ib_udata on the stack in create_qp X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=43b57d73ebbe5e7964a8b3ee3ffde0948fae6e2e;p=thirdparty%2Fkernel%2Fstable.git RDMA/core: Don't make a dummy ib_udata on the stack in create_qp 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 --- diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h index a2c36666e6fc..19104c542b27 100644 --- a/drivers/infiniband/core/core_priv.h +++ b/drivers/infiniband/core/core_priv.h @@ -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); diff --git a/drivers/infiniband/core/ib_core_uverbs.c b/drivers/infiniband/core/ib_core_uverbs.c index 6e063e05f796..dbbc0875132a 100644 --- a/drivers/infiniband/core/ib_core_uverbs.c +++ b/drivers/infiniband/core/ib_core_uverbs.c @@ -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 diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h index b626d3d24d08..56121103e9f4 100644 --- a/drivers/infiniband/core/rdma_core.h +++ b/drivers/infiniband/core/rdma_core.h @@ -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 diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 10bd7cafd976..e16eacf40d17 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -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; diff --git a/drivers/infiniband/core/uverbs_std_types_qp.c b/drivers/infiniband/core/uverbs_std_types_qp.c index e44974abc6b5..5767607dd420 100644 --- a/drivers/infiniband/core/uverbs_std_types_qp.c +++ b/drivers/infiniband/core/uverbs_std_types_qp.c @@ -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; diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index de7d19fabd75..c0ba517297b8 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -53,6 +53,7 @@ #include #include +#include "rdma_core.h" #include "core_priv.h" #include @@ -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;