From: Berkant Koc <[email protected]> Sent: Sunday, May 17, 2026 7:25 AM
> 
> hyperv_receive() reads bytes_recvd from vmbus_recvpacket() but does not
> forward that value to hyperv_receive_sub(). The sub-handler reads
> msg->vid_hdr.type and msg->feature_chg.is_dirt_needed without knowing
> how many bytes the host actually wrote, so a short packet leaves the
> parser reading bytes that the host did not write in this packet.

This is a valid concern. Similar patterns have hopefully been fixed in other
drivers that were hardened for CoCo VMs.

> The unconditional memcpy(hv->init_buf, msg, VMBUS_MAX_PACKET_SIZE) on the
> wait-completion path also copies the full 16 KiB recv_buf regardless
> of bytes_recvd, including any residue from the prior message.

Does copying the full 16 KiB break anything? Or are you flagging as just
wasteful activity? This gets to what I previously mentioned about commit
messages -- explain "why".  Being wasteful is a valid reason, but it can be
helpful to future readers to be explicit about the "why".

> 
> Pass bytes_recvd into hyperv_receive_sub() and reject any packet shorter
> than the pipe + synthvid header. The dirt-feature branch additionally
> requires the feature_change payload size before reading is_dirt_needed.
> The init_buf copy now uses bytes_recvd as the length argument, which
> keeps it bounded by VMBUS_MAX_PACKET_SIZE through the new upper check.
> 
> Unchanged from v1.

Version related comments should go below the "---" following the Signed-off
line. They will be visible in the patch emails, but won't get put into the
git log when the patch is finally accepted. The Linux kernel doesn't want
to clutter the git log with intermediate version information that accumulates
as the patch is reviewed and revised.

> 
> Fixes: 76c56a5affeb ("drm/hyperv: Add DRM driver for hyperv synthetic video 
> device")
> Cc: [email protected] # 5.14+
> Signed-off-by: Berkant Koc <[email protected]>
> ---
>  drivers/gpu/drm/hyperv/hyperv_drm_proto.c | 15 ++++++++++++---
>  1 file changed, 12 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c
> b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c
> index 3b5065fe06e4..cdab4895dd40 100644
> --- a/drivers/gpu/drm/hyperv/hyperv_drm_proto.c
> +++ b/drivers/gpu/drm/hyperv/hyperv_drm_proto.c
> @@ -423,26 +423,35 @@ 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;
> 
>       if (!hv)
>               return;
> 
> +     hdr_size = sizeof(struct pipe_msg_hdr) +
> +                sizeof(struct synthvid_msg_hdr);
> +     if (bytes_recvd < hdr_size || bytes_recvd > VMBUS_MAX_PACKET_SIZE)

The check against VMBUS_MAX_PACKET_SIZE shouldn't be needed.
vmbus_recvpacket() takes VMBUS_MAX_PACKET_SIZE as the max
receive size and won't return a bytes_recvd value that is larger.

> +             return;

In similar cases in other drivers that have been hardened for CoCo VMs, the
code outputs a rate limited error message. That should be done here so the
bad received message isn't just ignored. See hv_kvp_onchannelcallback() for
example.

> +
>       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);
> +             memcpy(hv->init_buf, msg, bytes_recvd);

Additional logic is needed here. Each of the three message types
in the "if" statement has data beyond just the header. Before doing
the memcpy() and complete(), the code should validate that the msg
is big enough to contain that expected data.  I.e., it needs to do the
same as you have done for SYNTHVID_FEATURE_CHANGE.
Otherwise, the code that wakes up from the completion
will think that it has valid data to work with, and it may not.

Of course, the problem already exists in the upstream code. But if you
are going to make changes to fix the problem, the fix should fully
handle situation and not just be a partial fix.

>               complete(&hv->wait);
>               return;
>       }
> 
>       if (msg->vid_hdr.type == SYNTHVID_FEATURE_CHANGE) {
> +             if (bytes_recvd < hdr_size +
> +                 sizeof(struct synthvid_feature_change))
> +                     return;

Same here.  Output a rate limited error message.

>               hv->dirt_needed = msg->feature_chg.is_dirt_needed;
>               if (hv->dirt_needed)
>                       hyperv_hide_hw_ptr(hv->hdev);
> @@ -469,7 +478,7 @@ static void hyperv_receive(void *ctx)
>                                      &bytes_recvd, &req_id);
>               if (bytes_recvd > 0 &&
>                   recv_buf->pipe_hdr.type == PIPE_MSG_DATA)
> -                     hyperv_receive_sub(hdev);
> +                     hyperv_receive_sub(hdev, bytes_recvd);
>       } while (bytes_recvd > 0 && ret == 0);
>  }
> 
> --
> 2.47.3
> 

Reply via email to