diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c index aed7cc2a9e86..c63583dbc6b9 100644 --- a/drivers/infiniband/core/rdma_core.c +++ b/drivers/infiniband/core/rdma_core.c @@ -133,7 +133,7 @@ static int uverbs_try_lock_object(struct ib_uobject *uobj, bool exclusive) * returns success_res on success (negative errno on failure). For use by * callers that do not need the uobj. */ -int __uobj_perform_destroy(const struct uverbs_obj_type *type, int id, +int __uobj_perform_destroy(const struct uverbs_obj_type *type, u32 id, struct ib_uverbs_file *ufile, int success_res) { struct ib_uobject *uobj; @@ -212,13 +212,17 @@ static void uverbs_idr_remove_uobj(struct ib_uobject *uobj) /* Returns the ib_uobject or an error. The caller should check for IS_ERR. */ static struct ib_uobject * lookup_get_idr_uobject(const struct uverbs_obj_type *type, - struct ib_uverbs_file *ufile, int id, bool exclusive) + struct ib_uverbs_file *ufile, s64 id, bool exclusive) { struct ib_uobject *uobj; + unsigned long idrno = id; + + if (id < 0 || id > ULONG_MAX) + return ERR_PTR(-EINVAL); rcu_read_lock(); /* object won't be released as we're protected in rcu */ - uobj = idr_find(&ufile->idr, id); + uobj = idr_find(&ufile->idr, idrno); if (!uobj) { uobj = ERR_PTR(-ENOENT); goto free; @@ -240,17 +244,21 @@ lookup_get_idr_uobject(const struct uverbs_obj_type *type, static struct ib_uobject *lookup_get_fd_uobject(const struct uverbs_obj_type *type, struct ib_uverbs_file *ufile, - int id, bool exclusive) + s64 id, bool exclusive) { struct file *f; struct ib_uobject *uobject; + int fdno = id; const struct uverbs_obj_fd_type *fd_type = container_of(type, struct uverbs_obj_fd_type, type); + if (fdno != id) + return ERR_PTR(-EINVAL); + if (exclusive) return ERR_PTR(-EOPNOTSUPP); - f = fget(id); + f = fget(fdno); if (!f) return ERR_PTR(-EBADF); @@ -270,7 +278,7 @@ static struct ib_uobject *lookup_get_fd_uobject(const struct uverbs_obj_type *ty } struct ib_uobject *rdma_lookup_get_uobject(const struct uverbs_obj_type *type, - struct ib_uverbs_file *ufile, int id, + struct ib_uverbs_file *ufile, s64 id, bool exclusive) { struct ib_uobject *uobj; @@ -725,7 +733,7 @@ EXPORT_SYMBOL(uverbs_fd_class); struct ib_uobject * uverbs_get_uobject_from_file(const struct uverbs_obj_type *type_attrs, struct ib_uverbs_file *ufile, - enum uverbs_obj_access access, int id) + enum uverbs_obj_access access, s64 id) { switch (access) { case UVERBS_ACCESS_READ: diff --git a/drivers/infiniband/core/rdma_core.h b/drivers/infiniband/core/rdma_core.h index 1bba60e960c1..db2339330f6f 100644 --- a/drivers/infiniband/core/rdma_core.h +++ b/drivers/infiniband/core/rdma_core.h @@ -86,7 +86,7 @@ void uverbs_close_fd(struct file *f); struct ib_uobject * uverbs_get_uobject_from_file(const struct uverbs_obj_type *type_attrs, struct ib_uverbs_file *ufile, - enum uverbs_obj_access access, int id); + enum uverbs_obj_access access, s64 id); /* * Note that certain finalize stages could return a status: diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 987ee38ab4b3..409fd46a2a99 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -48,10 +48,10 @@ #include "core_priv.h" static struct ib_uverbs_completion_event_file * -ib_uverbs_lookup_comp_file(int fd, struct ib_uverbs_file *ufile) +_ib_uverbs_lookup_comp_file(s32 fd, struct ib_uverbs_file *ufile) { - struct ib_uobject *uobj = uobj_get_read(UVERBS_OBJECT_COMP_CHANNEL, - fd, ufile); + struct ib_uobject *uobj = ufd_get_read(UVERBS_OBJECT_COMP_CHANNEL, + fd, ufile); if (IS_ERR(uobj)) return (void *)uobj; @@ -62,6 +62,8 @@ ib_uverbs_lookup_comp_file(int fd, struct ib_uverbs_file *ufile) return container_of(uobj, struct ib_uverbs_completion_event_file, uobj); } +#define ib_uverbs_lookup_comp_file(_fd, _ufile) \ + _ib_uverbs_lookup_comp_file((_fd)*typecheck(s32, _fd), _ufile) ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, struct ib_device *ib_dev, diff --git a/drivers/infiniband/core/uverbs_ioctl.c b/drivers/infiniband/core/uverbs_ioctl.c index d3bf82cfaa2b..26ddc5cadcdb 100644 --- a/drivers/infiniband/core/uverbs_ioctl.c +++ b/drivers/infiniband/core/uverbs_ioctl.c @@ -136,15 +136,11 @@ static int uverbs_process_attr(struct ib_uverbs_file *ufile, break; case UVERBS_ATTR_TYPE_IDR: - if (uattr->data >> 32) - return -EINVAL; - /* fall through */ case UVERBS_ATTR_TYPE_FD: if (uattr->attr_data.reserved) return -EINVAL; - if (uattr->len != 0 || !ufile->ucontext || - uattr->data > INT_MAX) + if (uattr->len != 0 || !ufile->ucontext) return -EINVAL; o_attr = &e->obj_attr; @@ -152,17 +148,23 @@ static int uverbs_process_attr(struct ib_uverbs_file *ufile, if (!object) return -EINVAL; + /* + * The type of uattr->data is u64 for UVERBS_ATTR_TYPE_IDR and + * s64 for UVERBS_ATTR_TYPE_FD. We can cast the u64 to s64 + * here without caring about truncation as we know that the + * IDR implementation today rejects negative IDs + */ o_attr->uobject = uverbs_get_uobject_from_file( object->type_attrs, ufile, spec->u.obj.access, - (int)uattr->data); + uattr->data_s64); if (IS_ERR(o_attr->uobject)) return PTR_ERR(o_attr->uobject); if (spec->u.obj.access == UVERBS_ACCESS_NEW) { - u64 id = o_attr->uobject->id; + s64 id = o_attr->uobject->id; /* Copy the allocated id to the user-space */ if (put_user(id, &e->uattr->data)) { diff --git a/include/rdma/uverbs_std_types.h b/include/rdma/uverbs_std_types.h index 3e3f108f0912..4f32eab8b7a4 100644 --- a/include/rdma/uverbs_std_types.h +++ b/include/rdma/uverbs_std_types.h @@ -46,39 +46,43 @@ static inline const struct uverbs_object_tree_def *uverbs_default_get_objects(vo } #endif -static inline struct ib_uobject *__uobj_get(const struct uverbs_obj_type *type, - bool write, - struct ib_uverbs_file *ufile, - int id) -{ - return rdma_lookup_get_uobject(type, ufile, id, write); -} +/* Returns _id, or causes a compile error if _id is not a u32. + * + * The uobj APIs should only be used with the write based uAPI to access + * object IDs. The write API must use a u32 for the object handle, which is + * checked by this macro. + */ +#define _uobj_check_id(_id) ((_id) * typecheck(u32, _id)) #define uobj_get_type(_object) UVERBS_OBJECT(_object).type_attrs #define uobj_get_read(_type, _id, _ufile) \ - __uobj_get(uobj_get_type(_type), false, _ufile, _id) + rdma_lookup_get_uobject(uobj_get_type(_type), _ufile, \ + _uobj_check_id(_id), false) -static inline void *_uobj_get_obj_read(const struct uverbs_obj_type *type, - int id, struct ib_uverbs_file *ufile) +#define ufd_get_read(_type, _fdnum, _ufile) \ + rdma_lookup_get_uobject(uobj_get_type(_type), _ufile, \ + (_fdnum)*typecheck(s32, _fdnum), false) + +static inline void *_uobj_get_obj_read(struct ib_uobject *uobj) { - struct ib_uobject *uobj = __uobj_get(type, false, ufile, id); - if (IS_ERR(uobj)) return NULL; return uobj->object; } #define uobj_get_obj_read(_object, _type, _id, _ufile) \ - ((struct ib_##_object *)_uobj_get_obj_read(uobj_get_type(_type), _id, \ - _ufile)) + ((struct ib_##_object *)_uobj_get_obj_read( \ + uobj_get_read(_type, _id, _ufile))) #define uobj_get_write(_type, _id, _ufile) \ - __uobj_get(uobj_get_type(_type), true, _ufile, _id) + rdma_lookup_get_uobject(uobj_get_type(_type), _ufile, \ + _uobj_check_id(_id), true) -int __uobj_perform_destroy(const struct uverbs_obj_type *type, int id, +int __uobj_perform_destroy(const struct uverbs_obj_type *type, u32 id, struct ib_uverbs_file *ufile, int success_res); #define uobj_perform_destroy(_type, _id, _ufile, _success_res) \ - __uobj_perform_destroy(uobj_get_type(_type), _id, _ufile, _success_res) + __uobj_perform_destroy(uobj_get_type(_type), _uobj_check_id(_id), \ + _ufile, _success_res) static inline void uobj_put_read(struct ib_uobject *uobj) { diff --git a/include/rdma/uverbs_types.h b/include/rdma/uverbs_types.h index e2fc9db466d3..2f50cc6def3c 100644 --- a/include/rdma/uverbs_types.h +++ b/include/rdma/uverbs_types.h @@ -77,7 +77,7 @@ struct uverbs_obj_type_class { void (*alloc_abort)(struct ib_uobject *uobj); struct ib_uobject *(*lookup_get)(const struct uverbs_obj_type *type, - struct ib_uverbs_file *ufile, int id, + struct ib_uverbs_file *ufile, s64 id, bool exclusive); void (*lookup_put)(struct ib_uobject *uobj, bool exclusive); /* @@ -121,7 +121,7 @@ struct uverbs_obj_idr_type { struct ib_uobject *rdma_lookup_get_uobject(const struct uverbs_obj_type *type, struct ib_uverbs_file *ufile, - int id, bool exclusive); + s64 id, bool exclusive); void rdma_lookup_put_uobject(struct ib_uobject *uobj, bool exclusive); struct ib_uobject *rdma_alloc_begin_uobject(const struct uverbs_obj_type *type, struct ib_uverbs_file *ufile); diff --git a/include/uapi/rdma/rdma_user_ioctl_cmds.h b/include/uapi/rdma/rdma_user_ioctl_cmds.h index 1da5a1e1f3a8..24800c6c1f32 100644 --- a/include/uapi/rdma/rdma_user_ioctl_cmds.h +++ b/include/uapi/rdma/rdma_user_ioctl_cmds.h @@ -62,7 +62,12 @@ struct ib_uverbs_attr { } enum_data; __u16 reserved; } attr_data; - __aligned_u64 data; /* ptr to command, inline data or idr/fd */ + union { + /* Used by PTR_IN/OUT, ENUM_IN and IDR */ + __aligned_u64 data; + /* Used by FD_IN and FD_OUT */ + __s64 data_s64; + }; }; struct ib_uverbs_ioctl_hdr {