greybus: operation: fix unaligned memory accesses in receive path

The buffer received from our current host driver is 1-byte aligned and
will therefore cause unaligned memory accesses if simply cast to an
operation-message header.

Fix this by making a properly aligned copy of the header in
gb_connection_recv_response before accessing its fields.

Note that this does not affect protocol drivers as the whole buffer is
copied when creating the corresponding request or response before being
forwarded.

Signed-off-by: Johan Hovold <johan@hovoldconsulting.com>
Reviewed-by: Alex Elder <elder@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
diff --git a/drivers/staging/greybus/operation.c b/drivers/staging/greybus/operation.c
index 260774e..0fd77c9 100644
--- a/drivers/staging/greybus/operation.c
+++ b/drivers/staging/greybus/operation.c
@@ -885,7 +885,7 @@
 void gb_connection_recv(struct gb_connection *connection,
 				void *data, size_t size)
 {
-	struct gb_operation_msg_hdr *header;
+	struct gb_operation_msg_hdr header;
 	size_t msg_size;
 	u16 operation_id;
 
@@ -895,27 +895,28 @@
 		return;
 	}
 
-	if (size < sizeof(*header)) {
+	if (size < sizeof(header)) {
 		dev_err(&connection->dev, "message too small\n");
 		return;
 	}
 
-	header = data;
-	msg_size = le16_to_cpu(header->size);
+	/* Use memcpy as data may be unaligned */
+	memcpy(&header, data, sizeof(header));
+	msg_size = le16_to_cpu(header.size);
 	if (size < msg_size) {
 		dev_err(&connection->dev,
 			"incomplete message received: 0x%04x (%zu < %zu)\n",
-			le16_to_cpu(header->operation_id), size, msg_size);
+			le16_to_cpu(header.operation_id), size, msg_size);
 		return;		/* XXX Should still complete operation */
 	}
 
-	operation_id = le16_to_cpu(header->operation_id);
-	if (header->type & GB_OPERATION_TYPE_RESPONSE)
+	operation_id = le16_to_cpu(header.operation_id);
+	if (header.type & GB_OPERATION_TYPE_RESPONSE)
 		gb_connection_recv_response(connection, operation_id,
-						header->result, data, msg_size);
+						header.result, data, msg_size);
 	else
 		gb_connection_recv_request(connection, operation_id,
-						header->type, data, msg_size);
+						header.type, data, msg_size);
 }
 
 /*