drm/radeon: properly handle vbios fake edid sizing
authorjsg <jsg@openbsd.org>
Mon, 7 Oct 2024 05:14:50 +0000 (05:14 +0000)
committerjsg <jsg@openbsd.org>
Mon, 7 Oct 2024 05:14:50 +0000 (05:14 +0000)
From Alex Deucher
de67850b401946dc683103d11d7814ae5611750e in linux-6.6.y/6.6.54
17c6baff3d5f65c8da164137a58742541a060b2f in mainline linux

sys/dev/pci/drm/radeon/radeon_atombios.c

index 092279f..7ed37b3 100644 (file)
@@ -1720,26 +1720,29 @@ struct radeon_encoder_atom_dig *radeon_atombios_get_lvds_info(struct
                                        fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record;
                                        if (fake_edid_record->ucFakeEDIDLength) {
                                                struct edid *edid;
-                                               int edid_size =
-                                                       max((int)EDID_LENGTH, (int)fake_edid_record->ucFakeEDIDLength);
-                                               edid = kmalloc(edid_size, GFP_KERNEL);
+                                               int edid_size;
+
+                                               if (fake_edid_record->ucFakeEDIDLength == 128)
+                                                       edid_size = fake_edid_record->ucFakeEDIDLength;
+                                               else
+                                                       edid_size = fake_edid_record->ucFakeEDIDLength * 128;
+                                               edid = kmemdup(&fake_edid_record->ucFakeEDIDString[0],
+                                                              edid_size, GFP_KERNEL);
                                                if (edid) {
-                                                       memcpy((u8 *)edid, (u8 *)&fake_edid_record->ucFakeEDIDString[0],
-                                                              fake_edid_record->ucFakeEDIDLength);
-
                                                        if (drm_edid_is_valid(edid)) {
                                                                rdev->mode_info.bios_hardcoded_edid = edid;
                                                                rdev->mode_info.bios_hardcoded_edid_size = edid_size;
-                                                       } else
+                                                       } else {
                                                                kfree(edid);
+                                                       }
                                                }
+                                               record += struct_size(fake_edid_record,
+                                                                     ucFakeEDIDString,
+                                                                     edid_size);
+                                       } else {
+                                               /* empty fake edid record must be 3 bytes long */
+                                               record += sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1;
                                        }
-                                       record += fake_edid_record->ucFakeEDIDLength ?
-                                                 struct_size(fake_edid_record,
-                                                             ucFakeEDIDString,
-                                                             fake_edid_record->ucFakeEDIDLength) :
-                                                 /* empty fake edid record must be 3 bytes long */
-                                                 sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + 1;
                                        break;
                                case LCD_PANEL_RESOLUTION_RECORD_TYPE:
                                        panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record;