⬢ DragonFlyBSD Kernel Audit
DF-4104 / fix.diff
← back to finding ↓ download raw
--- a/sys/dev/drm/amd/amdgpu/atom.h
+++ b/sys/dev/drm/amd/amdgpu/atom.h
@@ -129,6 +129,7 @@ struct atom_context {
 	struct lock mutex;
 	void *bios;
+	int bios_size;
 	uint32_t cmd_table, data_table;
 	uint16_t *iio;
--- a/sys/dev/drm/amd/amdgpu/atom.c
+++ b/sys/dev/drm/amd/amdgpu/atom.c
@@ -1314,6 +1314,7 @@ struct atom_context *amdgpu_atom_parse(struct card_info *card, void *bios)
 	ctx->card = card;
 	ctx->bios = bios;
+	ctx->bios_size = 0;	/* caller patches via amdgpu_atom_parse_bios_size */
 
 	base = CU16(ATOM_ROM_TABLE_PTR);
@@ -1384,9 +1385,16 @@ bool amdgpu_atom_parse_data_header(struct atom_context *ctx, int index,
 	if (size)
 		*size = CU16(idx);
 	if (frev)
 		*frev = CU8(idx + 2);
 	if (crev)
 		*crev = CU8(idx + 3);
+	/*
+	 * The table header itself must lie inside the BIOS image;
+	 * consumers additionally validate data_start + sizeof(struct).
+	 */
+	if (ctx->bios_size && idx + 4 > ctx->bios_size)
+		return false;
 	*data_start = idx;
 	return true;
 }
+
+void amdgpu_atom_parse_bios_size(struct atom_context *ctx, int size)
+{
+	ctx->bios_size = size;
+}
--- a/sys/dev/drm/amd/amdgpu/atombios_encoders.c
+++ b/sys/dev/drm/amd/amdgpu/atombios_encoders.c
@@ -2081,7 +2081,9 @@ amdgpu_atombios_encoder_get_lcd_info(struct amdgpu_encoder *encoder)
 
 	if (amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
 				   &frev, &crev, &data_offset)) {
+		if (mode_info->atom_context->bios_size &&
+		    (int)data_offset + sizeof(union lvds_info) >
+		    mode_info->atom_context->bios_size)
+			return NULL;
 		lvds_info =
 			(union lvds_info *)(mode_info->atom_context->bios + data_offset);
--- a/sys/dev/drm/amd/amdgpu/amdgpu_atombios.c
+++ b/sys/dev/drm/amd/amdgpu/amdgpu_atombios.c
@@ -2037,6 +2037,8 @@ int amdgpu_atombios_init(struct amdgpu_device *adev)
 		return -ENOMEM;
 
 	adev->mode_info.atom_context = amdgpu_atom_parse(atom_card_info, adev->bios);
+	amdgpu_atom_parse_bios_size(adev->mode_info.atom_context,
+				    adev->bios_size);
 	if (!adev->mode_info.atom_context) {
 		kfree(atom_card_info);
 		return -ENOMEM;