client_monitors_config is allocated with space for count heads, while QXL creates qxl_num_crtc outputs whose indexes range from zero to qxl_num_crtc - 1. The monitor count may be smaller than qxl_num_crtc, but qxl_update_offset_props() and qxl_conn_get_modes() use the output index to access heads[] without checking it against count. Starting QEMU with "-device qxl-vga,xres=1024,yres=768" provides one client monitor while the driver creates four outputs by default. KASAN reported the first out-of-bounds access during probe, with qxl_update_offset_props() inlined into its caller: BUG: KASAN: slab-out-of-bounds in qxl_display_read_client_monitors_config+0x2379/0x2e30 Read of size 4 at addr ffff88810403e170 by task swapper/0/1 Call Trace: qxl_display_read_client_monitors_config+0x2379/0x2e30 qxl_modeset_init+0x6a6/0x7b0 qxl_pci_probe+0x150/0x2d0 The same configuration reaches the unchecked access in qxl_conn_get_modes() when userspace enumerates connectors. Skip offset updates for outputs that have no corresponding client head, and retain the default preferred mode dimensions in qxl_conn_get_modes() when its output index is outside the client head array. Fixes: 7dea0941f880 ("drm/qxl: use suggested x/y offset properties to pass guest prefs") Fixes: 1b043677d4be ("drm/qxl: add qxl_add_mode helper function") Cc: stable@vger.kernel.org Signed-off-by: Jiale Yao --- drivers/gpu/drm/qxl/qxl_display.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 0719fc6a52d5..25f786ab7f1b 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -158,6 +158,9 @@ static void qxl_update_offset_props(struct qxl_device *qdev) list_for_each_entry(connector, &dev->mode_config.connector_list, head) { output = drm_connector_to_qxl_output(connector); + if (output->index >= qdev->client_monitors_config->count) + continue; + head = &qdev->client_monitors_config->heads[output->index]; drm_object_property_set_value(&connector->base, @@ -1056,7 +1059,8 @@ static int qxl_conn_get_modes(struct drm_connector *connector) unsigned int pheight = 768; int ret = 0; - if (qdev->client_monitors_config) { + if (qdev->client_monitors_config && + output->index < qdev->client_monitors_config->count) { struct qxl_head *head; head = &qdev->client_monitors_config->heads[output->index]; if (head->width) -- 2.34.1