xref: /openbmc/linux/drivers/infiniband/core/uverbs_ioctl.c (revision ca90578000afb0d8f177ea36f7259a9c3640cf49)
1 /*
2  * Copyright (c) 2017, Mellanox Technologies inc.  All rights reserved.
3  *
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:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
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.
22  *
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
30  * SOFTWARE.
31  */
32 
33 #include <rdma/rdma_user_ioctl.h>
34 #include <rdma/uverbs_ioctl.h>
35 #include "rdma_core.h"
36 #include "uverbs.h"
37 
38 static bool uverbs_is_attr_cleared(const struct ib_uverbs_attr *uattr,
39 				   u16 len)
40 {
41 	if (uattr->len > sizeof(((struct ib_uverbs_attr *)0)->data))
42 		return ib_is_buffer_cleared(u64_to_user_ptr(uattr->data) + len,
43 					    uattr->len - len);
44 
45 	return !memchr_inv((const void *)&uattr->data + len,
46 			   0, uattr->len - len);
47 }
48 
49 static int uverbs_process_attr(struct ib_device *ibdev,
50 			       struct ib_ucontext *ucontext,
51 			       const struct ib_uverbs_attr *uattr,
52 			       u16 attr_id,
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)
56 {
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;
63 
64 	if (attr_id >= attr_spec_bucket->num_attrs) {
65 		if (uattr->flags & UVERBS_ATTR_F_MANDATORY)
66 			return -EINVAL;
67 		else
68 			return 0;
69 	}
70 
71 	if (test_bit(attr_id, attr_bundle_h->valid_bitmap))
72 		return -EINVAL;
73 
74 	spec = &attr_spec_bucket->attrs[attr_id];
75 	val_spec = spec;
76 	e = &elements[attr_id];
77 	e->uattr = uattr_ptr;
78 
79 	switch (spec->type) {
80 	case UVERBS_ATTR_TYPE_ENUM_IN:
81 		if (uattr->attr_data.enum_data.elem_id >= spec->enum_def.num_elems)
82 			return -EOPNOTSUPP;
83 
84 		if (uattr->attr_data.enum_data.reserved)
85 			return -EINVAL;
86 
87 		val_spec = &spec->enum_def.ids[uattr->attr_data.enum_data.elem_id];
88 
89 		/* Currently we only support PTR_IN based enums */
90 		if (val_spec->type != UVERBS_ATTR_TYPE_PTR_IN)
91 			return -EOPNOTSUPP;
92 
93 		e->ptr_attr.enum_id = uattr->attr_data.enum_data.elem_id;
94 	/* fall through */
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.
100 		 */
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))
104 			return -EOPNOTSUPP;
105 
106 	/* fall through */
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))
111 			return -EINVAL;
112 
113 		if (spec->type != UVERBS_ATTR_TYPE_ENUM_IN &&
114 		    uattr->attr_data.reserved)
115 			return -EINVAL;
116 
117 		e->ptr_attr.data = uattr->data;
118 		e->ptr_attr.len = uattr->len;
119 		e->ptr_attr.flags = uattr->flags;
120 		break;
121 
122 	case UVERBS_ATTR_TYPE_IDR:
123 		if (uattr->data >> 32)
124 			return -EINVAL;
125 	/* fall through */
126 	case UVERBS_ATTR_TYPE_FD:
127 		if (uattr->attr_data.reserved)
128 			return -EINVAL;
129 
130 		if (uattr->len != 0 || !ucontext || uattr->data > INT_MAX)
131 			return -EINVAL;
132 
133 		o_attr = &e->obj_attr;
134 		object = uverbs_get_object(ibdev, spec->obj.obj_type);
135 		if (!object)
136 			return -EINVAL;
137 		o_attr->type = object->type_attrs;
138 
139 		o_attr->id = (int)uattr->data;
140 		o_attr->uobject = uverbs_get_uobject_from_context(
141 					o_attr->type,
142 					ucontext,
143 					spec->obj.access,
144 					o_attr->id);
145 
146 		if (IS_ERR(o_attr->uobject))
147 			return PTR_ERR(o_attr->uobject);
148 
149 		if (spec->obj.access == UVERBS_ACCESS_NEW) {
150 			u64 id = o_attr->uobject->id;
151 
152 			/* Copy the allocated id to the user-space */
153 			if (put_user(id, &e->uattr->data)) {
154 				uverbs_finalize_object(o_attr->uobject,
155 						       UVERBS_ACCESS_NEW,
156 						       false);
157 				return -EFAULT;
158 			}
159 		}
160 
161 		break;
162 	default:
163 		return -EOPNOTSUPP;
164 	}
165 
166 	set_bit(attr_id, attr_bundle_h->valid_bitmap);
167 	return 0;
168 }
169 
170 static int uverbs_uattrs_process(struct ib_device *ibdev,
171 				 struct ib_ucontext *ucontext,
172 				 const struct ib_uverbs_attr *uattrs,
173 				 size_t num_uattrs,
174 				 const struct uverbs_method_spec *method,
175 				 struct uverbs_attr_bundle *attr_bundle,
176 				 struct ib_uverbs_attr __user *uattr_ptr)
177 {
178 	size_t i;
179 	int ret = 0;
180 	int num_given_buckets = 0;
181 
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;
186 
187 		ret = uverbs_ns_idx(&attr_id, method->num_buckets);
188 		if (ret < 0) {
189 			if (uattr->flags & UVERBS_ATTR_F_MANDATORY) {
190 				uverbs_finalize_objects(attr_bundle,
191 							method->attr_buckets,
192 							num_given_buckets,
193 							false);
194 				return ret;
195 			}
196 			continue;
197 		}
198 
199 		/*
200 		 * ret is the found ns, so increase num_given_buckets if
201 		 * necessary.
202 		 */
203 		if (ret >= num_given_buckets)
204 			num_given_buckets = ret + 1;
205 
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],
209 					  uattr_ptr++);
210 		if (ret) {
211 			uverbs_finalize_objects(attr_bundle,
212 						method->attr_buckets,
213 						num_given_buckets,
214 						false);
215 			return ret;
216 		}
217 	}
218 
219 	return num_given_buckets;
220 }
221 
222 static int uverbs_validate_kernel_mandatory(const struct uverbs_method_spec *method_spec,
223 					    struct uverbs_attr_bundle *attr_bundle)
224 {
225 	unsigned int i;
226 
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];
230 
231 		if (!bitmap_subset(attr_spec_bucket->mandatory_attrs_bitmask,
232 				   attr_bundle->hash[i].valid_bitmap,
233 				   attr_spec_bucket->num_attrs))
234 			return -EINVAL;
235 	}
236 
237 	return 0;
238 }
239 
240 static int uverbs_handle_method(struct ib_uverbs_attr __user *uattr_ptr,
241 				const struct ib_uverbs_attr *uattrs,
242 				size_t num_uattrs,
243 				struct ib_device *ibdev,
244 				struct ib_uverbs_file *ufile,
245 				const struct uverbs_method_spec *method_spec,
246 				struct uverbs_attr_bundle *attr_bundle)
247 {
248 	int ret;
249 	int finalize_ret;
250 	int num_given_buckets;
251 
252 	num_given_buckets = uverbs_uattrs_process(ibdev, ufile->ucontext, uattrs,
253 						  num_uattrs, method_spec,
254 						  attr_bundle, uattr_ptr);
255 	if (num_given_buckets <= 0)
256 		return -EINVAL;
257 
258 	attr_bundle->num_buckets = num_given_buckets;
259 	ret = uverbs_validate_kernel_mandatory(method_spec, attr_bundle);
260 	if (ret)
261 		goto cleanup;
262 
263 	ret = method_spec->handler(ibdev, ufile, attr_bundle);
264 cleanup:
265 	finalize_ret = uverbs_finalize_objects(attr_bundle,
266 					       method_spec->attr_buckets,
267 					       attr_bundle->num_buckets,
268 					       !ret);
269 
270 	return ret ? ret : finalize_ret;
271 }
272 
273 #define UVERBS_OPTIMIZE_USING_STACK_SZ  256
274 static long ib_uverbs_cmd_verbs(struct ib_device *ib_dev,
275 				struct ib_uverbs_file *file,
276 				struct ib_uverbs_ioctl_hdr *hdr,
277 				void __user *buf)
278 {
279 	const struct uverbs_object_spec *object_spec;
280 	const struct uverbs_method_spec *method_spec;
281 	long err = 0;
282 	unsigned int i;
283 	struct {
284 		struct ib_uverbs_attr		*uattrs;
285 		struct uverbs_attr_bundle	*uverbs_attr_bundle;
286 	} *ctx = NULL;
287 	struct uverbs_attr *curr_attr;
288 	unsigned long *curr_bitmap;
289 	size_t ctx_size;
290 	uintptr_t data[UVERBS_OPTIMIZE_USING_STACK_SZ / sizeof(uintptr_t)];
291 
292 	if (hdr->driver_id != ib_dev->driver_id)
293 		return -EINVAL;
294 
295 	object_spec = uverbs_get_object(ib_dev, hdr->object_id);
296 	if (!object_spec)
297 		return -EPROTONOSUPPORT;
298 
299 	method_spec = uverbs_get_method(object_spec, hdr->method_id);
300 	if (!method_spec)
301 		return -EPROTONOSUPPORT;
302 
303 	if ((method_spec->flags & UVERBS_ACTION_FLAG_CREATE_ROOT) ^ !file->ucontext)
304 		return -EINVAL;
305 
306 	ctx_size = sizeof(*ctx) +
307 		   sizeof(struct uverbs_attr_bundle) +
308 		   sizeof(struct uverbs_attr_bundle_hash) * method_spec->num_buckets +
309 		   sizeof(*ctx->uattrs) * hdr->num_attrs +
310 		   sizeof(*ctx->uverbs_attr_bundle->hash[0].attrs) *
311 		   method_spec->num_child_attrs +
312 		   sizeof(*ctx->uverbs_attr_bundle->hash[0].valid_bitmap) *
313 			(method_spec->num_child_attrs / BITS_PER_LONG +
314 			 method_spec->num_buckets);
315 
316 	if (ctx_size <= UVERBS_OPTIMIZE_USING_STACK_SZ)
317 		ctx = (void *)data;
318 	if (!ctx)
319 		ctx = kmalloc(ctx_size, GFP_KERNEL);
320 	if (!ctx)
321 		return -ENOMEM;
322 
323 	ctx->uverbs_attr_bundle = (void *)ctx + sizeof(*ctx);
324 	ctx->uattrs = (void *)(ctx->uverbs_attr_bundle + 1) +
325 			      (sizeof(ctx->uverbs_attr_bundle->hash[0]) *
326 			       method_spec->num_buckets);
327 	curr_attr = (void *)(ctx->uattrs + hdr->num_attrs);
328 	curr_bitmap = (void *)(curr_attr + method_spec->num_child_attrs);
329 
330 	/*
331 	 * We just fill the pointers and num_attrs here. The data itself will be
332 	 * filled at a later stage (uverbs_process_attr)
333 	 */
334 	for (i = 0; i < method_spec->num_buckets; i++) {
335 		unsigned int curr_num_attrs = method_spec->attr_buckets[i]->num_attrs;
336 
337 		ctx->uverbs_attr_bundle->hash[i].attrs = curr_attr;
338 		curr_attr += curr_num_attrs;
339 		ctx->uverbs_attr_bundle->hash[i].num_attrs = curr_num_attrs;
340 		ctx->uverbs_attr_bundle->hash[i].valid_bitmap = curr_bitmap;
341 		bitmap_zero(curr_bitmap, curr_num_attrs);
342 		curr_bitmap += BITS_TO_LONGS(curr_num_attrs);
343 	}
344 
345 	err = copy_from_user(ctx->uattrs, buf,
346 			     sizeof(*ctx->uattrs) * hdr->num_attrs);
347 	if (err) {
348 		err = -EFAULT;
349 		goto out;
350 	}
351 
352 	err = uverbs_handle_method(buf, ctx->uattrs, hdr->num_attrs, ib_dev,
353 				   file, method_spec, ctx->uverbs_attr_bundle);
354 
355 	/*
356 	 * EPROTONOSUPPORT is ONLY to be returned if the ioctl framework can
357 	 * not invoke the method because the request is not supported.  No
358 	 * other cases should return this code.
359 	*/
360 	if (unlikely(err == -EPROTONOSUPPORT)) {
361 		WARN_ON_ONCE(err == -EPROTONOSUPPORT);
362 		err = -EINVAL;
363 	}
364 out:
365 	if (ctx != (void *)data)
366 		kfree(ctx);
367 	return err;
368 }
369 
370 #define IB_UVERBS_MAX_CMD_SZ 4096
371 
372 long ib_uverbs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
373 {
374 	struct ib_uverbs_file *file = filp->private_data;
375 	struct ib_uverbs_ioctl_hdr __user *user_hdr =
376 		(struct ib_uverbs_ioctl_hdr __user *)arg;
377 	struct ib_uverbs_ioctl_hdr hdr;
378 	struct ib_device *ib_dev;
379 	int srcu_key;
380 	long err;
381 
382 	srcu_key = srcu_read_lock(&file->device->disassociate_srcu);
383 	ib_dev = srcu_dereference(file->device->ib_dev,
384 				  &file->device->disassociate_srcu);
385 	if (!ib_dev) {
386 		err = -EIO;
387 		goto out;
388 	}
389 
390 	if (cmd == RDMA_VERBS_IOCTL) {
391 		err = copy_from_user(&hdr, user_hdr, sizeof(hdr));
392 
393 		if (err || hdr.length > IB_UVERBS_MAX_CMD_SZ ||
394 		    hdr.length != sizeof(hdr) + hdr.num_attrs * sizeof(struct ib_uverbs_attr)) {
395 			err = -EINVAL;
396 			goto out;
397 		}
398 
399 		if (hdr.reserved1 || hdr.reserved2) {
400 			err = -EPROTONOSUPPORT;
401 			goto out;
402 		}
403 
404 		err = ib_uverbs_cmd_verbs(ib_dev, file, &hdr,
405 					  (__user void *)arg + sizeof(hdr));
406 	} else {
407 		err = -ENOIOCTLCMD;
408 	}
409 out:
410 	srcu_read_unlock(&file->device->disassociate_srcu, srcu_key);
411 
412 	return err;
413 }
414