⬢ DragonFlyBSD Kernel Audit
DF-4348 / fix.diff
← back to finding ↓ download raw
--- 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: ");