:: commit 97d0a177989131a5f6c1966433b45776ea2d5342

mintsuki <mintsuki@protonmail.com> — 2021-10-29 17:51

parents: 813418f7c9

stivale2: Introduce fully virtual kernel mappings (KASLR/PIE fixes)

diff --git a/stage23/lib/elf.c b/stage23/lib/elf.c
index db12643f..76755969 100644
--- a/stage23/lib/elf.c
+++ b/stage23/lib/elf.c
@@ -457,6 +457,8 @@ int elf64_load(uint8_t *elf, uint64_t *entry_point, uint64_t *top, uint64_t *_sl
 
     uint64_t max_align = elf64_max_align(elf);
 
+    uint64_t image_size = 0;
+
     if (fully_virtual) {
         simulation = false;
 
@@ -470,9 +472,6 @@ int elf64_load(uint8_t *elf, uint64_t *entry_point, uint64_t *top, uint64_t *_sl
             if (phdr.p_type != PT_LOAD)
                 continue;
 
-            if (phdr.p_type != PT_LOAD)
-                continue;
-
             if (phdr.p_vaddr < min_vaddr) {
                 min_vaddr = phdr.p_vaddr;
             }
@@ -482,7 +481,7 @@ int elf64_load(uint8_t *elf, uint64_t *entry_point, uint64_t *top, uint64_t *_sl
             }
         }
 
-        uint64_t image_size = max_vaddr - min_vaddr;
+        image_size = max_vaddr - min_vaddr;
 
         *physical_base = (uintptr_t)ext_mem_alloc_type_aligned(image_size, alloc_type, max_align);
         *virtual_base = min_vaddr;
@@ -494,9 +493,19 @@ int elf64_load(uint8_t *elf, uint64_t *entry_point, uint64_t *top, uint64_t *_sl
     }
 
 again:
-    if (kaslr)
+    if (kaslr) {
         slide = rand32() & ~(max_align - 1);
 
+        if (fully_virtual) {
+            if ((*virtual_base - FIXED_HIGHER_HALF_OFFSET_64) + slide + image_size >= 0x80000000) {
+                if (++try_count == max_simulated_tries) {
+                    panic("elf: Image wants to load too high");
+                }
+                goto again;
+            }
+        }
+    }
+
 final:
     if (top)
         *top = 0;
@@ -528,16 +537,12 @@ final:
         }
 
         if (!fully_virtual) {
-            if (higher_half == true && load_addr + phdr.p_memsz > 0x80000000) {
-                panic("elf: Higher half executable trying to load too high");
-            }
-
             load_addr += slide;
         }
 
         uint64_t this_top = load_addr + phdr.p_memsz;
 
-        // Make sure we don't overshoot due to KASLR
+        // Make sure we don't overshoot
         if (higher_half == true && this_top > 0x80000000) {
             goto again;
         }
@@ -596,6 +601,10 @@ final:
         goto final;
     }
 
+    if (fully_virtual) {
+        *virtual_base += slide;
+    }
+
     *entry_point = entry + slide;
     if (_slide)
         *_slide = slide;
diff --git a/stage23/protos/stivale2.c b/stage23/protos/stivale2.c
index d7e834d5..4a8d3119 100644
--- a/stage23/protos/stivale2.c
+++ b/stage23/protos/stivale2.c
@@ -169,6 +169,9 @@ void stivale2_load(char *config, char *cmdline, bool pxe, void *efi_system_table
                                want_fully_virtual, &physical_base, &virtual_base))
                     panic("stivale2: ELF64 load failure");
 
+                printv("stivale2: Physical base: %X\n", physical_base);
+                printv("stivale2: Virtual base:  %X\n", virtual_base);
+
                 ret = elf64_load_section(kernel, &stivale2_hdr, ".stivale2hdr",
                                          sizeof(struct stivale2_header), slide);
             }
diff --git a/test/Makefile b/test/Makefile
index 45cb828f..28e7bbde 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -9,7 +9,10 @@ INTERNALLDFLAGS :=         \
 	-Tlinker.ld            \
 	-nostdlib              \
 	-zmax-page-size=0x1000 \
-	-static
+	-static                \
+	-pie                   \
+	--no-dynamic-linker    \
+	-ztext
 
 INTERNALCFLAGS  :=       \
 	-I../stivale         \
@@ -17,15 +20,14 @@ INTERNALCFLAGS  :=       \
 	-std=gnu11           \
 	-ffreestanding       \
 	-fno-stack-protector \
-	-fno-pic -fno-pie       \
+	-fpie                \
 	-mabi=sysv           \
 	-mno-80387           \
 	-mno-mmx             \
 	-mno-3dnow           \
 	-mno-sse             \
 	-mno-sse2            \
-	-mno-red-zone \
-	-mcmodel=kernel
+	-mno-red-zone
 
 all: test.elf
 
diff --git a/test/linker.ld b/test/linker.ld
index 18222830..69aa865a 100644
--- a/test/linker.ld
+++ b/test/linker.ld
@@ -6,6 +6,7 @@ PHDRS
     text    PT_LOAD    FLAGS((1 << 0) | (1 << 2)) ; /* Execute + Read */
     rodata  PT_LOAD    FLAGS((1 << 2)) ;            /* Read only */
     data    PT_LOAD    FLAGS((1 << 1) | (1 << 2)) ; /* Write + Read */
+    dynamic PT_DYNAMIC FLAGS((1 << 1) | (1 << 2)) ; /* Dynamic segment needed for PIE */
 }
 
 SECTIONS
@@ -36,6 +37,10 @@ SECTIONS
         *(.data*)
     } :data
 
+    .dynamic : {
+        *(.dynamic)
+    } :data :dynamic
+
     .bss : {
         *(COMMON)
         *(.bss*)
tab: 248 wrap: offon