i915_user_extensions.c 1.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. /*
  2. * SPDX-License-Identifier: MIT
  3. *
  4. * Copyright © 2018 Intel Corporation
  5. */
  6. #include <linux/nospec.h>
  7. #include <linux/sched/signal.h>
  8. #include <linux/uaccess.h>
  9. #include <uapi/drm/i915_drm.h>
  10. #include "i915_user_extensions.h"
  11. #include "i915_utils.h"
  12. int i915_user_extensions(struct i915_user_extension __user *ext,
  13. const i915_user_extension_fn *tbl,
  14. unsigned int count,
  15. void *data)
  16. {
  17. unsigned int stackdepth = 512;
  18. while (ext) {
  19. int i, err;
  20. u32 name;
  21. u64 next;
  22. if (!stackdepth--) /* recursion vs useful flexibility */
  23. return -E2BIG;
  24. err = check_user_mbz(&ext->flags);
  25. if (err)
  26. return err;
  27. for (i = 0; i < ARRAY_SIZE(ext->rsvd); i++) {
  28. err = check_user_mbz(&ext->rsvd[i]);
  29. if (err)
  30. return err;
  31. }
  32. if (get_user(name, &ext->name))
  33. return -EFAULT;
  34. err = -EINVAL;
  35. if (name < count) {
  36. name = array_index_nospec(name, count);
  37. if (tbl[name])
  38. err = tbl[name](ext, data);
  39. }
  40. if (err)
  41. return err;
  42. if (get_user(next, &ext->next_extension) ||
  43. overflows_type(next, uintptr_t))
  44. return -EFAULT;
  45. ext = u64_to_user_ptr(next);
  46. }
  47. return 0;
  48. }