drm/i915/gvt: Refine non privilege register address calucation
[sfrench/cifs-2.6.git] / drivers / gpu / drm / i915 / i915_user_extensions.c
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, ext))
55                         return -EFAULT;
56
57                 ext = u64_to_user_ptr(next);
58         }
59
60         return 0;
61 }