The GSP sequencer RPC contains a variable command stream. The handler
currently walks commands using the stream header length without first
proving that the stream, each command payload, or a register-save slot
fits in the received RPC and its fixed save area.

Validate the stream and each command against the RPC payload before
walking it, and reject register-save indexes beyond the fixed save
array.

Signed-off-by: Pengpeng Hou <[email protected]>
---
 .../drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c | 22 +++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c 
b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c
index f544afa12b6b..00417bbccc12 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/rm/r535/gsp.c
@@ -1010,15 +1010,30 @@ r535_gsp_msg_run_cpu_sequencer(void *priv, u32 fn, void 
*repv, u32 repc)
        struct nvkm_subdev *subdev = &gsp->subdev;
        struct nvkm_device *device = subdev->device;
        rpc_run_cpu_sequencer_v17_00 *seq = repv;
-       int ptr = 0, ret;
+       u32 ptr = 0, payload;
+       int ret;
+
+       if (repc < offsetof(rpc_run_cpu_sequencer_v17_00, commandBuffer) ||
+           seq->cmdIndex >
+           (repc - offsetof(rpc_run_cpu_sequencer_v17_00, commandBuffer)) /
+           sizeof(seq->commandBuffer[0])) {
+               nvkm_error(subdev, "invalid sequencer command buffer size\n");
+               return -EINVAL;
+       }
 
        nvkm_debug(subdev, "seq: %08x %08x\n", seq->bufferSizeDWord, 
seq->cmdIndex);
 
        while (ptr < seq->cmdIndex) {
                GSP_SEQUENCER_BUFFER_CMD *cmd = (void 
*)&seq->commandBuffer[ptr];
 
+               payload = GSP_SEQUENCER_PAYLOAD_SIZE_DWORDS(cmd->opCode);
+               if (seq->cmdIndex - ptr < payload + 1) {
+                       nvkm_error(subdev, "truncated sequencer command\n");
+                       return -EINVAL;
+               }
+
                ptr += 1;
-               ptr += GSP_SEQUENCER_PAYLOAD_SIZE_DWORDS(cmd->opCode);
+               ptr += payload;
 
                switch (cmd->opCode) {
                case GSP_SEQ_BUF_OPCODE_REG_WRITE: {
@@ -1064,6 +1079,9 @@ r535_gsp_msg_run_cpu_sequencer(void *priv, u32 fn, void 
*repv, u32 repc)
                        u32 addr = cmd->payload.regStore.addr;
                        u32 slot = cmd->payload.regStore.index;
 
+                       if (slot >= ARRAY_SIZE(seq->regSaveArea))
+                               return -EINVAL;
+
                        seq->regSaveArea[slot] = nvkm_rd32(device, addr);
                        nvkm_trace(subdev, "seq save %08x -> %d: %08x\n", addr, 
slot,
                                   seq->regSaveArea[slot]);
-- 
2.43.0

Reply via email to