diff options
author | Dave Airlie <airlied@redhat.com> | 2023-07-21 12:02:31 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2023-07-21 12:14:05 +1000 |
commit | f4f19c03cfb99b587cf35ff057be97cb98c5d251 (patch) | |
tree | 0664c11558c76a35afd91b867d11c65eeaac3ebc | |
parent | 78e9b217d78e9f69c5699ccff18794ea03be597f (diff) | |
parent | ea293f823a8805735d9e00124df81a8f448ed1ae (diff) |
Merge tag 'drm-misc-fixes-2023-07-20' of git://anongit.freedesktop.org/drm/drm-misc into drm-fixes
Memory leak fixes in drm/client, memory access/leak fixes for
accel/qaic, another leak fix in dma-buf and three nouveau fixes around
hotplugging.
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Maxime Ripard <mripard@redhat.com>
Link: https://patchwork.freedesktop.org/patch/msgid/fmj5nok7zggux2lcpdtls2iknweba54wfc6o4zxq6i6s3dgi2r@7z3eawwhyhen
-rw-r--r-- | drivers/accel/qaic/qaic_control.c | 39 | ||||
-rw-r--r-- | drivers/dma-buf/dma-resv.c | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_client_modeset.c | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/dispnv50/disp.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c | 27 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c | 11 |
7 files changed, 73 insertions, 31 deletions
diff --git a/drivers/accel/qaic/qaic_control.c b/drivers/accel/qaic/qaic_control.c index 5c57f7b4494e..cfbc92da426f 100644 --- a/drivers/accel/qaic/qaic_control.c +++ b/drivers/accel/qaic/qaic_control.c @@ -14,6 +14,7 @@ #include <linux/mm.h> #include <linux/moduleparam.h> #include <linux/mutex.h> +#include <linux/overflow.h> #include <linux/pci.h> #include <linux/scatterlist.h> #include <linux/types.h> @@ -366,7 +367,7 @@ static int encode_passthrough(struct qaic_device *qdev, void *trans, struct wrap if (in_trans->hdr.len % 8 != 0) return -EINVAL; - if (msg_hdr_len + in_trans->hdr.len > QAIC_MANAGE_EXT_MSG_LENGTH) + if (size_add(msg_hdr_len, in_trans->hdr.len) > QAIC_MANAGE_EXT_MSG_LENGTH) return -ENOSPC; trans_wrapper = add_wrapper(wrappers, @@ -418,9 +419,12 @@ static int find_and_map_user_pages(struct qaic_device *qdev, } ret = get_user_pages_fast(xfer_start_addr, nr_pages, 0, page_list); - if (ret < 0 || ret != nr_pages) { - ret = -EFAULT; + if (ret < 0) goto free_page_list; + if (ret != nr_pages) { + nr_pages = ret; + ret = -EFAULT; + goto put_pages; } sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); @@ -557,11 +561,8 @@ static int encode_dma(struct qaic_device *qdev, void *trans, struct wrapper_list msg = &wrapper->msg; msg_hdr_len = le32_to_cpu(msg->hdr.len); - if (msg_hdr_len > (UINT_MAX - QAIC_MANAGE_EXT_MSG_LENGTH)) - return -EINVAL; - /* There should be enough space to hold at least one ASP entry. */ - if (msg_hdr_len + sizeof(*out_trans) + sizeof(struct wire_addr_size_pair) > + if (size_add(msg_hdr_len, sizeof(*out_trans) + sizeof(struct wire_addr_size_pair)) > QAIC_MANAGE_EXT_MSG_LENGTH) return -ENOMEM; @@ -634,7 +635,7 @@ static int encode_activate(struct qaic_device *qdev, void *trans, struct wrapper msg = &wrapper->msg; msg_hdr_len = le32_to_cpu(msg->hdr.len); - if (msg_hdr_len + sizeof(*out_trans) > QAIC_MANAGE_MAX_MSG_LENGTH) + if (size_add(msg_hdr_len, sizeof(*out_trans)) > QAIC_MANAGE_MAX_MSG_LENGTH) return -ENOSPC; if (!in_trans->queue_size) @@ -718,7 +719,7 @@ static int encode_status(struct qaic_device *qdev, void *trans, struct wrapper_l msg = &wrapper->msg; msg_hdr_len = le32_to_cpu(msg->hdr.len); - if (msg_hdr_len + in_trans->hdr.len > QAIC_MANAGE_MAX_MSG_LENGTH) + if (size_add(msg_hdr_len, in_trans->hdr.len) > QAIC_MANAGE_MAX_MSG_LENGTH) return -ENOSPC; trans_wrapper = add_wrapper(wrappers, sizeof(*trans_wrapper)); @@ -748,7 +749,8 @@ static int encode_message(struct qaic_device *qdev, struct manage_msg *user_msg, int ret; int i; - if (!user_msg->count) { + if (!user_msg->count || + user_msg->len < sizeof(*trans_hdr)) { ret = -EINVAL; goto out; } @@ -765,12 +767,13 @@ static int encode_message(struct qaic_device *qdev, struct manage_msg *user_msg, } for (i = 0; i < user_msg->count; ++i) { - if (user_len >= user_msg->len) { + if (user_len > user_msg->len - sizeof(*trans_hdr)) { ret = -EINVAL; break; } trans_hdr = (struct qaic_manage_trans_hdr *)(user_msg->data + user_len); - if (user_len + trans_hdr->len > user_msg->len) { + if (trans_hdr->len < sizeof(trans_hdr) || + size_add(user_len, trans_hdr->len) > user_msg->len) { ret = -EINVAL; break; } @@ -953,15 +956,23 @@ static int decode_message(struct qaic_device *qdev, struct manage_msg *user_msg, int ret; int i; - if (msg_hdr_len > QAIC_MANAGE_MAX_MSG_LENGTH) + if (msg_hdr_len < sizeof(*trans_hdr) || + msg_hdr_len > QAIC_MANAGE_MAX_MSG_LENGTH) return -EINVAL; user_msg->len = 0; user_msg->count = le32_to_cpu(msg->hdr.count); for (i = 0; i < user_msg->count; ++i) { + u32 hdr_len; + + if (msg_len > msg_hdr_len - sizeof(*trans_hdr)) + return -EINVAL; + trans_hdr = (struct wire_trans_hdr *)(msg->data + msg_len); - if (msg_len + le32_to_cpu(trans_hdr->len) > msg_hdr_len) + hdr_len = le32_to_cpu(trans_hdr->len); + if (hdr_len < sizeof(*trans_hdr) || + size_add(msg_len, hdr_len) > msg_hdr_len) return -EINVAL; switch (le32_to_cpu(trans_hdr->type)) { diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c index b6f71eb00866..38b4110378de 100644 --- a/drivers/dma-buf/dma-resv.c +++ b/drivers/dma-buf/dma-resv.c @@ -571,6 +571,7 @@ int dma_resv_get_fences(struct dma_resv *obj, enum dma_resv_usage usage, dma_resv_for_each_fence_unlocked(&cursor, fence) { if (dma_resv_iter_is_restarted(&cursor)) { + struct dma_fence **new_fences; unsigned int count; while (*num_fences) @@ -579,13 +580,17 @@ int dma_resv_get_fences(struct dma_resv *obj, enum dma_resv_usage usage, count = cursor.num_fences + 1; /* Eventually re-allocate the array */ - *fences = krealloc_array(*fences, count, - sizeof(void *), - GFP_KERNEL); - if (count && !*fences) { + new_fences = krealloc_array(*fences, count, + sizeof(void *), + GFP_KERNEL); + if (count && !new_fences) { + kfree(*fences); + *fences = NULL; + *num_fences = 0; dma_resv_iter_end(&cursor); return -ENOMEM; } + *fences = new_fences; } (*fences)[(*num_fences)++] = dma_fence_get(fence); diff --git a/drivers/gpu/drm/drm_client_modeset.c b/drivers/gpu/drm/drm_client_modeset.c index 1b12a3c201a3..871e4e2129d6 100644 --- a/drivers/gpu/drm/drm_client_modeset.c +++ b/drivers/gpu/drm/drm_client_modeset.c @@ -311,6 +311,9 @@ static bool drm_client_target_cloned(struct drm_device *dev, can_clone = true; dmt_mode = drm_mode_find_dmt(dev, 1024, 768, 60, false); + if (!dmt_mode) + goto fail; + for (i = 0; i < connector_count; i++) { if (!enabled[i]) continue; @@ -326,11 +329,13 @@ static bool drm_client_target_cloned(struct drm_device *dev, if (!modes[i]) can_clone = false; } + kfree(dmt_mode); if (can_clone) { DRM_DEBUG_KMS("can clone using 1024x768\n"); return true; } +fail: DRM_INFO("kms: can't enable cloning when we probably wanted to.\n"); return false; } @@ -862,6 +867,7 @@ int drm_client_modeset_probe(struct drm_client_dev *client, unsigned int width, break; } + kfree(modeset->mode); modeset->mode = drm_mode_duplicate(dev, mode); drm_connector_get(connector); modeset->connectors[modeset->num_connectors++] = connector; diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 38d3fad0d97a..1bec819da876 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -1877,6 +1877,8 @@ nv50_pior_destroy(struct drm_encoder *encoder) nvif_outp_dtor(&nv_encoder->outp); drm_encoder_cleanup(encoder); + + mutex_destroy(&nv_encoder->dp.hpd_irq_lock); kfree(encoder); } @@ -1921,6 +1923,8 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) nv_encoder->i2c = ddc; nv_encoder->aux = aux; + mutex_init(&nv_encoder->dp.hpd_irq_lock); + encoder = to_drm_encoder(nv_encoder); encoder->possible_crtcs = dcbe->heads; encoder->possible_clones = 0; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h index 40a1065ae626..ef441dfdea09 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h @@ -16,7 +16,7 @@ struct nvkm_i2c_bus { const struct nvkm_i2c_bus_func *func; struct nvkm_i2c_pad *pad; #define NVKM_I2C_BUS_CCB(n) /* 'n' is ccb index */ (n) -#define NVKM_I2C_BUS_EXT(n) /* 'n' is dcb external encoder type */ ((n) + 0x100) +#define NVKM_I2C_BUS_EXT(n) /* 'n' is dcb external encoder type */ ((n) + 0x10) #define NVKM_I2C_BUS_PRI /* ccb primary comm. port */ -1 #define NVKM_I2C_BUS_SEC /* ccb secondary comm. port */ -2 int id; @@ -38,7 +38,7 @@ struct nvkm_i2c_aux { const struct nvkm_i2c_aux_func *func; struct nvkm_i2c_pad *pad; #define NVKM_I2C_AUX_CCB(n) /* 'n' is ccb index */ (n) -#define NVKM_I2C_AUX_EXT(n) /* 'n' is dcb external encoder type */ ((n) + 0x100) +#define NVKM_I2C_AUX_EXT(n) /* 'n' is dcb external encoder type */ ((n) + 0x10) int id; struct mutex mutex; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c index dad942be6679..46b057fe1412 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/uconn.c @@ -81,20 +81,29 @@ nvkm_uconn_uevent(struct nvkm_object *object, void *argv, u32 argc, struct nvkm_ return -ENOSYS; list_for_each_entry(outp, &conn->disp->outps, head) { - if (outp->info.connector == conn->index && outp->dp.aux) { - if (args->v0.types & NVIF_CONN_EVENT_V0_PLUG ) bits |= NVKM_I2C_PLUG; - if (args->v0.types & NVIF_CONN_EVENT_V0_UNPLUG) bits |= NVKM_I2C_UNPLUG; - if (args->v0.types & NVIF_CONN_EVENT_V0_IRQ ) bits |= NVKM_I2C_IRQ; + if (outp->info.connector == conn->index) + break; + } - return nvkm_uevent_add(uevent, &device->i2c->event, outp->dp.aux->id, bits, - nvkm_uconn_uevent_aux); - } + if (&outp->head == &conn->disp->outps) + return -EINVAL; + + if (outp->dp.aux && !outp->info.location) { + if (args->v0.types & NVIF_CONN_EVENT_V0_PLUG ) bits |= NVKM_I2C_PLUG; + if (args->v0.types & NVIF_CONN_EVENT_V0_UNPLUG) bits |= NVKM_I2C_UNPLUG; + if (args->v0.types & NVIF_CONN_EVENT_V0_IRQ ) bits |= NVKM_I2C_IRQ; + + return nvkm_uevent_add(uevent, &device->i2c->event, outp->dp.aux->id, bits, + nvkm_uconn_uevent_aux); } if (args->v0.types & NVIF_CONN_EVENT_V0_PLUG ) bits |= NVKM_GPIO_HI; if (args->v0.types & NVIF_CONN_EVENT_V0_UNPLUG) bits |= NVKM_GPIO_LO; - if (args->v0.types & NVIF_CONN_EVENT_V0_IRQ) - return -EINVAL; + if (args->v0.types & NVIF_CONN_EVENT_V0_IRQ) { + /* TODO: support DP IRQ on ANX9805 and remove this hack. */ + if (!outp->info.location) + return -EINVAL; + } return nvkm_uevent_add(uevent, &device->gpio->event, conn->info.hpd, bits, nvkm_uconn_uevent_gpio); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c index 976539de4220..731b2f68d3db 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c @@ -260,10 +260,11 @@ nvkm_i2c_new_(const struct nvkm_i2c_func *func, struct nvkm_device *device, { struct nvkm_bios *bios = device->bios; struct nvkm_i2c *i2c; + struct nvkm_i2c_aux *aux; struct dcb_i2c_entry ccbE; struct dcb_output dcbE; u8 ver, hdr; - int ret, i; + int ret, i, ids; if (!(i2c = *pi2c = kzalloc(sizeof(*i2c), GFP_KERNEL))) return -ENOMEM; @@ -406,5 +407,11 @@ nvkm_i2c_new_(const struct nvkm_i2c_func *func, struct nvkm_device *device, } } - return nvkm_event_init(&nvkm_i2c_intr_func, &i2c->subdev, 4, i, &i2c->event); + ids = 0; + list_for_each_entry(aux, &i2c->aux, head) + ids = max(ids, aux->id + 1); + if (!ids) + return 0; + + return nvkm_event_init(&nvkm_i2c_intr_func, &i2c->subdev, 4, ids, &i2c->event); } |