ACPI fix for final 6.13

Prevent acpi_video_device_EDID() from returning a pointer to a memory
 region that should not be passed to kfree() which causes one of its
 users to crash randomly on attempts to free it (Chris Bainbridge).
 -----BEGIN PGP SIGNATURE-----
 
 iQJGBAABCAAwFiEE4fcc61cGeeHD/fCwgsRv/nhiVHEFAmeJF6YSHHJqd0Byand5
 c29ja2kubmV0AAoJEILEb/54YlRxqbgQAIdwiU/kLnvhIxfgOpaqMtAWxlpwmMyU
 qXmBNrvrW0CueMy2lCCKQZbVcyxxzvZigV8eW1rdmx+ISfI3fPTFeroqK+XHMl6z
 +izohhWVKj3hCormkefOLuqh1TnJsM0OVYVVJrQZ4CrewunCzG7mR72qaJnk+98x
 LQuSOCIbAe7AChAEW1Ydg1I2oWcwz4HUdixkJse5F3h8M51ZhwyoUZsRvk2fIIVA
 pfcZw2yz9bidCzUuhP54pfVwVItngCe9AwUu7/gDUXCAtxyMQrMn5ppDSmYhCHxc
 BSACmcDdJzOOcwoBRbsaYJrc33zRXH8NmXK3ekZLb3FgozDmuT01lvsn+tGay/zR
 Ektk0d0uSLLDfaXdO4IycuEtngINkO7R43J4TiT5QufN+HLJz3Ru+0/cGe3YkSae
 WLu+N3ZDnpA9CDT4A/eEL6taabZfgN2FIKNq+OuKdhb9sogrcrN2U6R5RvIWZipN
 +Xgwg1euRrmAfjDZngvpDRVMTYywl8PYoGdoYKMDHlLU6ftzK+5d59juBXVsoze8
 8IUUgszkNcqunMj+V3GlnRmu6LlTpRQinArFU+DKf3/YQvqr+l9V8IDjiiFiQh6N
 P2BPUlKTl3LgiY2vNvztxQK504cim78Xwe2U+rwngJS6y2SiGldkwwxSzILAsVA2
 YIbY9jfQeTlF
 =7/13
 -----END PGP SIGNATURE-----

Merge tag 'acpi-6.13-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull ACPI fix from Rafael Wysocki:
 "Prevent acpi_video_device_EDID() from returning a pointer to a memory
  region that should not be passed to kfree() which causes one of its
  users to crash randomly on attempts to free it (Chris Bainbridge)"

* tag 'acpi-6.13-rc8' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  ACPI: video: Fix random crashes due to bad kfree()
This commit is contained in:
Linus Torvalds 2025-01-16 09:02:10 -08:00
commit 5d5c478759
2 changed files with 28 additions and 23 deletions

View File

@ -610,16 +610,28 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
return 0;
}
/**
* acpi_video_device_EDID() - Get EDID from ACPI _DDC
* @device: video output device (LCD, CRT, ..)
* @edid: address for returned EDID pointer
* @length: _DDC length to request (must be a multiple of 128)
*
* Get EDID from ACPI _DDC. On success, a pointer to the EDID data is written
* to the @edid address, and the length of the EDID is returned. The caller is
* responsible for freeing the edid pointer.
*
* Return the length of EDID (positive value) on success or error (negative
* value).
*/
static int
acpi_video_device_EDID(struct acpi_video_device *device,
union acpi_object **edid, int length)
acpi_video_device_EDID(struct acpi_video_device *device, void **edid, int length)
{
int status;
acpi_status status;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list args = { 1, &arg0 };
int ret;
*edid = NULL;
@ -636,16 +648,17 @@ acpi_video_device_EDID(struct acpi_video_device *device,
obj = buffer.pointer;
if (obj && obj->type == ACPI_TYPE_BUFFER)
*edid = obj;
else {
if (obj && obj->type == ACPI_TYPE_BUFFER) {
*edid = kmemdup(obj->buffer.pointer, obj->buffer.length, GFP_KERNEL);
ret = *edid ? obj->buffer.length : -ENOMEM;
} else {
acpi_handle_debug(device->dev->handle,
"Invalid _DDC data for length %d\n", length);
status = -EFAULT;
kfree(obj);
ret = -EFAULT;
}
return status;
kfree(obj);
return ret;
}
/* bus */
@ -1435,9 +1448,7 @@ int acpi_video_get_edid(struct acpi_device *device, int type, int device_id,
{
struct acpi_video_bus *video;
struct acpi_video_device *video_device;
union acpi_object *buffer = NULL;
acpi_status status;
int i, length;
int i, length, ret;
if (!device || !acpi_driver_data(device))
return -EINVAL;
@ -1477,16 +1488,10 @@ int acpi_video_get_edid(struct acpi_device *device, int type, int device_id,
}
for (length = 512; length > 0; length -= 128) {
status = acpi_video_device_EDID(video_device, &buffer,
length);
if (ACPI_SUCCESS(status))
break;
ret = acpi_video_device_EDID(video_device, edid, length);
if (ret > 0)
return ret;
}
if (!length)
continue;
*edid = buffer->buffer.pointer;
return length;
}
return -ENODEV;

View File

@ -384,7 +384,7 @@ nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector)
if (ret < 0)
return NULL;
return kmemdup(edid, EDID_LENGTH, GFP_KERNEL);
return edid;
}
bool nouveau_acpi_video_backlight_use_native(void)