The regcmd fields in drm_rocket_task come from userspace and are programmed into the PC unit without any validation.
Bits 31:4 of PC_BASE_ADDRESS hold the register command DMA address and bit 0 selects slave mode, so a misaligned regcmd silently drops its low bits, and an odd address flips the PC unit into slave mode. Similarly, pc_data_amount is a 16-bit field holding (regcmd_count + 1) / 2 - 1, so a larger regcmd_count is silently truncated by the register encoding. Reject unaligned regcmd addresses and out-of-range regcmd_count with -EINVAL at submission time. Existing userspace is not affected: Mesa places regcmd buffers at 64-byte aligned offsets, and its regcmd counts stay far below the limit. Signed-off-by: Sidong Yang <[email protected]> --- drivers/accel/rocket/rocket_job.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/accel/rocket/rocket_job.c b/drivers/accel/rocket/rocket_job.c index bb77b6bf0f23..9ebabf86fe97 100644 --- a/drivers/accel/rocket/rocket_job.c +++ b/drivers/accel/rocket/rocket_job.c @@ -7,6 +7,7 @@ #include <drm/drm_file.h> #include <drm/drm_gem.h> #include <drm/rocket_accel.h> +#include <linux/align.h> #include <linux/interrupt.h> #include <linux/overflow.h> #include <linux/iommu.h> @@ -21,6 +22,15 @@ #define JOB_TIMEOUT_MS 500 +/* + * The PC unit fetches two 64-bit register commands per pc_data_amount unit, + * and the field holds (regcmd_count + 1) / 2 - 1. + */ +#define ROCKET_MAX_REGCMDS ((PC_REGISTER_AMOUNTS_PC_DATA_AMOUNT__MASK + 1) * 2U) + +/* Bits 3:0 of PC_BASE_ADDRESS hold the mode selection bit and reserved bits */ +#define ROCKET_REGCMD_ALIGN 16 + static struct rocket_job * to_rocket_job(struct drm_sched_job *sched_job) { @@ -95,6 +105,20 @@ rocket_copy_tasks(struct drm_device *dev, goto fail; } + if (task.regcmd_count > ROCKET_MAX_REGCMDS) { + drm_dbg(dev, "regcmd_count field in drm_rocket_task should be <= %u.\n", + ROCKET_MAX_REGCMDS); + ret = -EINVAL; + goto fail; + } + + if (!IS_ALIGNED(task.regcmd, ROCKET_REGCMD_ALIGN)) { + drm_dbg(dev, "regcmd field in drm_rocket_task should be aligned to %u bytes.\n", + ROCKET_REGCMD_ALIGN); + ret = -EINVAL; + goto fail; + } + rjob->tasks[i].regcmd = task.regcmd; rjob->tasks[i].regcmd_count = task.regcmd_count; } base-commit: a284476db2653ae893f46cbea408eb412db54eb0 -- 2.42.0
