Commit 1de9287e authored by Jason Gunthorpe's avatar Jason Gunthorpe
Browse files

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: default avatarSriharsha Basavapatna <sriharsha.basavapatna@broadcom.com>
Acked-by: default avatarSriharsha Basavapatna <sriharsha.basavapatna@broadcom.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
parent b51caeb2
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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[];
+51 −0
Original line number Diff line number Diff line
@@ -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);
+26 −0
Original line number Diff line number Diff line
@@ -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