From c5f338c4a040d7d6eefc560f3ee5cdb6ede03b74 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 24 Feb 2016 16:11:51 +0100 Subject: [PATCH] greybus: uart: fix incomplete receive-data sanity checks Fix incomplete receive-data sanity checks. The payload size was never verified before parsing the uart header and neither was the uart-header data size verified against the actual payload size, something which could lead to information leaks when passing data beyond the payload buffer to the tty layer. Also remove the incorrect check against the maximum (tx-buffer) payload size. Reviewed-by: Rui Miguel Silva Signed-off-by: Johan Hovold Reviewed-by: Bryan O'Donoghue Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/uart.c | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/drivers/staging/greybus/uart.c b/drivers/staging/greybus/uart.c index c09a76b..0685cdc 100644 --- a/drivers/staging/greybus/uart.c +++ b/drivers/staging/greybus/uart.c @@ -65,18 +65,36 @@ static DEFINE_IDR(tty_minors); static DEFINE_MUTEX(table_lock); static atomic_t reference_count = ATOMIC_INIT(0); -static int gb_uart_receive_data(struct gb_tty *gb_tty, - struct gb_connection *connection, - struct gb_uart_recv_data_request *receive_data) +static int gb_uart_receive_data_handler(struct gb_operation *op) { + struct gb_connection *connection = op->connection; + struct gb_tty *gb_tty = connection->private; struct tty_port *port = &gb_tty->port; + struct gb_message *request = op->request; + struct gb_uart_recv_data_request *receive_data; u16 recv_data_size; int count; unsigned long tty_flags = TTY_NORMAL; - count = gb_tty->buffer_payload_max - sizeof(*receive_data); + if (request->payload_size < sizeof(*receive_data)) { + dev_err(&connection->bundle->dev, + "short receive-data request received (%zu < %zu)\n", + request->payload_size, sizeof(*receive_data)); + return -EINVAL; + } + + receive_data = op->request->payload; recv_data_size = le16_to_cpu(receive_data->size); - if (!recv_data_size || recv_data_size > count) + + if (recv_data_size != request->payload_size - sizeof(*receive_data)) { + dev_err(&connection->bundle->dev, + "malformed receive-data request received (%u != %zu)\n", + recv_data_size, + request->payload_size - sizeof(*receive_data)); + return -EINVAL; + } + + if (!recv_data_size) return -EINVAL; if (receive_data->flags) { @@ -126,14 +144,11 @@ static int gb_uart_serial_state_handler(struct gb_operation *op) static int gb_uart_request_recv(u8 type, struct gb_operation *op) { struct gb_connection *connection = op->connection; - struct gb_tty *gb_tty = connection->private; - struct gb_message *request = op->request; int ret; switch (type) { case GB_UART_TYPE_RECEIVE_DATA: - ret = gb_uart_receive_data(gb_tty, connection, - request->payload); + ret = gb_uart_receive_data_handler(op); break; case GB_UART_TYPE_SERIAL_STATE: ret = gb_uart_serial_state_handler(op); -- 2.7.4