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:
Dave Airlie 2026-05-30 06:39:58 +10:00
commit 6e40c93789
6 changed files with 132 additions and 25 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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");

View File

@ -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;

View File

@ -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;