Re: [PATCH] drm/amdgpu: bound ATOM bytecode cursor within the VBIOS image
Alex Deucher <[email protected]> Tue, 4 Aug 2026 10:00:54 -0400
| Newsgroups | dev.linux.lists.sashiko-reviews,org.freedesktop.lists.dri-devel |
|---|---|
| Message-ID | <CADnq5_PZ2i9d+eOdMEkSYynxzqO5E0iO0fXX77PRhZ420eBVNA@mail.gmail.com> |
On Thu, Jul 30, 2026 at 1:33=E2=80=AFPM <[email protected]> wrote: > > Thank you for your contribution! Sashiko AI review found 6 potential issu= e(s) to consider: > > New issues: > - [High] The newly added bounds check in `atom_op_switch` breaks out of t= he loop on malformed data without setting the abort flag, allowing garbage = execution. > > Pre-existing issues: > - [Critical] Kernel stack buffer overflow due to unit mismatch between `p= s_size` (passed in bytes) and parameter array indexing (processed in dwords= ). > - [Critical] Nested ATOM command tables can underflow `ps_size` and bypas= s bounds checks, causing an arbitrary kernel stack buffer overflow. > - [Critical] The bounds check for `ATOM_ARG_FB` scratch memory accesses i= s vulnerable to an off-by-one error and integer overflow, allowing arbitrar= y out-of-bounds kernel memory corruption. > - [High] The patch bounds-checks the initial opcode fetch but fails to bo= und variable-length operand fetches, leaving the interpreter vulnerable to = out-of-bounds reads. > - [High] Command table directory index `base` is read from the VBIOS imag= e without bounds checking the index calculation itself. > -- > > --- Patch [1]: [PATCH] drm/amdgpu: bound ATOM bytecode cursor within the = VBIOS image --- > commit e34469f5366554f7ff6d1ad26ef62ec969ed0a40 > Author: Hari Mishal <[email protected]> > drm/amdgpu: bound ATOM bytecode cursor within the VBIOS image > > The commit bounds-checks several ATOM interpreter opcode fetch and table > jump paths against the VBIOS image size to prevent out-of-bounds reads > on malformed images. It utilizes the existing ctx->bios_size infrastructu= re. > > > diff --git a/drivers/gpu/drm/amd/amdgpu/atom.c b/drivers/gpu/drm/amd/am= dgpu/atom.c > > --- a/drivers/gpu/drm/amd/amdgpu/atom.c > > +++ b/drivers/gpu/drm/amd/amdgpu/atom.c > > [ ... ] > > > @@ -1032,8 +1032,12 @@ static void atom_op_switch(atom_exec_context *ct= x, int *ptr, int arg) > > uint32_t src, val, target; > > SDEBUG(" switch: "); > > src =3D atom_get_src(ctx, attr, ptr); > > - while (U16(*ptr) !=3D ATOM_CASE_END) > > + while ((uint32_t)*ptr + 2 <=3D ctx->ctx->bios_size && > > + U16(*ptr) !=3D ATOM_CASE_END) > > if (U8(*ptr) =3D=3D ATOM_CASE_MAGIC) { > > + /* magic byte + immediate (up to 4) + 2-byte targ= et */ > > + if ((uint32_t)*ptr + 7 > ctx->ctx->bios_size) > > + break; > > [Severity: High] > Does breaking out of this loop without setting ctx->abort =3D true allow = the > interpreter to continue execution? > > It seems the function advances the pointer and returns normally when this > bounds check fails, which might cause the interpreter loop to fetch the n= ext > byte from the middle of the switch data and execute it as garbage opcodes= . > Hari, can you double check this and respin if necessary? Thanks, Alex > [ ... ] > > > @@ -1237,6 +1248,13 @@ static int amdgpu_atom_execute_table_locked(stru= ct atom_context *ctx, int index, > > if (!base) > > return -EINVAL; > > > > + /* the table offset itself comes from the VBIOS master table */ > > + if ((uint32_t)base + ATOM_CT_CODE_PTR >=3D ctx->bios_size) { > > [Severity: High] > This isn't a bug introduced by this patch, but is the retrieval of base i= tself > bounds-checked before this new check? > > The command table directory index is read via: > CU16(ctx->cmd_table + 4 + 2 * index) > > If index is arbitrarily large and controlled by the VBIOS, could the macr= o > perform an out-of-bounds heap read before reaching this newly added valid= ation? > > [ ... ] > > > if (ctx->execute_depth >=3D ATOM_EXECUTE_MAX_DEPTH) { > > DRM_ERROR("atombios command table nesting exceeded limit = (%u)\n", > > ATOM_EXECUTE_MAX_DEPTH); > > [Severity: Critical] > This isn't a bug introduced by this patch, but are nested ATOM command ta= bles > safe from size underflows? > > When atom_op_calltable() recursively calls amdgpu_atom_execute_table_lock= ed(), > it passes ctx->ps_size - ctx->ps_shift for the params_size. > > If a malformed VBIOS specifies a ps_shift larger than ps_size, could this > uncontrolled subtraction underflow and promote to a large unsigned bound > during execution, bypassing bounds checks like idx < ctx->ps_size? > > [Severity: Critical] > This is another pre-existing issue, but do atom_get_src_int() and > atom_put_dst() incorrectly process ps_size as a dword limit instead of by= tes? > > External callers pass a stack-allocated structure and its byte size to > amdgpu_atom_execute_table(). If the VBIOS-supplied idx is used to index t= he > uint32_t *ps array, could passing idx =3D 7 for an 8-byte structure pass = the > idx < 8 check but access the 7th dword, leading to out-of-bounds stack > reads and writes? > > [ ... ] > > > @@ -1273,6 +1291,13 @@ static int amdgpu_atom_execute_table_locked(stru= ct atom_context *ctx, int index, > > > > debug_depth++; > > while (1) { > > + /* jump/skip targets are bytecode-supplied; stay inside t= he image */ > > + if ((uint32_t)ptr >=3D ctx->bios_size) { > > + DRM_ERROR("atombios cursor 0x%x outside VBIOS ima= ge (table %04X)\n", > > + ptr, base); > > + ret =3D -EINVAL; > > + goto free; > > + } > > op =3D CU8(ptr++); > > [Severity: High] > This isn't a bug introduced by this patch, but does this bounds check onl= y > protect the opcode byte itself? > > The individual opcode handlers executed later via opcode_table[op].func() > appear to unconditionally fetch subsequent variable-length arguments. If = the > image ends immediately after an opcode, could these operand fetches perfo= rm > out-of-bounds reads? > > [Severity: Critical] > This is a pre-existing issue, but is the bounds check for ATOM_ARG_FB scr= atch > memory accesses in atom_put_dst() susceptible to integer overflow? > > The bounds check appears to be: > if ((gctx->fb_base + (idx * 4)) > gctx->scratch_size_bytes) > > Since it uses > instead of >=3D, it might allow an off-by-one access. Mor= e > importantly, if gctx->fb_base and idx are 32-bit values controlled by the > VBIOS, could their addition wrap around a 32-bit integer and bypass the > bounds check entirely? > > -- > Sashiko AI review =C2=B7 https://sashiko.dev/#/patchset/20260730170011.28= [email protected]?part=3D1