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