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