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>
This commit is contained in:
Jason Gunthorpe 2026-03-03 15:50:00 -04:00
parent b51caeb24a
commit 1de9287ece
3 changed files with 80 additions and 0 deletions

View 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[];

View 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);

View 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