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  
i915_user_extensions(struct i915_user_extension __user * ext,const i915_user_extension_fn * tbl,unsigned int count,void * data)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