mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 01:55:51 +02:00
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: 00a79d6b99 ("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>
This commit is contained in:
parent
b548a6c4ee
commit
43b57d73eb
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 @@ static struct ib_qp *create_qp(struct ib_device *dev, struct ib_pd *pd,
|
|||
* @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;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user