-
Missing Message Size Validation in gb_connection_recv():
When receiving data on a Greybus connection in gb_connection_recv() (drivers/greybus/operation.c:1027):
if (size < sizeof(header)) {
dev_err_ratelimited(dev, "%s: short message received\n",
connection->name);
return;
}
memcpy(&header, data, sizeof(header));
msg_size = le16_to_cpu(header.size);
if (size < msg_size) {
...
return;
}
While size (the received URB or transfer buffer length) is checked against sizeof(header) (8 bytes), msg_size (the length encoded in header.size by the peer) is only checked against size via if (size < msg_size). If the peer sends a message with header.size < sizeof(struct gb_operation_msg_hdr) (e.g., header.size = 3 with size >= 8), the condition size < msg_size is false, and the code proceeds to dispatch the message using msg_size:
gb_connection_recv_request(connection, &header, data, msg_size);
-
Unsigned Arithmetic Underflow in gb_operation_create_incoming():
gb_connection_recv_request() calls gb_operation_create_incoming(connection, operation_id, type, data, size) with size = msg_size (3 in the report).
In gb_operation_create_incoming():
/* Caller has made sure we at least have a message header. */
request_size = size - sizeof(struct gb_operation_msg_hdr);
Because size < sizeof(struct gb_operation_msg_hdr), the unsigned subtraction underflows:
request_size = (size_t)3 - 8 = 0xfffffffffffffffb.
-
Undersized Buffer Allocation in gb_operation_message_alloc():
gb_operation_create_incoming() calls gb_operation_create_common(), which calls:
gb_operation_message_alloc(hd, type, request_size, gfp_flags);
Inside gb_operation_message_alloc():
size_t message_size = payload_size + sizeof(*header);
Here, payload_size is 0xfffffffffffffffb. Adding sizeof(*header) (8) wraps modulo $2^{64}$ back to 3. The size boundary check message_size > hd->buffer_size_max succeeds because 3 <= hd->buffer_size_max, and kzalloc() is called:
message->buffer = kzalloc(message_size, gfp_flags); /* kzalloc(3, GFP_ATOMIC) */
A buffer of only 3 bytes is allocated from the kmalloc-8 slab cache.
-
Corrupted Message Initialization and Manifestation:
In gb_operation_message_init():
header = message->buffer;
message->header = header;
message->payload = payload_size ? header + 1 : NULL;
message->payload_size = payload_size;
message->header points to the 3-byte allocation.
message->payload_size is set to the underflowed ~18.4 exabyte value.
message->payload is set to header + 1 (offset 8), which already points past the 3-byte allocation.
When the operation work item runs on the workqueue (gb_operation_work() -> gb_operation_request_handle() -> gb_operation_response_send() -> gb_operation_response_alloc()):
request_header = operation->request->header;
response->header->operation_id = request_header->operation_id;
request_header->operation_id is an __le16 located at offset 2 (bytes 2 and 3). Reading 2 bytes starting at offset 2 of a 3-byte slab object reads byte 3, which is past the end of the allocated 3-byte buffer, triggering the reported KASAN slab-out-of-bounds read:
Read of size 2 at addr ffff88813689df82 (offset 2 inside allocated 3-byte region [ffff88813689df80, ffff88813689df83)).
-
Extreme Case (msg_size == 0):
If header.size == 0, kzalloc(0) returns ZERO_SIZE_PTR (0x10). Dereferencing request_header->operation_id at offset 2 dereferences address 0x12, triggering a kernel NULL-pointer dereference page fault.