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