mirror of
https://github.com/torvalds/linux.git
synced 2026-06-03 03:53:37 +02:00
Short summary of fixes pull:
amdxdna: - require IOMMU on AIE2 dumb-buffer: - prevent overflows in dumb-buffer creation dma-buf: - fix UAF in dma_buf_fd() tracepoint hyperv: - improve protocol validation ivpu: - test write offset in debugfs rocket: - fix UAF in bo creation -----BEGIN PGP SIGNATURE----- iQFPBAABCgA5FiEEchf7rIzpz2NEoWjlaA3BHVMLeiMFAmoZON4bFIAAAAAABAAO bWFudTIsMi41KzEuMTIsMiwyAAoJEGgNwR1TC3ojkmQH/iTes3bKpMGoXvNUWblI QYDtLgQR6uHwDwJgeYDBxu2RZQvS2y29bsW02dSCtAgQ+OkAb5TKRg1ew/cBfKQm QSjp4aT1qM+U+mqWhJhN40dtyyEVXZ4JlzeVcACLQhRzuohd2u5AybONtW/1NRnX BSpKXbntjKk+1EX6do0Cs4I8KaSKkogBAeKRIbS+J9w4rTBds3LefOGjhHo+hVkY +G4LAjEYO1onmN+OGvqZGXtdZKhH6j1rb8trRWHYkkcNP8GLWPQ2WFOMXDNLcxA3 l3EUcOiU0ka6oW2NunO7rFay0h/+VFDU2VyUUvUTBKSxjbQ/7uhdIa+UoYYJOQ6B I+Y= =UkZG -----END PGP SIGNATURE----- Merge tag 'drm-misc-fixes-2026-05-29' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-fixes Short summary of fixes pull: amdxdna: - require IOMMU on AIE2 dumb-buffer: - prevent overflows in dumb-buffer creation dma-buf: - fix UAF in dma_buf_fd() tracepoint hyperv: - improve protocol validation ivpu: - test write offset in debugfs rocket: - fix UAF in bo creation Signed-off-by: Dave Airlie <airlied@redhat.com> From: Thomas Zimmermann <tzimmermann@suse.de> Link: https://patch.msgid.link/20260529070009.GA313534@linux.fritz.box
This commit is contained in:
commit
6e40c93789
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user