2 * Copyright (c) 2017, Mellanox Technologies inc. All rights reserved.
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33 #include <rdma/rdma_user_ioctl.h>
34 #include <rdma/uverbs_ioctl.h>
35 #include "rdma_core.h"
38 static bool uverbs_is_attr_cleared(const struct ib_uverbs_attr
*uattr
,
41 if (uattr
->len
> sizeof(((struct ib_uverbs_attr
*)0)->data
))
42 return ib_is_buffer_cleared(u64_to_user_ptr(uattr
->data
) + len
,
45 return !memchr_inv((const void *)&uattr
->data
+ len
,
49 static int uverbs_process_attr(struct ib_device
*ibdev
,
50 struct ib_ucontext
*ucontext
,
51 const struct ib_uverbs_attr
*uattr
,
53 const struct uverbs_attr_spec_hash
*attr_spec_bucket
,
54 struct uverbs_attr_bundle_hash
*attr_bundle_h
,
55 struct ib_uverbs_attr __user
*uattr_ptr
)
57 const struct uverbs_attr_spec
*spec
;
58 const struct uverbs_attr_spec
*val_spec
;
59 struct uverbs_attr
*e
;
60 const struct uverbs_object_spec
*object
;
61 struct uverbs_obj_attr
*o_attr
;
62 struct uverbs_attr
*elements
= attr_bundle_h
->attrs
;
64 if (attr_id
>= attr_spec_bucket
->num_attrs
) {
65 if (uattr
->flags
& UVERBS_ATTR_F_MANDATORY
)
71 if (test_bit(attr_id
, attr_bundle_h
->valid_bitmap
))
74 spec
= &attr_spec_bucket
->attrs
[attr_id
];
76 e
= &elements
[attr_id
];
80 case UVERBS_ATTR_TYPE_ENUM_IN
:
81 if (uattr
->attr_data
.enum_data
.elem_id
>= spec
->enum_def
.num_elems
)
84 if (uattr
->attr_data
.enum_data
.reserved
)
87 val_spec
= &spec
->enum_def
.ids
[uattr
->attr_data
.enum_data
.elem_id
];
89 /* Currently we only support PTR_IN based enums */
90 if (val_spec
->type
!= UVERBS_ATTR_TYPE_PTR_IN
)
93 e
->ptr_attr
.enum_id
= uattr
->attr_data
.enum_data
.elem_id
;
95 case UVERBS_ATTR_TYPE_PTR_IN
:
96 /* Ensure that any data provided by userspace beyond the known
97 * struct is zero. Userspace that knows how to use some future
98 * longer struct will fail here if used with an old kernel and
99 * non-zero content, making ABI compat/discovery simpler.
101 if (uattr
->len
> val_spec
->ptr
.len
&&
102 val_spec
->flags
& UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO
&&
103 !uverbs_is_attr_cleared(uattr
, val_spec
->ptr
.len
))
107 case UVERBS_ATTR_TYPE_PTR_OUT
:
108 if (uattr
->len
< val_spec
->ptr
.min_len
||
109 (!(val_spec
->flags
& UVERBS_ATTR_SPEC_F_MIN_SZ_OR_ZERO
) &&
110 uattr
->len
> val_spec
->ptr
.len
))
113 if (spec
->type
!= UVERBS_ATTR_TYPE_ENUM_IN
&&
114 uattr
->attr_data
.reserved
)
117 e
->ptr_attr
.data
= uattr
->data
;
118 e
->ptr_attr
.len
= uattr
->len
;
119 e
->ptr_attr
.flags
= uattr
->flags
;
122 case UVERBS_ATTR_TYPE_IDR
:
123 if (uattr
->data
>> 32)
126 case UVERBS_ATTR_TYPE_FD
:
127 if (uattr
->attr_data
.reserved
)
130 if (uattr
->len
!= 0 || !ucontext
|| uattr
->data
> INT_MAX
)
133 o_attr
= &e
->obj_attr
;
134 object
= uverbs_get_object(ibdev
, spec
->obj
.obj_type
);
137 o_attr
->type
= object
->type_attrs
;
139 o_attr
->id
= (int)uattr
->data
;
140 o_attr
->uobject
= uverbs_get_uobject_from_context(
146 if (IS_ERR(o_attr
->uobject
))
147 return PTR_ERR(o_attr
->uobject
);
149 if (spec
->obj
.access
== UVERBS_ACCESS_NEW
) {
150 u64 id
= o_attr
->uobject
->id
;
152 /* Copy the allocated id to the user-space */
153 if (put_user(id
, &e
->uattr
->data
)) {
154 uverbs_finalize_object(o_attr
->uobject
,
166 set_bit(attr_id
, attr_bundle_h
->valid_bitmap
);
170 static int uverbs_uattrs_process(struct ib_device
*ibdev
,
171 struct ib_ucontext
*ucontext
,
172 const struct ib_uverbs_attr
*uattrs
,
174 const struct uverbs_method_spec
*method
,
175 struct uverbs_attr_bundle
*attr_bundle
,
176 struct ib_uverbs_attr __user
*uattr_ptr
)
180 int num_given_buckets
= 0;
182 for (i
= 0; i
< num_uattrs
; i
++) {
183 const struct ib_uverbs_attr
*uattr
= &uattrs
[i
];
184 u16 attr_id
= uattr
->attr_id
;
185 struct uverbs_attr_spec_hash
*attr_spec_bucket
;
187 ret
= uverbs_ns_idx(&attr_id
, method
->num_buckets
);
189 if (uattr
->flags
& UVERBS_ATTR_F_MANDATORY
) {
190 uverbs_finalize_objects(attr_bundle
,
191 method
->attr_buckets
,
200 * ret is the found ns, so increase num_given_buckets if
203 if (ret
>= num_given_buckets
)
204 num_given_buckets
= ret
+ 1;
206 attr_spec_bucket
= method
->attr_buckets
[ret
];
207 ret
= uverbs_process_attr(ibdev
, ucontext
, uattr
, attr_id
,
208 attr_spec_bucket
, &attr_bundle
->hash
[ret
],
211 uverbs_finalize_objects(attr_bundle
,
212 method
->attr_buckets
,
219 return num_given_buckets
;
222 static int uverbs_validate_kernel_mandatory(const struct uverbs_method_spec
*method_spec
,
223 struct uverbs_attr_bundle
*attr_bundle
)
227 for (i
= 0; i
< attr_bundle
->num_buckets
; i
++) {
228 struct uverbs_attr_spec_hash
*attr_spec_bucket
=
229 method_spec
->attr_buckets
[i
];
231 if (!bitmap_subset(attr_spec_bucket
->mandatory_attrs_bitmask
,
232 attr_bundle
->hash
[i
].valid_bitmap
,
233 attr_spec_bucket
->num_attrs
))
237 for (; i
< method_spec
->num_buckets
; i
++) {
238 struct uverbs_attr_spec_hash
*attr_spec_bucket
=
239 method_spec
->attr_buckets
[i
];
241 if (!bitmap_empty(attr_spec_bucket
->mandatory_attrs_bitmask
,
242 attr_spec_bucket
->num_attrs
))
249 static int uverbs_handle_method(struct ib_uverbs_attr __user
*uattr_ptr
,
250 const struct ib_uverbs_attr
*uattrs
,
252 struct ib_device
*ibdev
,
253 struct ib_uverbs_file
*ufile
,
254 const struct uverbs_method_spec
*method_spec
,
255 struct uverbs_attr_bundle
*attr_bundle
)
259 int num_given_buckets
;
261 num_given_buckets
= uverbs_uattrs_process(ibdev
, ufile
->ucontext
, uattrs
,
262 num_uattrs
, method_spec
,
263 attr_bundle
, uattr_ptr
);
264 if (num_given_buckets
<= 0)
267 attr_bundle
->num_buckets
= num_given_buckets
;
268 ret
= uverbs_validate_kernel_mandatory(method_spec
, attr_bundle
);
272 ret
= method_spec
->handler(ibdev
, ufile
, attr_bundle
);
274 finalize_ret
= uverbs_finalize_objects(attr_bundle
,
275 method_spec
->attr_buckets
,
276 attr_bundle
->num_buckets
,
279 return ret
? ret
: finalize_ret
;
282 #define UVERBS_OPTIMIZE_USING_STACK_SZ 256
283 static long ib_uverbs_cmd_verbs(struct ib_device
*ib_dev
,
284 struct ib_uverbs_file
*file
,
285 struct ib_uverbs_ioctl_hdr
*hdr
,
288 const struct uverbs_object_spec
*object_spec
;
289 const struct uverbs_method_spec
*method_spec
;
293 struct ib_uverbs_attr
*uattrs
;
294 struct uverbs_attr_bundle
*uverbs_attr_bundle
;
296 struct uverbs_attr
*curr_attr
;
297 unsigned long *curr_bitmap
;
299 uintptr_t data
[UVERBS_OPTIMIZE_USING_STACK_SZ
/ sizeof(uintptr_t)];
301 if (hdr
->driver_id
!= ib_dev
->driver_id
)
304 object_spec
= uverbs_get_object(ib_dev
, hdr
->object_id
);
306 return -EPROTONOSUPPORT
;
308 method_spec
= uverbs_get_method(object_spec
, hdr
->method_id
);
310 return -EPROTONOSUPPORT
;
312 if ((method_spec
->flags
& UVERBS_ACTION_FLAG_CREATE_ROOT
) ^ !file
->ucontext
)
315 ctx_size
= sizeof(*ctx
) +
316 sizeof(struct uverbs_attr_bundle
) +
317 sizeof(struct uverbs_attr_bundle_hash
) * method_spec
->num_buckets
+
318 sizeof(*ctx
->uattrs
) * hdr
->num_attrs
+
319 sizeof(*ctx
->uverbs_attr_bundle
->hash
[0].attrs
) *
320 method_spec
->num_child_attrs
+
321 sizeof(*ctx
->uverbs_attr_bundle
->hash
[0].valid_bitmap
) *
322 (method_spec
->num_child_attrs
/ BITS_PER_LONG
+
323 method_spec
->num_buckets
);
325 if (ctx_size
<= UVERBS_OPTIMIZE_USING_STACK_SZ
)
328 ctx
= kmalloc(ctx_size
, GFP_KERNEL
);
332 ctx
->uverbs_attr_bundle
= (void *)ctx
+ sizeof(*ctx
);
333 ctx
->uattrs
= (void *)(ctx
->uverbs_attr_bundle
+ 1) +
334 (sizeof(ctx
->uverbs_attr_bundle
->hash
[0]) *
335 method_spec
->num_buckets
);
336 curr_attr
= (void *)(ctx
->uattrs
+ hdr
->num_attrs
);
337 curr_bitmap
= (void *)(curr_attr
+ method_spec
->num_child_attrs
);
340 * We just fill the pointers and num_attrs here. The data itself will be
341 * filled at a later stage (uverbs_process_attr)
343 for (i
= 0; i
< method_spec
->num_buckets
; i
++) {
344 unsigned int curr_num_attrs
= method_spec
->attr_buckets
[i
]->num_attrs
;
346 ctx
->uverbs_attr_bundle
->hash
[i
].attrs
= curr_attr
;
347 curr_attr
+= curr_num_attrs
;
348 ctx
->uverbs_attr_bundle
->hash
[i
].num_attrs
= curr_num_attrs
;
349 ctx
->uverbs_attr_bundle
->hash
[i
].valid_bitmap
= curr_bitmap
;
350 bitmap_zero(curr_bitmap
, curr_num_attrs
);
351 curr_bitmap
+= BITS_TO_LONGS(curr_num_attrs
);
354 err
= copy_from_user(ctx
->uattrs
, buf
,
355 sizeof(*ctx
->uattrs
) * hdr
->num_attrs
);
361 err
= uverbs_handle_method(buf
, ctx
->uattrs
, hdr
->num_attrs
, ib_dev
,
362 file
, method_spec
, ctx
->uverbs_attr_bundle
);
365 * EPROTONOSUPPORT is ONLY to be returned if the ioctl framework can
366 * not invoke the method because the request is not supported. No
367 * other cases should return this code.
369 if (unlikely(err
== -EPROTONOSUPPORT
)) {
370 WARN_ON_ONCE(err
== -EPROTONOSUPPORT
);
374 if (ctx
!= (void *)data
)
379 #define IB_UVERBS_MAX_CMD_SZ 4096
381 long ib_uverbs_ioctl(struct file
*filp
, unsigned int cmd
, unsigned long arg
)
383 struct ib_uverbs_file
*file
= filp
->private_data
;
384 struct ib_uverbs_ioctl_hdr __user
*user_hdr
=
385 (struct ib_uverbs_ioctl_hdr __user
*)arg
;
386 struct ib_uverbs_ioctl_hdr hdr
;
387 struct ib_device
*ib_dev
;
391 srcu_key
= srcu_read_lock(&file
->device
->disassociate_srcu
);
392 ib_dev
= srcu_dereference(file
->device
->ib_dev
,
393 &file
->device
->disassociate_srcu
);
399 if (cmd
== RDMA_VERBS_IOCTL
) {
400 err
= copy_from_user(&hdr
, user_hdr
, sizeof(hdr
));
402 if (err
|| hdr
.length
> IB_UVERBS_MAX_CMD_SZ
||
403 hdr
.length
!= sizeof(hdr
) + hdr
.num_attrs
* sizeof(struct ib_uverbs_attr
)) {
408 if (hdr
.reserved1
|| hdr
.reserved2
) {
409 err
= -EPROTONOSUPPORT
;
413 err
= ib_uverbs_cmd_verbs(ib_dev
, file
, &hdr
,
414 (__user
void *)arg
+ sizeof(hdr
));
419 srcu_read_unlock(&file
->device
->disassociate_srcu
, srcu_key
);