atom_op_calltable() invokes a child ATOM table, forwarding the parent's parameter space with an offset: amdgpu_atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift, ctx->ps_size - ctx->ps_shift); ctx->ps_shift is derived from the child table's PS byte count (ps / 4) in amdgpu_atom_execute_table_locked(), while ctx->ps_size carries the remaining capacity from the parent. A malformed ATOM table chain in the VBIOS (or a GPU that reports corrupted table headers) can produce ps_shift > ps_size, underflowing the subtraction to a huge positive value passed as params_size to the recursive call. The child table then reads and writes far beyond the stack-allocated parameter buffer. Reject the call when the shift exceeds the available size. Fixes: d38ceaf99ed0 ("drm/amdgpu: add coordinate ATOMBIOS table support") Cc: stable@vger.kernel.org Reported-by: Sashiko Signed-off-by: Aldo Ariel Panzardo --- diff --git a/drivers/gpu/drm/amd/amdgpu/atom.c b/drivers/gpu/drm/amd/amdgpu/atom.c diff --git a/drivers/gpu/drm/amd/amdgpu/atom.c b/drivers/gpu/drm/amd/amdgpu/atom.c index e0e585f..638bd18 100644 --- a/drivers/gpu/drm/amd/amdgpu/atom.c +++ b/drivers/gpu/drm/amd/amdgpu/atom.c @@ -646,8 +646,13 @@ static void atom_op_calltable(atom_exec_context *ctx, int *ptr, int arg) SDEBUG(" table: %d (%s)\n", idx, atom_table_names[idx]); else SDEBUG(" table: %d\n", idx); - if (U16(ctx->ctx->cmd_table + 4 + 2 * idx)) + if (U16(ctx->ctx->cmd_table + 4 + 2 * idx)) { + if (ctx->ps_shift > ctx->ps_size) { + ctx->abort = true; + return; + } r = amdgpu_atom_execute_table_locked(ctx->ctx, idx, ctx->ps + ctx->ps_shift, ctx->ps_size - ctx->ps_shift); + } if (r) { ctx->abort = true; } -- 2.43.0