Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/aarch64/aarch64 When emulating obsoleted arm32 inst...



details:   https://anonhg.NetBSD.org/src/rev/8ce1addda266
branches:  trunk
changeset: 744995:8ce1addda266
user:      rin <rin%NetBSD.org@localhost>
date:      Thu Feb 20 12:15:33 2020 +0000

description:
When emulating obsoleted arm32 instructions, use ufetch(9) rather than
dereference tf_pc directly to retrieve an instruction.

Even if tf_pc is valid when processor decodes the instruction, someone
can unmap its page before tf_pc is read in the exception handler.

Now, SIGSEGV is delivered correctly to the process in this case, rather
than kernel panic.

Pointed out by maxv.
Discussed with ryo and skrll.

diffstat:

 sys/arch/aarch64/aarch64/trap.c |  46 +++++++++++++++++++++++++++-------------
 1 files changed, 31 insertions(+), 15 deletions(-)

diffs (102 lines):

diff -r 65db19eaba4f -r 8ce1addda266 sys/arch/aarch64/aarch64/trap.c
--- a/sys/arch/aarch64/aarch64/trap.c   Thu Feb 20 09:07:39 2020 +0000
+++ b/sys/arch/aarch64/aarch64/trap.c   Thu Feb 20 12:15:33 2020 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: trap.c,v 1.25 2020/01/31 09:23:58 maxv Exp $ */
+/* $NetBSD: trap.c,v 1.26 2020/02/20 12:15:33 rin Exp $ */
 
 /*-
  * Copyright (c) 2014 The NetBSD Foundation, Inc.
@@ -31,7 +31,7 @@
 
 #include <sys/cdefs.h>
 
-__KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.25 2020/01/31 09:23:58 maxv Exp $");
+__KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.26 2020/02/20 12:15:33 rin Exp $");
 
 #include "opt_arm_intr_impl.h"
 #include "opt_compat_netbsd32.h"
@@ -362,30 +362,36 @@
                uint16_t *pc = (uint16_t *)(tf->tf_pc & ~1UL); /* XXX */
                uint16_t hi, lo;
 
-               hi = *pc;
+               if (ufetch_16(pc, &hi))
+                       return -1;
+
                if (!THUMB_32BIT(hi)) {
                        /* 16-bit Thumb instruction */
                        *insn = hi;
                        return 2;
                }
 
-               /*
-                * 32-bit Thumb instruction:
-                * We can safely retrieve the lower-half word without
-                * consideration of a page fault; If present, it must
-                * have occurred already in the decode stage.
-                */
-               lo = *(pc + 1);
+               /* 32-bit Thumb instruction */
+               if (ufetch_16(pc + 1, &lo))
+                       return -1;
 
                *insn = ((uint32_t)hi << 16) | lo;
                return 4;
        }
 
-       *insn = *(uint32_t *)tf->tf_pc;
+       if (ufetch_32((uint32_t *)tf->tf_pc, insn))
+               return -1;
+
        return 4;
 }
 
-static int
+enum emul_arm_result {
+       EMUL_ARM_SUCCESS = 0,
+       EMUL_ARM_UNKNOWN,
+       EMUL_ARM_FAULT,
+};
+
+static enum emul_arm_result
 emul_arm_insn(struct trapframe *tf)
 {
        uint32_t insn;
@@ -432,14 +438,16 @@
                        break;
                }
                break;
+       default:
+               return EMUL_ARM_FAULT;
        }
 
        /* unknown, or unsupported instruction */
-       return 1;
+       return EMUL_ARM_UNKNOWN;
 
  emulated:
        tf->tf_pc += insn_size;
-       return 0;
+       return EMUL_ARM_SUCCESS;
 }
 #endif /* COMPAT_NETBSD32 */
 
@@ -494,8 +502,16 @@
                break;
 
        case ESR_EC_UNKNOWN:
-               if (emul_arm_insn(tf))
+               switch (emul_arm_insn(tf)) {
+               case EMUL_ARM_SUCCESS:
+                       break;
+               case EMUL_ARM_UNKNOWN:
                        goto unknown;
+               case EMUL_ARM_FAULT:
+                       do_trapsignal(l, SIGSEGV, SEGV_MAPERR,
+                           (void *)tf->tf_pc, esr);
+                       break;
+               }
                userret(l);
                break;
 



Home | Main Index | Thread Index | Old Index