All of lore.kernel.org
 help / color / mirror / Atom feed
From: xiaoqian <xiaoqian9@huawei.com>
To: <linux@armlinux.org.uk>, <rafael.j.wysocki@intel.com>,
	<ebiederm@xmission.com>, <rppt@linux.ibm.com>, <pmladek@suse.com>,
	<bhelgaas@google.com>, <sakari.ailus@linux.intel.com>,
	<linux-arm-kernel@lists.infradead.org>,
	<gregkh@linuxfoundation.org>
Cc: <linux-kernel@vger.kernel.org>, <stable@vger.kernel.org>,
	<xiaoqian9@huawei.com>
Subject: [PATCH] Subject:alignment:fetch pc-instr before irq_enable
Date: Fri, 31 May 2019 11:01:20 +0800	[thread overview]
Message-ID: <1559271680-7486-1-git-send-email-xiaoqian9@huawei.com> (raw)

When the instruction code under PC address is read through
_probe_kernel_read in do_alignment,if the pte page corresponding
to the code segment of PC address is reclaimed exactly at this time,
the address mapping cannot be reconstructed because page fault_disable()
is executed in _probe_kernel_read function,and the failure to obtain
the instruction code of PC finally results in the unsuccessful repair
operation.
Thus we can modify the implementation of reading user-mode PC instruction
before local_irq_enable to avoid the above risk.
At the same time, adjust the sequence of code processing and optimize the
process.

Signed-off-by: xiaoqian <xiaoqian9@huawei.com>
Cc: stable@vger.kernel.org
---
 arch/arm/mm/alignment.c | 81 +++++++++++++++++++++++++++++++++----------------
 1 file changed, 55 insertions(+), 26 deletions(-)

diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index e376883ab35b..4124b9ce3c70 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -76,6 +76,11 @@
 #define IS_T32(hi16) \
 	(((hi16) & 0xe000) == 0xe000 && ((hi16) & 0x1800))
 
+#define INVALID_INSTR_MODE     0
+#define ARM_INSTR_MODE         1
+#define THUMB_INSTR_MODE       2
+#define THUMB2_INSTR_MODE      3
+
 static unsigned long ai_user;
 static unsigned long ai_sys;
 static void *ai_sys_last_pc;
@@ -705,6 +710,48 @@ thumb2arm(u16 tinstr)
 	}
 }
 
+static unsigned int
+fetch_usr_pc_instr(struct pt_regs *regs, unsigned long *pc_instrptr)
+{
+	unsigned int fault;
+	unsigned long instrptr;
+	unsigned long instr_mode = INVALID_INSTR_MODE;
+
+	instrptr = instruction_pointer(regs);
+
+	if (thumb_mode(regs)) {
+		u16 tinstr = 0;
+		u16 *ptr = (u16 *)(instrptr & ~1);
+
+		fault = probe_kernel_address(ptr, tinstr);
+		if (!fault) {
+			tinstr = __mem_to_opcode_thumb16(tinstr);
+			if (cpu_architecture() >= CPU_ARCH_ARMv7 &&
+			    IS_T32(tinstr)) {
+				/* Thumb-2 32-bit */
+				u16 tinstr2 = 0;
+
+				fault = probe_kernel_address(ptr + 1, tinstr2);
+				if (!fault) {
+					tinstr2 = __mem_to_opcode_thumb16(tinstr2);
+					*pc_instrptr = __opcode_thumb32_compose(tinstr, tinstr2);
+					instr_mode = THUMB2_INSTR_MODE;
+				}
+			} else {
+				*pc_instrptr = thumb2arm(tinstr);
+				instr_mode = THUMB_INSTR_MODE;
+			}
+		}
+	} else {
+		fault = probe_kernel_address((void *)instrptr, *pc_instrptr);
+		if (!fault) {
+			*pc_instrptr = __mem_to_opcode_arm(*pc_instrptr);
+			instr_mode = ARM_INSTR_MODE;
+		}
+	}
+	return instr_mode;
+}
+
 /*
  * Convert Thumb-2 32 bit LDM, STM, LDRD, STRD to equivalent instruction
  * handlable by ARM alignment handler, also find the corresponding handler,
@@ -775,42 +822,24 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 	unsigned long instr = 0, instrptr;
 	int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs);
 	unsigned int type;
-	unsigned int fault;
 	u16 tinstr = 0;
 	int isize = 4;
 	int thumb2_32b = 0;
+	unsigned long pc_instr_mode;
+
+	pc_instr_mode = fetch_usr_pc_instr(regs, &instr);
 
 	if (interrupts_enabled(regs))
 		local_irq_enable();
 
 	instrptr = instruction_pointer(regs);
-
-	if (thumb_mode(regs)) {
-		u16 *ptr = (u16 *)(instrptr & ~1);
-		fault = probe_kernel_address(ptr, tinstr);
-		tinstr = __mem_to_opcode_thumb16(tinstr);
-		if (!fault) {
-			if (cpu_architecture() >= CPU_ARCH_ARMv7 &&
-			    IS_T32(tinstr)) {
-				/* Thumb-2 32-bit */
-				u16 tinst2 = 0;
-				fault = probe_kernel_address(ptr + 1, tinst2);
-				tinst2 = __mem_to_opcode_thumb16(tinst2);
-				instr = __opcode_thumb32_compose(tinstr, tinst2);
-				thumb2_32b = 1;
-			} else {
-				isize = 2;
-				instr = thumb2arm(tinstr);
-			}
-		}
-	} else {
-		fault = probe_kernel_address((void *)instrptr, instr);
-		instr = __mem_to_opcode_arm(instr);
-	}
-
-	if (fault) {
+	if (pc_instr_mode == INVALID_INSTR_MODE) {
 		type = TYPE_FAULT;
 		goto bad_or_fault;
+	} else if (pc_instr_mode == THUMB_INSTR_MODE) {
+		isize = 2;
+	} else if (pc_instr_mode == THUMB2_INSTR_MODE) {
+		thumb2_32b = 1;
 	}
 
 	if (user_mode(regs))
-- 
2.12.3


WARNING: multiple messages have this Message-ID (diff)
From: xiaoqian <xiaoqian9@huawei.com>
To: <linux@armlinux.org.uk>, <rafael.j.wysocki@intel.com>,
	<ebiederm@xmission.com>, <rppt@linux.ibm.com>, <pmladek@suse.com>,
	<bhelgaas@google.com>, <sakari.ailus@linux.intel.com>,
	<linux-arm-kernel@lists.infradead.org>,
	<gregkh@linuxfoundation.org>
Cc: xiaoqian9@huawei.com, linux-kernel@vger.kernel.org,
	stable@vger.kernel.org
Subject: [PATCH] Subject:alignment:fetch pc-instr before irq_enable
Date: Fri, 31 May 2019 11:01:20 +0800	[thread overview]
Message-ID: <1559271680-7486-1-git-send-email-xiaoqian9@huawei.com> (raw)

When the instruction code under PC address is read through
_probe_kernel_read in do_alignment,if the pte page corresponding
to the code segment of PC address is reclaimed exactly at this time,
the address mapping cannot be reconstructed because page fault_disable()
is executed in _probe_kernel_read function,and the failure to obtain
the instruction code of PC finally results in the unsuccessful repair
operation.
Thus we can modify the implementation of reading user-mode PC instruction
before local_irq_enable to avoid the above risk.
At the same time, adjust the sequence of code processing and optimize the
process.

Signed-off-by: xiaoqian <xiaoqian9@huawei.com>
Cc: stable@vger.kernel.org
---
 arch/arm/mm/alignment.c | 81 +++++++++++++++++++++++++++++++++----------------
 1 file changed, 55 insertions(+), 26 deletions(-)

diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index e376883ab35b..4124b9ce3c70 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -76,6 +76,11 @@
 #define IS_T32(hi16) \
 	(((hi16) & 0xe000) == 0xe000 && ((hi16) & 0x1800))
 
+#define INVALID_INSTR_MODE     0
+#define ARM_INSTR_MODE         1
+#define THUMB_INSTR_MODE       2
+#define THUMB2_INSTR_MODE      3
+
 static unsigned long ai_user;
 static unsigned long ai_sys;
 static void *ai_sys_last_pc;
@@ -705,6 +710,48 @@ thumb2arm(u16 tinstr)
 	}
 }
 
+static unsigned int
+fetch_usr_pc_instr(struct pt_regs *regs, unsigned long *pc_instrptr)
+{
+	unsigned int fault;
+	unsigned long instrptr;
+	unsigned long instr_mode = INVALID_INSTR_MODE;
+
+	instrptr = instruction_pointer(regs);
+
+	if (thumb_mode(regs)) {
+		u16 tinstr = 0;
+		u16 *ptr = (u16 *)(instrptr & ~1);
+
+		fault = probe_kernel_address(ptr, tinstr);
+		if (!fault) {
+			tinstr = __mem_to_opcode_thumb16(tinstr);
+			if (cpu_architecture() >= CPU_ARCH_ARMv7 &&
+			    IS_T32(tinstr)) {
+				/* Thumb-2 32-bit */
+				u16 tinstr2 = 0;
+
+				fault = probe_kernel_address(ptr + 1, tinstr2);
+				if (!fault) {
+					tinstr2 = __mem_to_opcode_thumb16(tinstr2);
+					*pc_instrptr = __opcode_thumb32_compose(tinstr, tinstr2);
+					instr_mode = THUMB2_INSTR_MODE;
+				}
+			} else {
+				*pc_instrptr = thumb2arm(tinstr);
+				instr_mode = THUMB_INSTR_MODE;
+			}
+		}
+	} else {
+		fault = probe_kernel_address((void *)instrptr, *pc_instrptr);
+		if (!fault) {
+			*pc_instrptr = __mem_to_opcode_arm(*pc_instrptr);
+			instr_mode = ARM_INSTR_MODE;
+		}
+	}
+	return instr_mode;
+}
+
 /*
  * Convert Thumb-2 32 bit LDM, STM, LDRD, STRD to equivalent instruction
  * handlable by ARM alignment handler, also find the corresponding handler,
@@ -775,42 +822,24 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 	unsigned long instr = 0, instrptr;
 	int (*handler)(unsigned long addr, unsigned long instr, struct pt_regs *regs);
 	unsigned int type;
-	unsigned int fault;
 	u16 tinstr = 0;
 	int isize = 4;
 	int thumb2_32b = 0;
+	unsigned long pc_instr_mode;
+
+	pc_instr_mode = fetch_usr_pc_instr(regs, &instr);
 
 	if (interrupts_enabled(regs))
 		local_irq_enable();
 
 	instrptr = instruction_pointer(regs);
-
-	if (thumb_mode(regs)) {
-		u16 *ptr = (u16 *)(instrptr & ~1);
-		fault = probe_kernel_address(ptr, tinstr);
-		tinstr = __mem_to_opcode_thumb16(tinstr);
-		if (!fault) {
-			if (cpu_architecture() >= CPU_ARCH_ARMv7 &&
-			    IS_T32(tinstr)) {
-				/* Thumb-2 32-bit */
-				u16 tinst2 = 0;
-				fault = probe_kernel_address(ptr + 1, tinst2);
-				tinst2 = __mem_to_opcode_thumb16(tinst2);
-				instr = __opcode_thumb32_compose(tinstr, tinst2);
-				thumb2_32b = 1;
-			} else {
-				isize = 2;
-				instr = thumb2arm(tinstr);
-			}
-		}
-	} else {
-		fault = probe_kernel_address((void *)instrptr, instr);
-		instr = __mem_to_opcode_arm(instr);
-	}
-
-	if (fault) {
+	if (pc_instr_mode == INVALID_INSTR_MODE) {
 		type = TYPE_FAULT;
 		goto bad_or_fault;
+	} else if (pc_instr_mode == THUMB_INSTR_MODE) {
+		isize = 2;
+	} else if (pc_instr_mode == THUMB2_INSTR_MODE) {
+		thumb2_32b = 1;
 	}
 
 	if (user_mode(regs))
-- 
2.12.3


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

             reply	other threads:[~2019-05-31  3:02 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-05-31  3:01 xiaoqian [this message]
2019-05-31  3:01 ` [PATCH] Subject:alignment:fetch pc-instr before irq_enable xiaoqian

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1559271680-7486-1-git-send-email-xiaoqian9@huawei.com \
    --to=xiaoqian9@huawei.com \
    --cc=bhelgaas@google.com \
    --cc=ebiederm@xmission.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@armlinux.org.uk \
    --cc=pmladek@suse.com \
    --cc=rafael.j.wysocki@intel.com \
    --cc=rppt@linux.ibm.com \
    --cc=sakari.ailus@linux.intel.com \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.