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
16int 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