0001
0002
0003
0004
0005
0006
0007 #include <linux/nospec.h>
0008 #include <linux/sched/signal.h>
0009 #include <linux/uaccess.h>
0010
0011 #include <uapi/drm/i915_drm.h>
0012
0013 #include "i915_user_extensions.h"
0014 #include "i915_utils.h"
0015
0016 int i915_user_extensions(struct i915_user_extension __user *ext,
0017 const i915_user_extension_fn *tbl,
0018 unsigned int count,
0019 void *data)
0020 {
0021 unsigned int stackdepth = 512;
0022
0023 while (ext) {
0024 int i, err;
0025 u32 name;
0026 u64 next;
0027
0028 if (!stackdepth--)
0029 return -E2BIG;
0030
0031 err = check_user_mbz(&ext->flags);
0032 if (err)
0033 return err;
0034
0035 for (i = 0; i < ARRAY_SIZE(ext->rsvd); i++) {
0036 err = check_user_mbz(&ext->rsvd[i]);
0037 if (err)
0038 return err;
0039 }
0040
0041 if (get_user(name, &ext->name))
0042 return -EFAULT;
0043
0044 err = -EINVAL;
0045 if (name < count) {
0046 name = array_index_nospec(name, count);
0047 if (tbl[name])
0048 err = tbl[name](ext, data);
0049 }
0050 if (err)
0051 return err;
0052
0053 if (get_user(next, &ext->next_extension) ||
0054 overflows_type(next, ext))
0055 return -EFAULT;
0056
0057 ext = u64_to_user_ptr(next);
0058 }
0059
0060 return 0;
0061 }