--- a/sys/dev/drm/amd/amdgpu/atom.c 2026-09-19 15:20:53.906466085 +0000 +++ b/sys/dev/drm/amd/amdgpu/atom.c 2026-09-19 15:20:53.922465882 +0000 @@ -83,6 +83,21 @@ }; static int atom_def_dst[8] = { 0, 0, 1, 2, 0, 1, 2, 3 }; +/* ATOM shift counts come from untrusted VBIOS operands (bytes or full + * dwords); counts >= 32 are undefined behaviour in C and are compiled + * inconsistently (observed on the audit guest: gcc 8.3 -O1 folds + * 0xffff << 40 to 0 while runtime x86 masking would give << 8). Define + * the intended hardware semantics: shifting by >= the width yields 0. */ +static uint32_t atom_shl(uint32_t v, uint32_t s) +{ + return s < 32 ? (v << s) : 0; +} + +static uint32_t atom_shr(uint32_t v, uint32_t s) +{ + return s < 32 ? (v >> s) : 0; +} + static int debug_depth = 0; #ifdef ATOM_DEBUG static void debug_print_spaces(int n) @@ -238,10 +253,10 @@ val = gctx->shift; break; case ATOM_WS_OR_MASK: - val = 1 << gctx->shift; + val = atom_shl(1, gctx->shift); break; case ATOM_WS_AND_MASK: - val = ~(1 << gctx->shift); + val = ~atom_shl(1, gctx->shift); break; case ATOM_WS_FB_WINDOW: val = gctx->fb_base; @@ -922,7 +937,7 @@ dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr); SDEBUG(" shift: %d\n", shift); - dst <<= shift; + dst = atom_shl(dst, shift); SDEBUG(" dst: "); atom_put_dst(ctx, arg, attr, &dptr, dst, saved); } @@ -938,7 +953,7 @@ dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1); shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr); SDEBUG(" shift: %d\n", shift); - dst >>= shift; + dst = atom_shr(dst, shift); SDEBUG(" dst: "); atom_put_dst(ctx, arg, attr, &dptr, dst, saved); } @@ -955,7 +970,7 @@ dst = saved; shift = atom_get_src(ctx, attr, ptr); SDEBUG(" shift: %d\n", shift); - dst <<= shift; + dst = atom_shl(dst, shift); dst &= atom_arg_mask[dst_align]; dst >>= atom_arg_shift[dst_align]; SDEBUG(" dst: "); @@ -974,7 +989,7 @@ dst = saved; shift = atom_get_src(ctx, attr, ptr); SDEBUG(" shift: %d\n", shift); - dst >>= shift; + dst = atom_shr(dst, shift); dst &= atom_arg_mask[dst_align]; dst >>= atom_arg_shift[dst_align]; SDEBUG(" dst: ");