diff options
| author | Mark Brown <broonie@kernel.org> | 2026-05-29 17:41:36 +0100 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-05-29 17:41:36 +0100 |
| commit | 851aeb423017763aa012d68fceaacb61fa8438f7 (patch) | |
| tree | 105527de718e337c84097cd6bac8cb2fcd4a8b78 | |
| parent | e1a42d12e2b479e261362db1d9d810639ef60fa7 (diff) | |
| parent | 5ab62dd3687bcc2cc542b99385aabac5c996db6f (diff) | |
| download | linux-next-history-851aeb423017763aa012d68fceaacb61fa8438f7.tar.gz | |
Merge branch 'for-linux-next-fixes' of https://gitlab.freedesktop.org/drm/misc/kernel.git
| -rw-r--r-- | drivers/accel/amdxdna/aie2_pci.c | 5 | ||||
| -rw-r--r-- | drivers/accel/ivpu/ivpu_debugfs.c | 2 | ||||
| -rw-r--r-- | drivers/accel/rocket/rocket_gem.c | 17 | ||||
| -rw-r--r-- | drivers/dma-buf/dma-buf.c | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/drm_dumb_buffers.c | 14 | ||||
| -rw-r--r-- | drivers/gpu/drm/hyperv/hyperv_drm_proto.c | 113 |
6 files changed, 132 insertions, 25 deletions
diff --git a/drivers/accel/amdxdna/aie2_pci.c b/drivers/accel/amdxdna/aie2_pci.c index f1ac4e00bd9f4..4500b9ccb02e0 100644 --- a/drivers/accel/amdxdna/aie2_pci.c +++ b/drivers/accel/amdxdna/aie2_pci.c @@ -511,6 +511,11 @@ static int aie2_init(struct amdxdna_dev *xdna) return -EINVAL; } + if (!xdna->group) { + XDNA_ERR(xdna, "Running without IOMMU not supported"); + return -EINVAL; + } + ndev = drmm_kzalloc(&xdna->ddev, sizeof(*ndev), GFP_KERNEL); if (!ndev) return -ENOMEM; diff --git a/drivers/accel/ivpu/ivpu_debugfs.c b/drivers/accel/ivpu/ivpu_debugfs.c index 189dbe94cf141..dc20bc73c6ed8 100644 --- a/drivers/accel/ivpu/ivpu_debugfs.c +++ b/drivers/accel/ivpu/ivpu_debugfs.c @@ -450,7 +450,7 @@ priority_bands_fops_write(struct file *file, const char __user *user_buf, size_t u32 band; int ret; - if (size >= sizeof(buf)) + if (*pos != 0 || size >= sizeof(buf)) return -EINVAL; ret = simple_write_to_buffer(buf, sizeof(buf) - 1, pos, user_buf, size); diff --git a/drivers/accel/rocket/rocket_gem.c b/drivers/accel/rocket/rocket_gem.c index c8084719208a2..a5fffa51ff355 100644 --- a/drivers/accel/rocket/rocket_gem.c +++ b/drivers/accel/rocket/rocket_gem.c @@ -79,11 +79,6 @@ int rocket_ioctl_create_bo(struct drm_device *dev, void *data, struct drm_file * rkt_obj->size = args->size; rkt_obj->offset = 0; - ret = drm_gem_handle_create(file, gem_obj, &args->handle); - drm_gem_object_put(gem_obj); - if (ret) - goto err; - sgt = drm_gem_shmem_get_pages_sgt(shmem_obj); if (IS_ERR(sgt)) { ret = PTR_ERR(sgt); @@ -95,6 +90,8 @@ int rocket_ioctl_create_bo(struct drm_device *dev, void *data, struct drm_file * rkt_obj->size, PAGE_SIZE, 0, 0); mutex_unlock(&rocket_priv->mm_lock); + if (ret) + goto err; ret = iommu_map_sgtable(rocket_priv->domain->domain, rkt_obj->mm.start, @@ -112,8 +109,18 @@ int rocket_ioctl_create_bo(struct drm_device *dev, void *data, struct drm_file * args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node); args->dma_address = rkt_obj->mm.start; + ret = drm_gem_handle_create(file, gem_obj, &args->handle); + if (ret) + goto err_unmap; + + drm_gem_object_put(gem_obj); + return 0; +err_unmap: + iommu_unmap(rocket_priv->domain->domain, + rkt_obj->mm.start, rkt_obj->size); + err_remove_node: mutex_lock(&rocket_priv->mm_lock); drm_mm_remove_node(&rkt_obj->mm); diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index 71f37544a5c61..d504c636dc294 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -792,9 +792,13 @@ int dma_buf_fd(struct dma_buf *dmabuf, int flags) if (!dmabuf || !dmabuf->file) return -EINVAL; - fd = FD_ADD(flags, dmabuf->file); + fd = get_unused_fd_flags(flags); + if (fd < 0) + return fd; + DMA_BUF_TRACE(trace_dma_buf_fd, dmabuf, fd); + fd_install(fd, dmabuf->file); return fd; } EXPORT_SYMBOL_NS_GPL(dma_buf_fd, "DMA_BUF"); diff --git a/drivers/gpu/drm/drm_dumb_buffers.c b/drivers/gpu/drm/drm_dumb_buffers.c index e2b62e5fb891b..cc99681a9ed0b 100644 --- a/drivers/gpu/drm/drm_dumb_buffers.c +++ b/drivers/gpu/drm/drm_dumb_buffers.c @@ -70,8 +70,11 @@ static int drm_mode_align_dumb(struct drm_mode_create_dumb *args, if (!pitch) return -EINVAL; - if (hw_pitch_align) + if (hw_pitch_align) { pitch = roundup(pitch, hw_pitch_align); + if (pitch < hw_pitch_align) + return -EINVAL; + } if (!hw_size_align) hw_size_align = PAGE_SIZE; @@ -80,7 +83,7 @@ static int drm_mode_align_dumb(struct drm_mode_create_dumb *args, if (check_mul_overflow(args->height, pitch, &size)) return -EINVAL; - size = ALIGN(size, hw_size_align); + size = roundup(size, hw_size_align); if (!size) return -EINVAL; @@ -199,6 +202,13 @@ int drm_mode_create_dumb(struct drm_device *dev, if (!args->width || !args->height || !args->bpp) return -EINVAL; + /* Reject unreasonable inputs early. Dumb buffers are for software + * rendering; nothing legitimate needs more than 8192x8192 at 32bpp. + * This prevents overflows in downstream alignment helpers. + */ + if (args->width >= 8192 || args->height >= 8192 || args->bpp > 32) + return -EINVAL; + /* overflow checks for 32bit size calculations */ if (args->bpp > U32_MAX - 8) return -EINVAL; diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c index 051ecc5268321..4e6f703a1b334 100644 --- a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c +++ b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c @@ -391,8 +391,11 @@ static int hyperv_get_supported_resolution(struct hv_device *hdev) return -ETIMEDOUT; } - if (msg->resolution_resp.resolution_count == 0) { - drm_err(dev, "No supported resolutions\n"); + if (msg->resolution_resp.resolution_count == 0 || + msg->resolution_resp.resolution_count > + SYNTHVID_MAX_RESOLUTION_COUNT) { + drm_err(dev, "Invalid resolution count: %d\n", + msg->resolution_resp.resolution_count); return -ENODEV; } @@ -417,30 +420,92 @@ static int hyperv_get_supported_resolution(struct hv_device *hdev) return 0; } -static void hyperv_receive_sub(struct hv_device *hdev) +static void hyperv_receive_sub(struct hv_device *hdev, u32 bytes_recvd) { struct hyperv_drm_device *hv = hv_get_drvdata(hdev); struct synthvid_msg *msg; + size_t hdr_size; + size_t need; if (!hv) return; - msg = (struct synthvid_msg *)hv->recv_buf; - - /* Complete the wait event */ - if (msg->vid_hdr.type == SYNTHVID_VERSION_RESPONSE || - msg->vid_hdr.type == SYNTHVID_RESOLUTION_RESPONSE || - msg->vid_hdr.type == SYNTHVID_VRAM_LOCATION_ACK) { - memcpy(hv->init_buf, msg, VMBUS_MAX_PACKET_SIZE); - complete(&hv->wait); + hdr_size = sizeof(struct pipe_msg_hdr) + + sizeof(struct synthvid_msg_hdr); + if (bytes_recvd < hdr_size) { + drm_err_ratelimited(&hv->dev, + "synthvid packet too small for header: %u\n", + bytes_recvd); return; } - if (msg->vid_hdr.type == SYNTHVID_FEATURE_CHANGE) { + msg = (struct synthvid_msg *)hv->recv_buf; + need = hdr_size; + + switch (msg->vid_hdr.type) { + case SYNTHVID_VERSION_RESPONSE: + need += sizeof(struct synthvid_version_resp); + break; + case SYNTHVID_RESOLUTION_RESPONSE: + /* + * The resolution response is variable length: the host + * fills resolution_count entries, not the full + * SYNTHVID_MAX_RESOLUTION_COUNT array. Require the fixed + * prefix first so resolution_count can be read, then + * demand exactly the count-sized array. + */ + need += offsetof(struct synthvid_supported_resolution_resp, + supported_resolution); + if (bytes_recvd < need) + break; + if (msg->resolution_resp.resolution_count > + SYNTHVID_MAX_RESOLUTION_COUNT) { + drm_err_ratelimited(&hv->dev, + "synthvid resolution count too large: %u\n", + msg->resolution_resp.resolution_count); + return; + } + need += msg->resolution_resp.resolution_count * + sizeof(struct hvd_screen_info); + break; + case SYNTHVID_VRAM_LOCATION_ACK: + need += sizeof(struct synthvid_vram_location_ack); + break; + case SYNTHVID_FEATURE_CHANGE: + /* + * Not a completion-driving message: validate its own payload + * and consume it here rather than falling through to the + * memcpy/complete shared by the wait-event responses. + */ + if (bytes_recvd < need + + sizeof(struct synthvid_feature_change)) { + drm_err_ratelimited(&hv->dev, + "synthvid feature change packet too small: %u\n", + bytes_recvd); + return; + } hv->dirt_needed = msg->feature_chg.is_dirt_needed; if (hv->dirt_needed) hyperv_hide_hw_ptr(hv->hdev); + return; + default: + return; + } + + /* + * Shared completion path for the wait-event responses + * (VERSION_RESPONSE, RESOLUTION_RESPONSE, VRAM_LOCATION_ACK): + * require the type-specific payload before handing the buffer to + * the waiter. + */ + if (bytes_recvd < need) { + drm_err_ratelimited(&hv->dev, + "synthvid packet too small for type %u: %u < %zu\n", + msg->vid_hdr.type, bytes_recvd, need); + return; } + memcpy(hv->init_buf, msg, bytes_recvd); + complete(&hv->wait); } static void hyperv_receive(void *ctx) @@ -461,9 +526,21 @@ static void hyperv_receive(void *ctx) ret = vmbus_recvpacket(hdev->channel, recv_buf, VMBUS_MAX_PACKET_SIZE, &bytes_recvd, &req_id); - if (bytes_recvd > 0 && - recv_buf->pipe_hdr.type == PIPE_MSG_DATA) - hyperv_receive_sub(hdev); + if (ret) { + /* + * A nonzero return (e.g. -ENOBUFS for an oversized + * packet) is itself a malformed message: bytes_recvd + * then reports the required length rather than a copied + * payload, so it must not be forwarded to the + * sub-handler. Channel recovery is not attempted. + */ + drm_err_ratelimited(&hv->dev, + "vmbus_recvpacket failed: %d (need %u)\n", + ret, bytes_recvd); + } else if (bytes_recvd > 0 && + recv_buf->pipe_hdr.type == PIPE_MSG_DATA) { + hyperv_receive_sub(hdev, bytes_recvd); + } } while (bytes_recvd > 0 && ret == 0); } @@ -508,9 +585,13 @@ int hyperv_connect_vsp(struct hv_device *hdev) ret = hyperv_get_supported_resolution(hdev); if (ret) drm_err(dev, "Failed to get supported resolution from host, use default\n"); - } else { + } + + if (!hv->screen_width_max) { hv->screen_width_max = SYNTHVID_WIDTH_WIN8; hv->screen_height_max = SYNTHVID_HEIGHT_WIN8; + hv->preferred_width = SYNTHVID_WIDTH_WIN8; + hv->preferred_height = SYNTHVID_HEIGHT_WIN8; } hv->mmio_megabytes = hdev->channel->offermsg.offer.mmio_megabytes; |
