lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-id: <1385634439-24554-1-git-send-email-a.anurag@samsung.com>
Date:	Thu, 28 Nov 2013 15:57:19 +0530
From:	Anurag Aggarwal <a.anurag@...sung.com>
To:	linux-arm-kernel@...ts.infradead.org, dave.martin@....com
Cc:	cpgs@...sung.com, linux@....linux.org.uk, a.anurag@...sung.com,
	naveen.sel@...sung.com, ashish.kalra@...sung.com,
	mohammad.a2@...sung.com, rajat.suri@...sung.com,
	naveenkrishna.ch@...il.com, anurag19aggarwal@...il.com,
	narendra.m1@...sung.com, poorva.s@...sung.com,
	linux-kernel@...r.kernel.org, will.deacon@....com, nico@...aro.org,
	catalin.marinas@....com
Subject: [PATCH] ARM : unwinder : Prevent data abort due to stack overflow in
 unwind_exec_insn Signed-off-by: Anurag Aggarwal <a.anurag@...sung.com>

While executing some unwind instructions stack overflow can cause a data abort
when area beyond stack is not mapped to physical memory.

To prevent the data abort check whether it is possible to execute
these instructions before unwinding the stack
---
 arch/arm/kernel/unwind.c |   59 +++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 58 insertions(+), 1 deletions(-)

diff --git a/arch/arm/kernel/unwind.c b/arch/arm/kernel/unwind.c
index 00df012..3777cd7 100644
--- a/arch/arm/kernel/unwind.c
+++ b/arch/arm/kernel/unwind.c
@@ -49,6 +49,8 @@
 #include <asm/traps.h>
 #include <asm/unwind.h>
 
+#define TOTAL_REGISTERS 16
+
 /* Dummy functions to avoid linker complaints */
 void __aeabi_unwind_cpp_pr0(void)
 {
@@ -66,7 +68,7 @@ void __aeabi_unwind_cpp_pr2(void)
 EXPORT_SYMBOL(__aeabi_unwind_cpp_pr2);
 
 struct unwind_ctrl_block {
-	unsigned long vrs[16];		/* virtual register set */
+	unsigned long vrs[TOTAL_REGISTERS];	/* virtual register set */
 	const unsigned long *insn;	/* pointer to the current instructions word */
 	int entries;			/* number of entries left to interpret */
 	int byte;			/* current byte number in the instructions word */
@@ -235,6 +237,58 @@ static unsigned long unwind_get_byte(struct unwind_ctrl_block *ctrl)
 	return ret;
 }
 
+/* check whether there is enough space on stack to execute instructions
+   that can cause a data abort*/
+static int unwind_check_insn(struct unwind_ctrl_block *ctrl, unsigned long insn)
+{
+	unsigned long high, low;
+	int required_stack = 0;
+
+	low = ctrl->vrs[SP];
+	high = ALIGN(low, THREAD_SIZE);
+
+	/* check whether we have enough space to extract
+	atleast one set of registers*/
+	if ((high - low) > TOTAL_REGISTERS)
+		return URC_OK;
+
+	if ((insn & 0xf0) == 0x80) {
+		unsigned long mask;
+		insn = (insn << 8) | unwind_get_byte(ctrl);
+		mask = insn & 0x0fff;
+		if (mask == 0) {
+			pr_warning("unwind: 'Refuse to unwind' instruction %04lx\n",
+				insn);
+			return -URC_FAILURE;
+		}
+		while (mask) {
+			if (mask & 1)
+				required_stack++;
+			mask >>= 1;
+		}
+	} else if ((insn & 0xf0) == 0xa0) {
+		required_stack += insn & 7;
+		required_stack +=  (insn & 0x80) ? 1 : 0;
+	} else if (insn == 0xb1) {
+		unsigned long mask = unwind_get_byte(ctrl);
+		if (mask == 0 || mask & 0xf0) {
+			pr_warning("unwind: Spare encoding %04lx\n",
+				(insn << 8) | mask);
+			return -URC_FAILURE;
+		}
+		while (mask) {
+			if (mask & 1)
+				required_stack++;
+			mask >>= 1;
+		}
+	}
+
+	if ((high - low) < required_stack)
+		return -URC_FAILURE;
+
+	return URC_OK;
+}
+
 /*
  * Execute the current unwind instruction.
  */
@@ -244,6 +298,9 @@ static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)
 
 	pr_debug("%s: insn = %08lx\n", __func__, insn);
 
+	if (unwind_check_insn(ctrl, insn) < 0)
+		return -URC_FAILURE;
+
 	if ((insn & 0xc0) == 0x00)
 		ctrl->vrs[SP] += ((insn & 0x3f) << 2) + 4;
 	else if ((insn & 0xc0) == 0x40)
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ