⬢ DragonFlyBSD Kernel Audit
DF-4340 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/radeon/atom.c
+++ b/sys/dev/drm/radeon/atom.c
@@ -84,6 +84,20 @@
 };
 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: gcc -O1 folds 0xffff << 40 to 0).  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)
@@ -248,12 +262,12 @@
 		case ATOM_WS_SHIFT:
 			val = gctx->shift;
 			break;
-		case ATOM_WS_OR_MASK:
-			val = 1 << gctx->shift;
-			break;
-		case ATOM_WS_AND_MASK:
-			val = ~(1 << gctx->shift);
-			break;
+	case ATOM_WS_OR_MASK:
+		val = atom_shl(1, gctx->shift);
+		break;
+	case ATOM_WS_AND_MASK:
+		val = ~atom_shl(1, gctx->shift);
+		break;
 		case ATOM_WS_FB_WINDOW:
 			val = gctx->fb_base;
 			break;
@@ -901,7 +915,7 @@
 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
 	shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
 	ATOM_SDEBUG_PRINT("   shift: %d\n", shift);
-	dst <<= shift;
+	dst = atom_shl(dst, shift);
 	ATOM_SDEBUG_PRINT("   dst: ");
 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
 }
@@ -917,7 +931,7 @@
 	dst = atom_get_dst(ctx, arg, attr, ptr, &saved, 1);
 	shift = atom_get_src_direct(ctx, ATOM_SRC_BYTE0, ptr);
 	ATOM_SDEBUG_PRINT("   shift: %d\n", shift);
-	dst >>= shift;
+	dst = atom_shr(dst, shift);
 	ATOM_SDEBUG_PRINT("   dst: ");
 	atom_put_dst(ctx, arg, attr, &dptr, dst, saved);
 }
@@ -934,7 +948,7 @@
 	dst = saved;
 	shift = atom_get_src(ctx, attr, ptr);
 	ATOM_SDEBUG_PRINT("   shift: %d\n", shift);
-	dst <<= shift;
+	dst = atom_shl(dst, shift);
 	dst &= atom_arg_mask[dst_align];
 	dst >>= atom_arg_shift[dst_align];
 	ATOM_SDEBUG_PRINT("   dst: ");
@@ -953,7 +967,7 @@
 	dst = saved;
 	shift = atom_get_src(ctx, attr, ptr);
 	ATOM_SDEBUG_PRINT("   shift: %d\n", shift);
-	dst >>= shift;
+	dst = atom_shr(dst, shift);
 	dst &= atom_arg_mask[dst_align];
 	dst >>= atom_arg_shift[dst_align];
 	ATOM_SDEBUG_PRINT("   dst: ");