Thread (6 messages) 6 messages, 3 authors, 2021-07-30

Re: [PATCH] asm-generic/hyperv: Fix struct hv_message_header ordering

From: Vitaly Kuznetsov <vkuznets@redhat.com>
Date: 2021-07-29 13:52:58
Also in: linux-hyperv, lkml

Siddharth Chandrasekaran [off-list ref] writes:
According to Hyper-V TLFS Version 6.0b, struct hv_message_header members
should be defined in the order:

	message_type, reserved, message_flags, payload_size

but we have it defined in the order:

	message_type, payload_size, message_flags, reserved

that is, the payload_size and reserved members swapped. 
Indeed,

typedef struct
{
	HV_MESSAGE_TYPE MessageType;
	UINT16 Reserved;
	HV_MESSAGE_FLAGS MessageFlags;
	UINT8 PayloadSize;
	union
	{
		UINT64 OriginationId;
		HV_PARTITION_ID Sender;
		HV_PORT_ID Port;
	};
} HV_MESSAGE_HEADER;
Due to this mix
up, we were inadvertently causing two issues:

    - The payload_size field has invalid data; it didn't cause an issue
      so far because we are delivering only timer messages which has fixed
      size payloads the guest probably did a sizeof(payload) instead
      relying on the value of payload_size member.

    - The message_flags was always delivered as 0 to the guest;
      fortunately, according to section 13.3.1 message_flags is also
      treated as a reserved field.

Although this is not causing an issue now, it might in future (we are
adding more message types in our VSM implementation) so fix it to
reflect the specification.
I'm wondering how this works for Linux-on-Hyper-V as
e.g. vmbus_on_msg_dpc() checks for mininum and maximum payload length:

        payload_size = msg_copy.header.payload_size;
        if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT) {
                WARN_ONCE(1, "payload size is too large (%d)\n", payload_size);
                goto msg_handled;
        }

        entry = &channel_message_table[msgtype];

	if (!entry->message_handler)
		goto msg_handled;

	if (payload_size < entry->min_payload_len) {
                WARN_ONCE(1, "message too short: msgtype=%d len=%d\n", msgtype, payload_size);
                goto msg_handled;
        }

Maybe it's vice versa, the header is correct and the documentation is wrong?
quoted hunk ↗ jump to hunk
Signed-off-by: Siddharth Chandrasekaran <redacted>
---
 include/asm-generic/hyperv-tlfs.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/include/asm-generic/hyperv-tlfs.h b/include/asm-generic/hyperv-tlfs.h
index 56348a541c50..a5540e9b171f 100644
--- a/include/asm-generic/hyperv-tlfs.h
+++ b/include/asm-generic/hyperv-tlfs.h
@@ -284,9 +284,9 @@ union hv_port_id {
 /* Define synthetic interrupt controller message header. */
 struct hv_message_header {
 	__u32 message_type;
-	__u8 payload_size;
-	union hv_message_flags message_flags;
 	__u8 reserved[2];
+	union hv_message_flags message_flags;
+	__u8 payload_size;
 	union {
 		__u64 sender;
 		union hv_port_id port;
-- 
Vitaly
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help