summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Gunthorpe <jgg@nvidia.com>2026-03-03 22:50:00 +0300
committerJason Gunthorpe <jgg@nvidia.com>2026-03-08 13:20:25 +0300
commit1de9287ece44022bd694e669153fb7644804e10d (patch)
tree44c958d4db92875b6cd555b6e87655bde6a38f1f
parentb51caeb24aad565ef26689fb667c60daa60094aa (diff)
downloadlinux-1de9287ece44022bd694e669153fb7644804e10d.tar.xz
RDMA: Add ib_copy_validate_udata_in()
Add a new function to consolidate the required compatibility pattern for driver data of checking against a minimum size, and checking for unknown trailing bytes to be zero into a function. This new function uses the faster copy_struct_from_user() instead of trying to directly check for zero. Incorporate the common ibdev_dbg() logging directly into the error paths of the helper. Link: https://patch.msgid.link/r/3-v3-bd56dd443069+49-bnxt_re_uapi_jgg@nvidia.com Tested-by: Sriharsha Basavapatna <sriharsha.basavapatna@broadcom.com> Acked-by: Sriharsha Basavapatna <sriharsha.basavapatna@broadcom.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
-rw-r--r--drivers/infiniband/core/rdma_core.h3
-rw-r--r--drivers/infiniband/core/uverbs_ioctl.c51
-rw-r--r--include/rdma/uverbs_ioctl.h26
3 files changed, 80 insertions, 0 deletions
diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h
index 55f1e3558856..269b393799ab 100644
--- a/drivers/infiniband/core/rdma_core.h
+++ b/drivers/infiniband/core/rdma_core.h
@@ -151,6 +151,9 @@ void uapi_compute_bundle_size(struct uverbs_api_ioctl_method *method_elm,
unsigned int num_attrs);
void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile);
+typedef int (*uverbs_api_ioctl_handler_fn)(struct uverbs_attr_bundle *attrs);
+uverbs_api_ioctl_handler_fn uverbs_get_handler_fn(struct ib_udata *udata);
+
extern const struct uapi_definition uverbs_def_obj_async_fd[];
extern const struct uapi_definition uverbs_def_obj_counters[];
extern const struct uapi_definition uverbs_def_obj_cq[];
diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c
index f37bb447c230..81798c0875ed 100644
--- a/drivers/infiniband/core/uverbs_ioctl.c
+++ b/drivers/infiniband/core/uverbs_ioctl.c
@@ -70,6 +70,19 @@ struct bundle_priv {
u64 internal_buffer[32];
};
+uverbs_api_ioctl_handler_fn uverbs_get_handler_fn(struct ib_udata *udata)
+{
+ struct uverbs_attr_bundle *bundle =
+ rdma_udata_to_uverbs_attr_bundle(udata);
+ struct bundle_priv *pbundle =
+ container_of(&bundle->hdr, struct bundle_priv, bundle);
+
+ lockdep_assert_held(&bundle->ufile->device->disassociate_srcu);
+
+ return srcu_dereference(pbundle->method_elm->handler,
+ &bundle->ufile->device->disassociate_srcu);
+}
+
/*
* Each method has an absolute minimum amount of memory it needs to allocate,
* precompute that amount and determine if the onstack memory can be used or
@@ -847,3 +860,41 @@ void uverbs_finalize_uobj_create(const struct uverbs_attr_bundle *bundle,
pbundle->uobj_hw_obj_valid);
}
EXPORT_SYMBOL(uverbs_finalize_uobj_create);
+
+int _ib_copy_validate_udata_in(struct ib_udata *udata, void *req,
+ size_t kernel_size, size_t minimum_size)
+{
+ int err;
+
+ if (udata->inlen < minimum_size) {
+ ibdev_dbg(
+ rdma_udata_to_dev(udata),
+ "System call driver input udata too small (%zu < %zu) for ioctl %ps called by %pSR\n",
+ udata->inlen, minimum_size,
+ uverbs_get_handler_fn(udata),
+ __builtin_return_address(0));
+ return -EINVAL;
+ }
+
+ err = copy_struct_from_user(req, kernel_size, udata->inbuf,
+ udata->inlen);
+ if (err) {
+ if (err == -E2BIG) {
+ ibdev_dbg(
+ rdma_udata_to_dev(udata),
+ "System call driver input udata not zero from %zu -> %zu for ioctl %ps called by %pSR\n",
+ minimum_size, udata->inlen,
+ uverbs_get_handler_fn(udata),
+ __builtin_return_address(0));
+ return -EOPNOTSUPP;
+ }
+ ibdev_dbg(
+ rdma_udata_to_dev(udata),
+ "System call driver input udata EFAULT for ioctl %ps called by %pSR\n",
+ uverbs_get_handler_fn(udata),
+ __builtin_return_address(0));
+ return err;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(_ib_copy_validate_udata_in);
diff --git a/include/rdma/uverbs_ioctl.h b/include/rdma/uverbs_ioctl.h
index bb86d8ae8a83..505492443c36 100644
--- a/include/rdma/uverbs_ioctl.h
+++ b/include/rdma/uverbs_ioctl.h
@@ -897,6 +897,9 @@ int _uverbs_get_const_unsigned(u64 *to,
size_t idx, u64 upper_bound, u64 *def_val);
int uverbs_copy_to_struct_or_zero(const struct uverbs_attr_bundle *bundle,
size_t idx, const void *from, size_t size);
+
+int _ib_copy_validate_udata_in(struct ib_udata *udata, void *req,
+ size_t kernel_size, size_t minimum_size);
#else
static inline int
uverbs_get_flags64(u64 *to, const struct uverbs_attr_bundle *attrs_bundle,
@@ -953,6 +956,14 @@ _uverbs_get_const_unsigned(u64 *to,
{
return -EINVAL;
}
+
+static inline int _ib_copy_validate_udata_in(struct ib_udata *udata, void *req,
+ size_t kernel_size,
+ size_t minimum_size)
+{
+ return -EINVAL;
+}
+
#endif
#define uverbs_get_const_signed(_to, _attrs_bundle, _idx) \
@@ -1018,4 +1029,19 @@ uverbs_get_raw_fd(int *to, const struct uverbs_attr_bundle *attrs_bundle,
return uverbs_get_const_signed(to, attrs_bundle, idx);
}
+/**
+ * ib_copy_validate_udata_in - Copy and validate that the request structure is
+ * compatible with this kernel
+ * @_udata: The system calls ib_udata struct
+ * @_req: The name of an on-stack structure that holds the driver data
+ * @_end_member: The member in the struct that is the original end of struct
+ * from the first kernel to introduce it.
+ *
+ * Check that the udata input request struct is properly formed for this kernel.
+ * Then copy it into req
+ */
+#define ib_copy_validate_udata_in(_udata, _req, _end_member) \
+ _ib_copy_validate_udata_in(_udata, &(_req), sizeof(_req), \
+ offsetofend(typeof(_req), _end_member))
+
#endif