Move writable data to a higher block of memory.
This means we can map the text and rodata sections read-only, and enable
WXN. The data section must be copied from its (now readonly) load
address to the writable block.
Bug: 223166344
Test: Ran unprotected VM under crosvm.
Change-Id: I9105f200c8bd937f6e3a504fed7d0fb5e38ff366
diff --git a/pvmfw/entry.S b/pvmfw/entry.S
index 787b4ff..e5c6045 100644
--- a/pvmfw/entry.S
+++ b/pvmfw/entry.S
@@ -63,13 +63,16 @@
.set .L_SCTLR_ELx_M, 0x1 << 0
/* Privileged Access Never is unchanged on taking an exception to EL1. */
.set .L_SCTLR_EL1_SPAN, 0x1 << 23
+/* All writable memory regions are treated as XN. */
+.set .L_SCTLR_EL1_WXN, 0x1 << 19
/* SETEND instruction disabled at EL0 in aarch32 mode. */
.set .L_SCTLR_EL1_SED, 0x1 << 8
/* Various IT instructions are disabled at EL0 in aarch32 mode. */
.set .L_SCTLR_EL1_ITD, 0x1 << 7
.set .L_SCTLR_EL1_RES1, (0x1 << 11) | (0x1 << 20) | (0x1 << 22) | (0x1 << 28) | (0x1 << 29)
.set .Lsctlrval, .L_SCTLR_ELx_M | .L_SCTLR_ELx_C | .L_SCTLR_ELx_SA | .L_SCTLR_EL1_ITD | .L_SCTLR_EL1_SED
-.set .Lsctlrval, .Lsctlrval | .L_SCTLR_ELx_I | .L_SCTLR_EL1_SPAN | .L_SCTLR_EL1_RES1
+.set .Lsctlrval, .Lsctlrval | .L_SCTLR_ELx_I | .L_SCTLR_EL1_SPAN | .L_SCTLR_EL1_RES1 | .L_SCTLR_EL1_WXN
+
/**
* This is a generic entry point for an image. It carries out the operations
* required to prepare the loaded image to be run. Specifically, it zeroes the
@@ -128,13 +131,23 @@
stp xzr, xzr, [x29], #16
b 0b
-1: /* Prepare the stack. */
- adr x30, boot_stack_end
+1: /* Copy the data section. */
+ adr_l x28, data_begin
+ adr_l x29, data_end
+ adr_l x30, data_lma
+2: cmp x28, x29
+ b.ge 3f
+ ldp q0, q1, [x30], #32
+ stp q0, q1, [x28], #32
+ b 2b
+
+3: /* Prepare the stack. */
+ adr_l x30, boot_stack_end
mov sp, x30
/* Call into Rust code. */
bl main
/* Loop forever waiting for interrupts. */
-2: wfi
- b 2b
+4: wfi
+ b 4b
diff --git a/pvmfw/idmap.S b/pvmfw/idmap.S
index f5050af..f1df6cc 100644
--- a/pvmfw/idmap.S
+++ b/pvmfw/idmap.S
@@ -30,7 +30,8 @@
.set .L_BLOCK_RO, .L_TT_TYPE_BLOCK | .L_TT_MT_MEM | .L_TT_AF | .L_TT_RO | .L_TT_XN
.set .L_BLOCK_DEV, .L_TT_TYPE_BLOCK | .L_TT_MT_DEV | .L_TT_AF | .L_TT_XN
-.set .L_BLOCK_MEM_XIP, .L_TT_TYPE_BLOCK | .L_TT_MT_MEM | .L_TT_AF | .L_TT_NG
+.set .L_BLOCK_MEM, .L_TT_TYPE_BLOCK | .L_TT_MT_MEM | .L_TT_AF | .L_TT_XN | .L_TT_NG
+.set .L_BLOCK_MEM_XIP, .L_TT_TYPE_BLOCK | .L_TT_MT_MEM | .L_TT_AF | .L_TT_NG | .L_TT_RO
.section ".rodata.idmap", "a", %progbits
.global idmap
@@ -45,4 +46,5 @@
/* level 2 */
0: .quad .L_BLOCK_RO | 0x80000000 // DT provided by VMM
.quad .L_BLOCK_MEM_XIP | 0x80200000 // 2 MB of DRAM containing image
- .fill 510, 8, 0x0
+ .quad .L_BLOCK_MEM | 0x80400000 // 2 MB of writable DRAM
+ .fill 509, 8, 0x0
diff --git a/pvmfw/image.ld b/pvmfw/image.ld
index e08fbe2..4655f68 100644
--- a/pvmfw/image.ld
+++ b/pvmfw/image.ld
@@ -18,6 +18,7 @@
{
dtb_region : ORIGIN = 0x80000000, LENGTH = 2M
image : ORIGIN = 0x80200000, LENGTH = 2M
+ writable_data : ORIGIN = 0x80400000, LENGTH = 2M
}
/*
@@ -82,7 +83,9 @@
*/
. = ALIGN(32);
data_end = .;
- } >image
+ } >writable_data AT>image
+ data_lma = LOADADDR(.data);
+
/* Everything beyond this point will not be included in the binary. */
bin_end = .;
@@ -93,14 +96,14 @@
*(COMMON)
. = ALIGN(16);
bss_end = .;
- } >image
+ } >writable_data
.stack (NOLOAD) : ALIGN(4096) {
boot_stack_begin = .;
. += 40 * 4096;
. = ALIGN(4096);
boot_stack_end = .;
- } >image
+ } >writable_data
/*
* Remove unused sections from the image.