xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/i915/i915_user_extensions.c (revision 41ec02673d281bbb3d38e6c78504ce6e30c228c1)
1 /*	$NetBSD: i915_user_extensions.c,v 1.2 2021/12/18 23:45:28 riastradh Exp $	*/
2 
3 /*
4  * SPDX-License-Identifier: MIT
5  *
6  * Copyright © 2018 Intel Corporation
7  */
8 
9 #include <sys/cdefs.h>
10 __KERNEL_RCSID(0, "$NetBSD: i915_user_extensions.c,v 1.2 2021/12/18 23:45:28 riastradh Exp $");
11 
12 #include <linux/nospec.h>
13 #include <linux/sched/signal.h>
14 #include <linux/uaccess.h>
15 
16 #include <uapi/drm/i915_drm.h>
17 
18 #include "i915_user_extensions.h"
19 #include "i915_utils.h"
20 
i915_user_extensions(struct i915_user_extension __user * ext,const i915_user_extension_fn * tbl,unsigned int count,void * data)21 int i915_user_extensions(struct i915_user_extension __user *ext,
22 			 const i915_user_extension_fn *tbl,
23 			 unsigned int count,
24 			 void *data)
25 {
26 	unsigned int stackdepth = 512;
27 
28 	while (ext) {
29 		int i, err;
30 		u32 name;
31 		u64 next;
32 
33 		if (!stackdepth--) /* recursion vs useful flexibility */
34 			return -E2BIG;
35 
36 		err = check_user_mbz(&ext->flags);
37 		if (err)
38 			return err;
39 
40 		for (i = 0; i < ARRAY_SIZE(ext->rsvd); i++) {
41 			err = check_user_mbz(&ext->rsvd[i]);
42 			if (err)
43 				return err;
44 		}
45 
46 		if (get_user(name, &ext->name))
47 			return -EFAULT;
48 
49 		err = -EINVAL;
50 		if (name < count) {
51 			name = array_index_nospec(name, count);
52 			if (tbl[name])
53 				err = tbl[name](ext, data);
54 		}
55 		if (err)
56 			return err;
57 
58 		if (get_user(next, &ext->next_extension) ||
59 		    overflows_type(next, ext))
60 			return -EFAULT;
61 
62 		ext = u64_to_user_ptr(next);
63 	}
64 
65 	return 0;
66 }
67