Prevent writing to the kernel area via the direct map. We do this by padding
authormlarkin <mlarkin@openbsd.org>
Sun, 21 Dec 2014 16:27:07 +0000 (16:27 +0000)
committermlarkin <mlarkin@openbsd.org>
Sun, 21 Dec 2014 16:27:07 +0000 (16:27 +0000)
the end of the kernel area to 2MB, so that the direct map pages can then
have the W permission removed (X permission was already removed in a previous
diff). This creates a VA hole at the end of bss, so adjust for that since
that's where symbols get loaded by the bootloader (for now, map that region
RO until the boot loader can be updated to place the symbols at "end" instead
of "end of bss").

with help from and ok deraadt@

sys/arch/amd64/amd64/locore.S
sys/arch/amd64/amd64/machdep.c
sys/arch/amd64/conf/ld.script
sys/ddb/db_sym.c

index eeecb11..022cd07 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: locore.S,v 1.60 2014/11/27 17:35:12 mlarkin Exp $     */
+/*     $OpenBSD: locore.S,v 1.61 2014/12/21 16:27:07 mlarkin Exp $     */
 /*     $NetBSD: locore.S,v 1.13 2004/03/25 18:33:17 drochner Exp $     */
 
 /*
@@ -174,7 +174,7 @@ _C_LABEL(lapic_isr):
        .globl  _C_LABEL(cpu_perf_ebx)
        .globl  _C_LABEL(cpu_perf_edx)
        .globl  _C_LABEL(cpu_apmi_edx)
-       .globl  _C_LABEL(esym),_C_LABEL(boothowto),_C_LABEL(bootdev)
+       .globl  _C_LABEL(ssym),_C_LABEL(esym),_C_LABEL(boothowto),_C_LABEL(bootdev)
        .globl  _C_LABEL(bootinfo), _C_LABEL(bootinfo_size), _C_LABEL(atdevbase)
        .globl  _C_LABEL(proc0paddr),_C_LABEL(PTDpaddr)
        .globl  _C_LABEL(biosbasemem),_C_LABEL(biosextmem)
@@ -196,6 +196,7 @@ _C_LABEL(cpuid_level):      .long   -1      # max. level accepted by 'cpuid'
 _C_LABEL(cpu_vendor):  .space  16      # vendor string returned by `cpuid'
                                        #   instruction
 _C_LABEL(cpu_brand_id):        .long   0       # brand ID from 'cpuid' instruction
+_C_LABEL(ssym):                .quad   0       # ptr to start of syms
 _C_LABEL(esym):                .quad   0       # ptr to end of syms
 _C_LABEL(atdevbase):   .quad   0       # location of start of iomem in virtual
 _C_LABEL(bootapiver):  .long   0       # /boot API version
@@ -474,14 +475,46 @@ cont:
        orl     $(PG_V|PG_KR), %eax
        fillkpt_nx
 
-       /* Reload %edx for data_start */
-       movl    $RELOC(__data_start), %edx
+       /* Map the data and BSS sections RW, NX */
+       movl    $RELOC(__data_start), %eax
+       movl    $RELOC(__kernel_bss_end),%ecx
+       addl    $PGOFSET, %ecx
+       andl    $~PGOFSET, %ecx
+       subl    %eax, %ecx
+       shrl    $PGSHIFT,%ecx
+       orl     $(PG_V|PG_KW), %eax
+       fillkpt_nx
 
-       /* Map the data, BSS, and bootstrap tables RW, NX */
+       /* Map "hole" at end of BSS RO, NX */
+       movl    $RELOC(__kernel_bss_end), %eax
+       movl    $RELOC(end), %ecx
+       addl    $PGOFSET, %ecx
+       andl    $~PGOFSET, %ecx
+       cmpl    %eax, %ecx
+       je      map_syms
+       subl    %eax, %ecx
+       shrl    $PGSHIFT, %ecx
+       orl     $(PG_V|PG_KR), %eax
+       fillkpt_nx
+
+map_syms:
+       /* Map symbol space RO, NX */
+       movl    $RELOC(end), %eax
+       movl    %esi, %ecx
+       addl    $PGOFSET, %ecx
+       andl    $~PGOFSET, %ecx
+       cmpl    %eax, %ecx
+       je      map_tables
+       subl    %eax, %ecx
+       shrl    $PGSHIFT, %ecx
+       orl     $(PG_V|PG_KR), %eax
+       fillkpt_nx
+
+map_tables:
+       /* Map the bootstrap tables RW, NX */
+       movl    %esi, %edx
        leal    (PG_V|PG_KW)(%edx),%eax
        movl    $TABLESIZE,%ecx
-       addl    %esi,%ecx               /* %ecx = end + TABLESIZE */
-       subl    %edx,%ecx               /* %ecx = %ecx - data_start */
        shrl    $PGSHIFT,%ecx
        fillkpt_nx
 
@@ -539,13 +572,22 @@ cont:
        /*
         * Map the first 4 GB with the direct map. We'll map the rest
         * in pmap_bootstrap. But we always need the first 4GB during
-        * bootstrap. The direct map is mapped RW, NX.
+        * bootstrap. The direct map is mapped RW, NX. We also change
+        * the permissions on the 2MB pages corresponding to the kernel
+        * PAs to RO to prevent someone writing to the kernel area
+        * via the direct map.
         */
        leal    (PROC0_DMP2_OFF)(%esi), %ebx
        xorl    %eax, %eax
-       orl     $(PG_V|PG_KW|PG_PS|PG_G), %eax
        movl    $(NDML2_ENTRIES * NPDPG), %ecx
-1:     movl    %eax, (%ebx)
+1:     orl     $(PG_V|PG_KW|PG_PS|PG_G), %eax
+       cmpl    $__kernel_base_phys, %eax
+       jl      store_pte
+       cmpl    $__kernel_end_phys, %eax
+       jg      store_pte
+       andl    $(~PG_KW), %eax
+store_pte:
+       movl    %eax, (%ebx)
        pushl   %ebp
        movl    RELOC((pg_nx + 4)), %ebp
        movl    %ebp, 4(%ebx)
@@ -681,6 +723,9 @@ longmode_hi:
        addq    %rsi,%rdx
        movq    %rdx,_C_LABEL(atdevbase)(%rip)
 
+       /* Record start of symbols */
+       movq    $__kernel_bss_end, _C_LABEL(ssym)(%rip)
+
        /* Set up bootstrap stack. */
        leaq    (PROC0_STK_OFF)(%rsi),%rax
        addq    %r8,%rax
index d1a6fdd..53402f7 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: machdep.c,v 1.203 2014/12/18 05:33:48 mlarkin Exp $   */
+/*     $OpenBSD: machdep.c,v 1.204 2014/12/21 16:27:07 mlarkin Exp $   */
 /*     $NetBSD: machdep.c,v 1.3 2003/05/07 22:58:18 fvdl Exp $ */
 
 /*-
@@ -177,8 +177,6 @@ paddr_t     dumpmem_paddr;
 vaddr_t        dumpmem_vaddr;
 psize_t        dumpmem_sz;
 
-
-char   *ssym = NULL;
 vaddr_t kern_end;
 
 vaddr_t        msgbuf_vaddr;
index 4dc06ff..15178e3 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ld.script,v 1.1 2014/11/18 01:11:13 deraadt Exp $     */
+/*     $OpenBSD: ld.script,v 1.2 2014/12/21 16:27:07 mlarkin Exp $     */
 
 /*
  * Copyright (c) 2009 Tobias Weingartner <weingart@tepid.org>
@@ -104,16 +104,16 @@ SECTIONS
                __bss_load = LOADADDR(.bss);
                *(.bss .bss.*)
                *(COMMON)
-               /* Align here to ensure that the .bss section occupies space
-                * up to _end.  Align after .bss to ensure correct alignment
-                * even if the .bss section disappears because there are no
-                * input sections.
+               /* Align after .bss to ensure correct alignment even if the
+                * .bss section disappears because there are no input sections.
                 */
-               . = ALIGN(64 / 8);
+               . = ALIGN(0x1000);
        } :bss
-       . = ALIGN(64 / 8);
+       __kernel_bss_end = .;
+       . = ALIGN(0x200000);
        _end = .;
        PROVIDE (end = .);
+       __kernel_end_phys = . & 0x7fffffff;
 
        /* XXX - hack alert, since we are not C++, nuke these */
        /DISCARD/ :
index 934fe22..5c20977 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: db_sym.c,v 1.35 2014/09/14 14:17:24 jsg Exp $ */
+/*     $OpenBSD: db_sym.c,v 1.36 2014/12/21 16:27:08 mlarkin Exp $     */
 /*     $NetBSD: db_sym.c,v 1.24 2000/08/11 22:50:47 tv Exp $   */
 
 /* 
@@ -121,13 +121,13 @@ ddb_init(void)
        const db_symformat_t **symf;
        const char *name = "bsd";
        extern char *esym;
-#if defined(__sparc64__) || defined(__mips__)
+#if defined(__sparc64__) || defined(__mips__) || defined(__amd64__)
        extern char *ssym;
 #endif
        char *xssym, *xesym;
 
        xesym = esym;
-#if defined(__sparc64__) || defined(__mips__)
+#if defined(__sparc64__) || defined(__mips__) || defined(__amd64__)
        xssym = ssym;
 #else
        xssym = (char *)&end;