From: Johan Hovold Date: Thu, 19 Nov 2015 17:27:59 +0000 (+0100) Subject: greybus: firmware: fix information leak X-Git-Tag: v4.9-rc1~119^2~378^2~21^2~1032 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=98645a9c69f40e46cdbf8c0c1862b4c2ed470319;p=karo-tx-linux.git greybus: firmware: fix information leak Add missing sanity checks on get_firmware-request offset and size parameters to fix potential information leaks. This prevents remotely controlled information leaks as the requestor currently controls both the 32-bit firmware-image offset and the amount of data that is returned (up to host-device MTU). Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/staging/greybus/firmware.c b/drivers/staging/greybus/firmware.c index b16f13318be4..4e1530fe9ae5 100644 --- a/drivers/staging/greybus/firmware.c +++ b/drivers/staging/greybus/firmware.c @@ -87,6 +87,7 @@ static int gb_firmware_get_firmware(struct gb_operation *op) { struct gb_connection *connection = op->connection; struct gb_firmware *firmware = connection->private; + const struct firmware *fw = firmware->fw; struct gb_firmware_get_firmware_request *firmware_request = op->request->payload; struct gb_firmware_get_firmware_response *firmware_response; struct device *dev = &connection->bundle->dev; @@ -99,7 +100,7 @@ static int gb_firmware_get_firmware(struct gb_operation *op) return -EINVAL; } - if (!firmware->fw) { + if (!fw) { dev_err(dev, "%s: firmware not available\n", __func__); return -EINVAL; } @@ -107,6 +108,12 @@ static int gb_firmware_get_firmware(struct gb_operation *op) offset = le32_to_cpu(firmware_request->offset); size = le32_to_cpu(firmware_request->size); + if (offset >= fw->size || size > fw->size - offset) { + dev_warn(dev, "bad firmware request (offs = %u, size = %u)\n", + offset, size); + return -EINVAL; + } + if (!gb_operation_response_alloc(op, sizeof(*firmware_response) + size, GFP_KERNEL)) { dev_err(dev, "%s: error allocating response\n", __func__); @@ -114,7 +121,7 @@ static int gb_firmware_get_firmware(struct gb_operation *op) } firmware_response = op->response->payload; - memcpy(firmware_response->data, firmware->fw->data + offset, size); + memcpy(firmware_response->data, fw->data + offset, size); return 0; }