This op hasn't followed the normal pattern of passing NULL for udata when invoked by the kernel. Instead the kernel caller creates a dummy ib_udata on the stack and passes that in. It does not seem to currently be a bug, but this flow should be modernized to use the new API flow and in the process accept NULL as well.
Only mlx4 uses an input request structure, have every other driver call ib_is_udata_in_empty() to enforce the lack of request structs. Use ib_respond_empty_udata() in every driver that does not use a response struct. Ensure a check for NULL udata before calling ib_respond_udata() in bnxt_re, efa, and mlx5. Make mlx4 safe to be called with NULL. Signed-off-by: Jason Gunthorpe <[email protected]> --- drivers/infiniband/core/device.c | 3 +-- drivers/infiniband/hw/bnxt_re/ib_verbs.c | 5 ++++- drivers/infiniband/hw/cxgb4/provider.c | 8 +++++--- drivers/infiniband/hw/erdma/erdma_verbs.c | 9 +++++++-- drivers/infiniband/hw/hns/hns_roce_main.c | 7 ++++++- drivers/infiniband/hw/ionic/ionic_ibdev.c | 7 ++++++- drivers/infiniband/hw/irdma/verbs.c | 8 +++++--- drivers/infiniband/hw/mana/main.c | 7 ++++++- drivers/infiniband/hw/mlx4/main.c | 13 +++++++------ drivers/infiniband/hw/mthca/mthca_provider.c | 13 ++++++++----- drivers/infiniband/hw/ocrdma/ocrdma_verbs.c | 8 +++++--- drivers/infiniband/hw/qedr/verbs.c | 7 ++++++- drivers/infiniband/hw/usnic/usnic_ib_verbs.c | 8 +++++--- drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c | 8 +++++--- drivers/infiniband/sw/rdmavt/vt.c | 9 ++++++--- drivers/infiniband/sw/rxe/rxe_verbs.c | 14 ++++---------- drivers/infiniband/sw/siw/siw_verbs.c | 8 +++++--- 17 files changed, 91 insertions(+), 51 deletions(-) diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index b89efaaa81ec58..9f9662e9228186 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -1245,7 +1245,6 @@ static int assign_name(struct ib_device *device, const char *name) */ static int setup_device(struct ib_device *device) { - struct ib_udata uhw = {.outlen = 0, .inlen = 0}; int ret; ib_device_check_mandatory(device); @@ -1257,7 +1256,7 @@ static int setup_device(struct ib_device *device) } memset(&device->attrs, 0, sizeof(device->attrs)); - ret = device->ops.query_device(device, &device->attrs, &uhw); + ret = device->ops.query_device(device, &device->attrs, NULL); if (ret) { dev_warn(&device->dev, "Couldn't query the device attributes\n"); diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index 94aa06e3b828ca..98d65c1b102200 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -265,7 +265,10 @@ int bnxt_re_query_device(struct ib_device *ibdev, resp.packet_pacing_caps.supported_qpts = 1 << IB_QPT_RC; } - return ib_respond_udata(udata, resp); + + if (udata) + return ib_respond_udata(udata, resp); + return 0; } int bnxt_re_modify_device(struct ib_device *ibdev, diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c index 0e3827022c63da..e1eec37ee8222a 100644 --- a/drivers/infiniband/hw/cxgb4/provider.c +++ b/drivers/infiniband/hw/cxgb4/provider.c @@ -259,11 +259,13 @@ static int c4iw_query_device(struct ib_device *ibdev, struct ib_device_attr *pro { struct c4iw_dev *dev; + int err; pr_debug("ibdev %p\n", ibdev); - if (uhw->inlen || uhw->outlen) - return -EINVAL; + err = ib_is_udata_in_empty(uhw); + if (err) + return err; dev = to_c4iw_dev(ibdev); addrconf_addr_eui48((u8 *)&props->sys_image_guid, @@ -298,7 +300,7 @@ static int c4iw_query_device(struct ib_device *ibdev, struct ib_device_attr *pro props->max_fast_reg_page_list_len = t4_max_fr_depth(dev->rdev.lldi.ulptx_memwrite_dsgl && use_dsgl); - return 0; + return ib_respond_empty_udata(uhw); } static int c4iw_query_port(struct ib_device *ibdev, u32 port, diff --git a/drivers/infiniband/hw/erdma/erdma_verbs.c b/drivers/infiniband/hw/erdma/erdma_verbs.c index b59c2e3a5306d1..d9eb8ae2c56fba 100644 --- a/drivers/infiniband/hw/erdma/erdma_verbs.c +++ b/drivers/infiniband/hw/erdma/erdma_verbs.c @@ -315,9 +315,14 @@ erdma_user_mmap_entry_insert(struct erdma_ucontext *uctx, void *address, } int erdma_query_device(struct ib_device *ibdev, struct ib_device_attr *attr, - struct ib_udata *unused) + struct ib_udata *udata) { struct erdma_dev *dev = to_edev(ibdev); + int err; + + err = ib_is_udata_in_empty(udata); + if (err) + return err; memset(attr, 0, sizeof(*attr)); @@ -358,7 +363,7 @@ int erdma_query_device(struct ib_device *ibdev, struct ib_device_attr *attr, addrconf_addr_eui48((u8 *)&attr->sys_image_guid, dev->netdev->dev_addr); - return 0; + return ib_respond_empty_udata(udata); } int erdma_query_gid(struct ib_device *ibdev, u32 port, int idx, diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 77bad9f5d482bb..c6f633bd5a3402 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -221,6 +221,11 @@ static int hns_roce_query_device(struct ib_device *ib_dev, struct ib_udata *uhw) { struct hns_roce_dev *hr_dev = to_hr_dev(ib_dev); + int ret; + + ret = ib_is_udata_in_empty(uhw); + if (ret) + return ret; memset(props, 0, sizeof(*props)); @@ -274,7 +279,7 @@ static int hns_roce_query_device(struct ib_device *ib_dev, if (hr_dev->caps.flags & HNS_ROCE_CAP_FLAG_XRC) props->device_cap_flags |= IB_DEVICE_XRC; - return 0; + return ib_respond_empty_udata(uhw); } static int hns_roce_query_port(struct ib_device *ib_dev, u32 port_num, diff --git a/drivers/infiniband/hw/ionic/ionic_ibdev.c b/drivers/infiniband/hw/ionic/ionic_ibdev.c index 73a616ae350236..b0449c75f8938f 100644 --- a/drivers/infiniband/hw/ionic/ionic_ibdev.c +++ b/drivers/infiniband/hw/ionic/ionic_ibdev.c @@ -25,6 +25,11 @@ static int ionic_query_device(struct ib_device *ibdev, { struct ionic_ibdev *dev = to_ionic_ibdev(ibdev); struct net_device *ndev; + int err; + + err = ib_is_udata_in_empty(udata); + if (err) + return err; ndev = ib_device_get_netdev(ibdev, 1); addrconf_ifid_eui48((u8 *)&attr->sys_image_guid, ndev); @@ -69,7 +74,7 @@ static int ionic_query_device(struct ib_device *ibdev, attr->max_fast_reg_page_list_len = dev->lif_cfg.npts_per_lif / 2; attr->max_pkeys = IONIC_PKEY_TBL_LEN; - return 0; + return ib_respond_empty_udata(udata); } static int ionic_query_port(struct ib_device *ibdev, u32 port, diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c index 3f4811bb5514c6..5ba2e63b51036e 100644 --- a/drivers/infiniband/hw/irdma/verbs.c +++ b/drivers/infiniband/hw/irdma/verbs.c @@ -16,9 +16,11 @@ static int irdma_query_device(struct ib_device *ibdev, struct irdma_pci_f *rf = iwdev->rf; struct pci_dev *pcidev = iwdev->rf->pcidev; struct irdma_hw_attrs *hw_attrs = &rf->sc_dev.hw_attrs; + int err; - if (udata->inlen || udata->outlen) - return -EINVAL; + err = ib_is_udata_in_empty(udata); + if (err) + return err; memset(props, 0, sizeof(*props)); addrconf_addr_eui48((u8 *)&props->sys_image_guid, @@ -74,7 +76,7 @@ static int irdma_query_device(struct ib_device *ibdev, if (hw_attrs->uk_attrs.hw_rev >= IRDMA_GEN_3) props->device_cap_flags |= IB_DEVICE_MEM_WINDOW_TYPE_2B; - return 0; + return ib_respond_empty_udata(udata); } /** diff --git a/drivers/infiniband/hw/mana/main.c b/drivers/infiniband/hw/mana/main.c index 307ae01bf26f34..4dcd048d44b69a 100644 --- a/drivers/infiniband/hw/mana/main.c +++ b/drivers/infiniband/hw/mana/main.c @@ -549,6 +549,11 @@ int mana_ib_query_device(struct ib_device *ibdev, struct ib_device_attr *props, { struct mana_ib_dev *dev = container_of(ibdev, struct mana_ib_dev, ib_dev); struct pci_dev *pdev = to_pci_dev(mdev_to_gc(dev)->dev); + int err; + + err = ib_is_udata_in_empty(uhw); + if (err) + return err; memset(props, 0, sizeof(*props)); props->vendor_id = pdev->vendor; @@ -576,7 +581,7 @@ int mana_ib_query_device(struct ib_device *ibdev, struct ib_device_attr *props, if (!mana_ib_is_rnic(dev)) props->raw_packet_caps = IB_RAW_PACKET_CAP_IP_CSUM; - return 0; + return ib_respond_empty_udata(uhw); } int mana_ib_query_port(struct ib_device *ibdev, u32 port, diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index d50743f090bf21..17073e8f105aab 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -444,8 +444,9 @@ static int mlx4_ib_query_device(struct ib_device *ibdev, struct mlx4_uverbs_ex_query_device cmd; struct mlx4_uverbs_ex_query_device_resp resp = {}; struct mlx4_clock_params clock_params; + size_t uhw_outlen = uhw ? uhw->outlen : 0; - if (uhw->inlen) { + if (uhw && uhw->inlen) { err = ib_copy_validate_udata_in_cm(uhw, cmd, reserved, 0); if (err) return err; @@ -572,7 +573,7 @@ static int mlx4_ib_query_device(struct ib_device *ibdev, props->cq_caps.max_cq_moderation_count = MLX4_MAX_CQ_COUNT; props->cq_caps.max_cq_moderation_period = MLX4_MAX_CQ_PERIOD; - if (uhw->outlen >= resp.response_length + sizeof(resp.hca_core_clock_offset)) { + if (uhw_outlen >= resp.response_length + sizeof(resp.hca_core_clock_offset)) { resp.response_length += sizeof(resp.hca_core_clock_offset); if (!mlx4_get_internal_clock_params(dev->dev, &clock_params)) { resp.comp_mask |= MLX4_IB_QUERY_DEV_RESP_MASK_CORE_CLOCK_OFFSET; @@ -580,14 +581,14 @@ static int mlx4_ib_query_device(struct ib_device *ibdev, } } - if (uhw->outlen >= resp.response_length + + if (uhw_outlen >= resp.response_length + sizeof(resp.max_inl_recv_sz)) { resp.response_length += sizeof(resp.max_inl_recv_sz); resp.max_inl_recv_sz = dev->dev->caps.max_rq_sg * sizeof(struct mlx4_wqe_data_seg); } - if (offsetofend(typeof(resp), rss_caps) <= uhw->outlen) { + if (offsetofend(typeof(resp), rss_caps) <= uhw_outlen) { if (props->rss_caps.supported_qpts) { resp.rss_caps.rx_hash_function = MLX4_IB_RX_HASH_FUNC_TOEPLITZ; @@ -611,7 +612,7 @@ static int mlx4_ib_query_device(struct ib_device *ibdev, sizeof(resp.rss_caps); } - if (offsetofend(typeof(resp), tso_caps) <= uhw->outlen) { + if (offsetofend(typeof(resp), tso_caps) <= uhw_outlen) { if (dev->dev->caps.max_gso_sz && ((mlx4_ib_port_link_layer(ibdev, 1) == IB_LINK_LAYER_ETHERNET) || @@ -625,7 +626,7 @@ static int mlx4_ib_query_device(struct ib_device *ibdev, sizeof(resp.tso_caps); } - if (uhw->outlen) { + if (uhw_outlen) { err = ib_respond_udata(uhw, resp); if (err) goto out; diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index afa97d3801f783..079c51003b24a4 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -55,16 +55,19 @@ static int mthca_query_device(struct ib_device *ibdev, struct ib_device_attr *pr { struct ib_smp *in_mad; struct ib_smp *out_mad; - int err = -ENOMEM; + int err; struct mthca_dev *mdev = to_mdev(ibdev); - if (uhw->inlen || uhw->outlen) - return -EINVAL; + err = ib_is_udata_in_empty(uhw); + if (err) + return err; in_mad = kzalloc_obj(*in_mad); out_mad = kmalloc_obj(*out_mad); - if (!in_mad || !out_mad) + if (!in_mad || !out_mad) { + err = -ENOMEM; goto out; + } memset(props, 0, sizeof *props); @@ -111,7 +114,7 @@ static int mthca_query_device(struct ib_device *ibdev, struct ib_device_attr *pr props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * props->max_mcast_grp; - err = 0; + err = ib_respond_empty_udata(uhw); out: kfree(in_mad); kfree(out_mad); diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c index 383f1d9c15d151..17def9d9ce99ca 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c @@ -68,9 +68,11 @@ int ocrdma_query_device(struct ib_device *ibdev, struct ib_device_attr *attr, struct ib_udata *uhw) { struct ocrdma_dev *dev = get_ocrdma_dev(ibdev); + int err; - if (uhw->inlen || uhw->outlen) - return -EINVAL; + err = ib_is_udata_in_empty(uhw); + if (err) + return err; memset(attr, 0, sizeof *attr); memcpy(&attr->fw_ver, &dev->attr.fw_ver[0], @@ -110,7 +112,7 @@ int ocrdma_query_device(struct ib_device *ibdev, struct ib_device_attr *attr, attr->local_ca_ack_delay = dev->attr.local_ca_ack_delay; attr->max_fast_reg_page_list_len = dev->attr.max_pages_per_frmr; attr->max_pkeys = 1; - return 0; + return ib_respond_empty_udata(uhw); } static inline void get_link_speed_and_width(struct ocrdma_dev *dev, diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 1af908275ca729..cf01078820d8cb 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -105,6 +105,7 @@ int qedr_query_device(struct ib_device *ibdev, { struct qedr_dev *dev = get_qedr_dev(ibdev); struct qedr_device_attr *qattr = &dev->attr; + int rc; if (!dev->rdma_ctx) { DP_ERR(dev, @@ -113,6 +114,10 @@ int qedr_query_device(struct ib_device *ibdev, return -EINVAL; } + rc = ib_is_udata_in_empty(udata); + if (rc) + return rc; + memset(attr, 0, sizeof(*attr)); attr->fw_ver = qattr->fw_ver; @@ -155,7 +160,7 @@ int qedr_query_device(struct ib_device *ibdev, attr->max_pkeys = qattr->max_pkey; attr->max_ah = qattr->max_ah; - return 0; + return ib_respond_empty_udata(udata); } static inline void get_link_speed_and_width(int speed, u16 *ib_speed, diff --git a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c index 261f18a8368543..dc355b00f61cec 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c @@ -275,10 +275,12 @@ int usnic_ib_query_device(struct ib_device *ibdev, union ib_gid gid; struct ethtool_drvinfo info; int qp_per_vf; + int err; usnic_dbg("\n"); - if (uhw->inlen || uhw->outlen) - return -EINVAL; + err = ib_is_udata_in_empty(uhw); + if (err) + return err; mutex_lock(&us_ibdev->usdev_lock); us_ibdev->netdev->ethtool_ops->get_drvinfo(us_ibdev->netdev, &info); @@ -322,7 +324,7 @@ int usnic_ib_query_device(struct ib_device *ibdev, * max_qp_wr, max_sge, max_sge_rd, max_cqe */ mutex_unlock(&us_ibdev->usdev_lock); - return 0; + return ib_respond_empty_udata(uhw); } int usnic_ib_query_port(struct ib_device *ibdev, u32 port, diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c index b9c3202b9545e3..1d29a535f76a8c 100644 --- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c @@ -67,9 +67,11 @@ int pvrdma_query_device(struct ib_device *ibdev, struct ib_udata *uhw) { struct pvrdma_dev *dev = to_vdev(ibdev); + int err; - if (uhw->inlen || uhw->outlen) - return -EINVAL; + err = ib_is_udata_in_empty(uhw); + if (err) + return err; props->fw_ver = dev->dsr->caps.fw_ver; props->sys_image_guid = dev->dsr->caps.sys_image_guid; @@ -114,7 +116,7 @@ int pvrdma_query_device(struct ib_device *ibdev, props->device_cap_flags |= IB_DEVICE_PORT_ACTIVE_EVENT | IB_DEVICE_RC_RNR_NAK_GEN; - return 0; + return ib_respond_empty_udata(uhw); } /** diff --git a/drivers/infiniband/sw/rdmavt/vt.c b/drivers/infiniband/sw/rdmavt/vt.c index 40aa6420836470..5fa3a1f3332689 100644 --- a/drivers/infiniband/sw/rdmavt/vt.c +++ b/drivers/infiniband/sw/rdmavt/vt.c @@ -6,6 +6,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/dma-mapping.h> +#include <rdma/uverbs_ioctl.h> #include "vt.h" #include "cq.h" #include "trace.h" @@ -79,14 +80,16 @@ static int rvt_query_device(struct ib_device *ibdev, struct ib_udata *uhw) { struct rvt_dev_info *rdi = ib_to_rvt(ibdev); + int err; - if (uhw->inlen || uhw->outlen) - return -EINVAL; + err = ib_is_udata_in_empty(uhw); + if (err) + return err; /* * Return rvt_dev_info.dparms.props contents */ *props = rdi->dparms.props; - return 0; + return ib_respond_empty_udata(uhw); } static int rvt_get_numa_node(struct ib_device *ibdev) diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c index 8edd4dd1f031f4..5815ce34d9704c 100644 --- a/drivers/infiniband/sw/rxe/rxe_verbs.c +++ b/drivers/infiniband/sw/rxe/rxe_verbs.c @@ -22,19 +22,13 @@ static int rxe_query_device(struct ib_device *ibdev, struct rxe_dev *rxe = to_rdev(ibdev); int err; - if (udata->inlen || udata->outlen) { - rxe_dbg_dev(rxe, "malformed udata\n"); - err = -EINVAL; - goto err_out; - } + err = ib_is_udata_in_empty(udata); + if (err) + return err; memcpy(attr, &rxe->attr, sizeof(*attr)); - return 0; - -err_out: - rxe_err_dev(rxe, "returned err = %d\n", err); - return err; + return ib_respond_empty_udata(udata); } static int rxe_query_port(struct ib_device *ibdev, diff --git a/drivers/infiniband/sw/siw/siw_verbs.c b/drivers/infiniband/sw/siw/siw_verbs.c index b34f3d6547ffc7..b74ac85c1b8b8b 100644 --- a/drivers/infiniband/sw/siw/siw_verbs.c +++ b/drivers/infiniband/sw/siw/siw_verbs.c @@ -130,9 +130,11 @@ int siw_query_device(struct ib_device *base_dev, struct ib_device_attr *attr, struct ib_udata *udata) { struct siw_device *sdev = to_siw_dev(base_dev); + int rv; - if (udata->inlen || udata->outlen) - return -EINVAL; + rv = ib_is_udata_in_empty(udata); + if (rv) + return rv; memset(attr, 0, sizeof(*attr)); @@ -165,7 +167,7 @@ int siw_query_device(struct ib_device *base_dev, struct ib_device_attr *attr, addrconf_addr_eui48((u8 *)&attr->sys_image_guid, sdev->raw_gid); - return 0; + return ib_respond_empty_udata(udata); } int siw_query_port(struct ib_device *base_dev, u32 port, -- 2.43.0
