drm: qxl: Fix NULL pointer dereference at qxl_alloc_client_monitors_config

If qxl_alloc_client_monitors_config() fails to allocate
client_monitors_config then NULL pointer dereference occurs
in function qxl_display_copy_rom_client_monitors_config() after
qxl_alloc_client_monitors_config() call.

The patch adds return error from qxl_alloc_client_monitors_config()
and additional status for qxl_display_copy_rom_client_monitors_config
return value.

Found by Linux Driver Verification project (linuxtesting.org).

Signed-off-by: Anton Vasilyev <vasilyev@ispras.ru>
Link: http://patchwork.freedesktop.org/patch/msgid/20180727153058.23620-1-vasilyev@ispras.ru
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
Anton Vasilyev 2018-07-27 18:30:58 +03:00 committed by Gerd Hoffmann
parent 5043348a49
commit 66e0c8a5bc

View File

@ -37,7 +37,8 @@ static bool qxl_head_enabled(struct qxl_head *head)
return head->width && head->height; return head->width && head->height;
} }
static void qxl_alloc_client_monitors_config(struct qxl_device *qdev, unsigned count) static int qxl_alloc_client_monitors_config(struct qxl_device *qdev,
unsigned int count)
{ {
if (qdev->client_monitors_config && if (qdev->client_monitors_config &&
count > qdev->client_monitors_config->count) { count > qdev->client_monitors_config->count) {
@ -49,15 +50,17 @@ static void qxl_alloc_client_monitors_config(struct qxl_device *qdev, unsigned c
sizeof(struct qxl_monitors_config) + sizeof(struct qxl_monitors_config) +
sizeof(struct qxl_head) * count, GFP_KERNEL); sizeof(struct qxl_head) * count, GFP_KERNEL);
if (!qdev->client_monitors_config) if (!qdev->client_monitors_config)
return; return -ENOMEM;
} }
qdev->client_monitors_config->count = count; qdev->client_monitors_config->count = count;
return 0;
} }
enum { enum {
MONITORS_CONFIG_MODIFIED, MONITORS_CONFIG_MODIFIED,
MONITORS_CONFIG_UNCHANGED, MONITORS_CONFIG_UNCHANGED,
MONITORS_CONFIG_BAD_CRC, MONITORS_CONFIG_BAD_CRC,
MONITORS_CONFIG_ERROR,
}; };
static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev) static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev)
@ -87,7 +90,10 @@ static int qxl_display_copy_rom_client_monitors_config(struct qxl_device *qdev)
&& (num_monitors != qdev->client_monitors_config->count)) { && (num_monitors != qdev->client_monitors_config->count)) {
status = MONITORS_CONFIG_MODIFIED; status = MONITORS_CONFIG_MODIFIED;
} }
qxl_alloc_client_monitors_config(qdev, num_monitors); if (qxl_alloc_client_monitors_config(qdev, num_monitors)) {
status = MONITORS_CONFIG_ERROR;
return status;
}
/* we copy max from the client but it isn't used */ /* we copy max from the client but it isn't used */
qdev->client_monitors_config->max_allowed = qdev->client_monitors_config->max_allowed =
qdev->monitors_config->max_allowed; qdev->monitors_config->max_allowed;
@ -161,6 +167,10 @@ void qxl_display_read_client_monitors_config(struct qxl_device *qdev)
break; break;
udelay(5); udelay(5);
} }
if (status == MONITORS_CONFIG_ERROR) {
DRM_DEBUG_KMS("ignoring client monitors config: error");
return;
}
if (status == MONITORS_CONFIG_BAD_CRC) { if (status == MONITORS_CONFIG_BAD_CRC) {
DRM_DEBUG_KMS("ignoring client monitors config: bad crc"); DRM_DEBUG_KMS("ignoring client monitors config: bad crc");
return; return;