public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/8] firmware: Sigma: Prevent out of bounds memory access
@ 2011-11-24 12:48 Lars-Peter Clausen
  2011-11-24 12:48 ` [PATCH 2/8] firmware: Sigma: Skip header during CRC generation Lars-Peter Clausen
                   ` (7 more replies)
  0 siblings, 8 replies; 26+ messages in thread
From: Lars-Peter Clausen @ 2011-11-24 12:48 UTC (permalink / raw)
  To: Mark Brown, Liam Girdwood
  Cc: Andrew Morton, Mike Frysinger, linux-kernel, alsa-devel, drivers,
	Lars-Peter Clausen, stable

The SigmaDSP firmware loader currently does not perform enough boundary size
checks when processing the firmware. As a result it is possible that a
malformed firmware can cause an out of bounds memory access.

This patch adds checks which ensure that both the action header and the payload
are completely inside the firmware data boundaries before processing them.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Cc: stable@kernel.org
---
 drivers/firmware/sigma.c |   70 ++++++++++++++++++++++++++++++++--------------
 include/linux/sigma.h    |    5 ---
 2 files changed, 49 insertions(+), 26 deletions(-)

diff --git a/drivers/firmware/sigma.c b/drivers/firmware/sigma.c
index f10fc52..5b17966 100644
--- a/drivers/firmware/sigma.c
+++ b/drivers/firmware/sigma.c
@@ -14,13 +14,30 @@
 #include <linux/module.h>
 #include <linux/sigma.h>
 
-/* Return: 0==OK, <0==error, =1 ==no more actions */
+static size_t sigma_action_size(struct sigma_action *sa)
+{
+	size_t payload = 0;
+
+	switch (sa->instr) {
+	case SIGMA_ACTION_WRITEXBYTES:
+	case SIGMA_ACTION_WRITESINGLE:
+	case SIGMA_ACTION_WRITESAFELOAD:
+		payload = sigma_action_len(sa);
+		break;
+	default:
+		break;
+	}
+
+	payload = ALIGN(payload, 2);
+
+	return payload + sizeof(struct sigma_action);
+}
+
 static int
-process_sigma_action(struct i2c_client *client, struct sigma_firmware *ssfw)
+process_sigma_action(struct i2c_client *client, struct sigma_action *sa)
 {
-	struct sigma_action *sa = (void *)(ssfw->fw->data + ssfw->pos);
 	size_t len = sigma_action_len(sa);
-	int ret = 0;
+	int ret;
 
 	pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__,
 		sa->instr, sa->addr, len);
@@ -29,44 +46,50 @@ process_sigma_action(struct i2c_client *client, struct sigma_firmware *ssfw)
 	case SIGMA_ACTION_WRITEXBYTES:
 	case SIGMA_ACTION_WRITESINGLE:
 	case SIGMA_ACTION_WRITESAFELOAD:
-		if (ssfw->fw->size < ssfw->pos + len)
-			return -EINVAL;
 		ret = i2c_master_send(client, (void *)&sa->addr, len);
 		if (ret < 0)
 			return -EINVAL;
 		break;
-
 	case SIGMA_ACTION_DELAY:
-		ret = 0;
 		udelay(len);
 		len = 0;
 		break;
-
 	case SIGMA_ACTION_END:
-		return 1;
-
+		return 0;
 	default:
 		return -EINVAL;
 	}
 
-	/* when arrive here ret=0 or sent data */
-	ssfw->pos += sigma_action_size(sa, len);
-	return ssfw->pos == ssfw->fw->size;
+	return 1;
 }
 
 static int
 process_sigma_actions(struct i2c_client *client, struct sigma_firmware *ssfw)
 {
-	pr_debug("%s: processing %p\n", __func__, ssfw);
+	struct sigma_action *sa;
+	size_t size;
+	int ret;
+
+	while (ssfw->pos + sizeof(*sa) <= ssfw->fw->size) {
+		sa = (struct sigma_action *)(ssfw->fw->data + ssfw->pos);
+
+		size = sigma_action_size(sa);
+		ssfw->pos += size;
+		if (ssfw->pos > ssfw->fw->size || size == 0)
+			break;
+
+		ret = process_sigma_action(client, sa);
 
-	while (1) {
-		int ret = process_sigma_action(client, ssfw);
 		pr_debug("%s: action returned %i\n", __func__, ret);
-		if (ret == 1)
-			return 0;
-		else if (ret)
+
+		if (ret <= 0)
 			return ret;
 	}
+
+	if (ssfw->pos != ssfw->fw->size)
+		return -EINVAL;
+
+	return 0;
 }
 
 int process_sigma_firmware(struct i2c_client *client, const char *name)
@@ -89,7 +112,12 @@ int process_sigma_firmware(struct i2c_client *client, const char *name)
 
 	/* then verify the header */
 	ret = -EINVAL;
-	if (fw->size < sizeof(*ssfw_head))
+
+	/* Reject too small or unreasonable large files. The upper limit is
+	 * chosen a bit arbitrarily but it should be enough for all practical
+	 * purposes and having the limit makes it easier to avoid integer
+	 * overflows later in the loading process. */
+	if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000)
 		goto done;
 
 	ssfw_head = (void *)fw->data;
diff --git a/include/linux/sigma.h b/include/linux/sigma.h
index e2accb3..9a138c2 100644
--- a/include/linux/sigma.h
+++ b/include/linux/sigma.h
@@ -50,11 +50,6 @@ static inline u32 sigma_action_len(struct sigma_action *sa)
 	return (sa->len_hi << 16) | sa->len;
 }
 
-static inline size_t sigma_action_size(struct sigma_action *sa, u32 payload_len)
-{
-	return sizeof(*sa) + payload_len + (payload_len % 2);
-}
-
 extern int process_sigma_firmware(struct i2c_client *client, const char *name);
 
 #endif
-- 
1.7.7.1



^ permalink raw reply related	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2011-11-29  5:11 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-11-24 12:48 [PATCH 1/8] firmware: Sigma: Prevent out of bounds memory access Lars-Peter Clausen
2011-11-24 12:48 ` [PATCH 2/8] firmware: Sigma: Skip header during CRC generation Lars-Peter Clausen
2011-11-24 17:21   ` Mike Frysinger
2011-11-25  8:55     ` Lars-Peter Clausen
2011-11-25 20:00       ` Mike Frysinger
2011-11-28  7:56         ` Lars-Peter Clausen
2011-11-29  5:11           ` Mike Frysinger
2011-11-24 12:48 ` [PATCH 3/8] firmware: Sigma: Fix endianess issues Lars-Peter Clausen
2011-11-24 17:20   ` Mike Frysinger
2011-11-24 12:48 ` [PATCH 4/8] firmware: Sigma: Mark firmware strutcs packed Lars-Peter Clausen
2011-11-24 17:19   ` Mike Frysinger
2011-11-25 10:48     ` Lars-Peter Clausen
2011-11-25 20:07       ` Mike Frysinger
2011-11-24 12:48 ` [PATCH 5/8] ASoC: Move SigmaDSP firmware loader to ASoC Lars-Peter Clausen
2011-11-24 13:15   ` [PATCH v2 " Lars-Peter Clausen
2011-11-24 17:31     ` Mike Frysinger
2011-11-24 12:48 ` [PATCH 6/8] ASoC: SigmaDSP: Provide diagnostic error messages Lars-Peter Clausen
2011-11-24 17:32   ` Mike Frysinger
2011-11-25  8:59     ` Lars-Peter Clausen
2011-11-25 20:02       ` Mike Frysinger
2011-11-24 12:48 ` [PATCH 7/8] ASoC: SigmaDSP: Move private structs and functions to c file Lars-Peter Clausen
2011-11-24 17:31   ` Mike Frysinger
2011-11-24 12:48 ` [PATCH 8/8] ASoC: SigmaDSP: Add regmap support Lars-Peter Clausen
2011-11-24 17:30   ` Mike Frysinger
2011-11-25  9:00     ` Lars-Peter Clausen
2011-11-24 17:26 ` [PATCH 1/8] firmware: Sigma: Prevent out of bounds memory access Mike Frysinger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox