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>
This commit is contained in:
parent
c15ccabe81
commit
564c72b1c6
@ -885,7 +885,7 @@ static void gb_connection_recv_response(struct gb_connection *connection,
|
|||||||
void gb_connection_recv(struct gb_connection *connection,
|
void gb_connection_recv(struct gb_connection *connection,
|
||||||
void *data, size_t size)
|
void *data, size_t size)
|
||||||
{
|
{
|
||||||
struct gb_operation_msg_hdr *header;
|
struct gb_operation_msg_hdr header;
|
||||||
size_t msg_size;
|
size_t msg_size;
|
||||||
u16 operation_id;
|
u16 operation_id;
|
||||||
|
|
||||||
@ -895,27 +895,28 @@ void gb_connection_recv(struct gb_connection *connection,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size < sizeof(*header)) {
|
if (size < sizeof(header)) {
|
||||||
dev_err(&connection->dev, "message too small\n");
|
dev_err(&connection->dev, "message too small\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
header = data;
|
/* Use memcpy as data may be unaligned */
|
||||||
msg_size = le16_to_cpu(header->size);
|
memcpy(&header, data, sizeof(header));
|
||||||
|
msg_size = le16_to_cpu(header.size);
|
||||||
if (size < msg_size) {
|
if (size < msg_size) {
|
||||||
dev_err(&connection->dev,
|
dev_err(&connection->dev,
|
||||||
"incomplete message received: 0x%04x (%zu < %zu)\n",
|
"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 */
|
return; /* XXX Should still complete operation */
|
||||||
}
|
}
|
||||||
|
|
||||||
operation_id = le16_to_cpu(header->operation_id);
|
operation_id = le16_to_cpu(header.operation_id);
|
||||||
if (header->type & GB_OPERATION_TYPE_RESPONSE)
|
if (header.type & GB_OPERATION_TYPE_RESPONSE)
|
||||||
gb_connection_recv_response(connection, operation_id,
|
gb_connection_recv_response(connection, operation_id,
|
||||||
header->result, data, msg_size);
|
header.result, data, msg_size);
|
||||||
else
|
else
|
||||||
gb_connection_recv_request(connection, operation_id,
|
gb_connection_recv_request(connection, operation_id,
|
||||||
header->type, data, msg_size);
|
header.type, data, msg_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user