162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * SPDX-License-Identifier: MIT
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright © 2018 Intel Corporation
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/nospec.h>
862306a36Sopenharmony_ci#include <linux/sched/signal.h>
962306a36Sopenharmony_ci#include <linux/uaccess.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <uapi/drm/i915_drm.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "i915_user_extensions.h"
1462306a36Sopenharmony_ci#include "i915_utils.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ciint i915_user_extensions(struct i915_user_extension __user *ext,
1762306a36Sopenharmony_ci			 const i915_user_extension_fn *tbl,
1862306a36Sopenharmony_ci			 unsigned int count,
1962306a36Sopenharmony_ci			 void *data)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	unsigned int stackdepth = 512;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	while (ext) {
2462306a36Sopenharmony_ci		int i, err;
2562306a36Sopenharmony_ci		u32 name;
2662306a36Sopenharmony_ci		u64 next;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci		if (!stackdepth--) /* recursion vs useful flexibility */
2962306a36Sopenharmony_ci			return -E2BIG;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci		err = check_user_mbz(&ext->flags);
3262306a36Sopenharmony_ci		if (err)
3362306a36Sopenharmony_ci			return err;
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(ext->rsvd); i++) {
3662306a36Sopenharmony_ci			err = check_user_mbz(&ext->rsvd[i]);
3762306a36Sopenharmony_ci			if (err)
3862306a36Sopenharmony_ci				return err;
3962306a36Sopenharmony_ci		}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci		if (get_user(name, &ext->name))
4262306a36Sopenharmony_ci			return -EFAULT;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci		err = -EINVAL;
4562306a36Sopenharmony_ci		if (name < count) {
4662306a36Sopenharmony_ci			name = array_index_nospec(name, count);
4762306a36Sopenharmony_ci			if (tbl[name])
4862306a36Sopenharmony_ci				err = tbl[name](ext, data);
4962306a36Sopenharmony_ci		}
5062306a36Sopenharmony_ci		if (err)
5162306a36Sopenharmony_ci			return err;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci		if (get_user(next, &ext->next_extension) ||
5462306a36Sopenharmony_ci		    overflows_type(next, uintptr_t))
5562306a36Sopenharmony_ci			return -EFAULT;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci		ext = u64_to_user_ptr(next);
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	return 0;
6162306a36Sopenharmony_ci}
62