]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
RDMA: Add ib_copy_validate_udata_in()
authorJason Gunthorpe <jgg@nvidia.com>
Tue, 3 Mar 2026 19:50:00 +0000 (15:50 -0400)
committerJason Gunthorpe <jgg@nvidia.com>
Sun, 8 Mar 2026 10:20:25 +0000 (06:20 -0400)
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>
drivers/infiniband/core/rdma_core.h
drivers/infiniband/core/uverbs_ioctl.c
include/rdma/uverbs_ioctl.h

index 55f1e3558856f129d125d44011fe2837130bb457..269b393799abbcf673e5a6798561973143c2d846 100644 (file)
@@ -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[];
index f37bb447c2306bf714d9dc1dd51adf07e3fbcb8e..81798c0875ed3a49e30681c939f565669b10352c 100644 (file)
@@ -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);
index bb86d8ae8a834b34e2b0c5e70690ddee2aec5bf3..505492443c36b5ff49f00e09578598508b2856af 100644 (file)
@@ -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