:: commit 2c09275aabdcad3ec318d62b24ec6dcadfbe1948

mintsuki <mintsuki@protonmail.com> — 2024-07-06 16:44

parents: 329d989b01

lib/elf: Apply a slide of 0xffffffff80000000 - min_vaddr instead of always 0xffffffff80000000 for relocatable kernels loaded low

diff --git a/common/lib/elf.c b/common/lib/elf.c
index e1006f86..0ef2405a 100644
--- a/common/lib/elf.c
+++ b/common/lib/elf.c
@@ -627,7 +627,7 @@ static void elf64_get_ranges(uint8_t *elf, uint64_t slide, struct elf_range **_r
         }
 
         if (phdr->p_vaddr < FIXED_HIGHER_HALF_OFFSET_64) {
-            if (!is_reloc || phdr->p_vaddr >= 0x80000000) {
+            if (!is_reloc) {
                 continue;
             }
         }
@@ -650,7 +650,7 @@ static void elf64_get_ranges(uint8_t *elf, uint64_t slide, struct elf_range **_r
         }
 
         if (phdr->p_vaddr < FIXED_HIGHER_HALF_OFFSET_64) {
-            if (!is_reloc || phdr->p_vaddr >= 0x80000000) {
+            if (!is_reloc) {
                 continue;
             }
         }
@@ -713,14 +713,13 @@ bool elf64_load(uint8_t *elf, uint64_t *entry_point, uint64_t *_slide, uint32_t
         }
 
         if (phdr->p_vaddr < FIXED_HIGHER_HALF_OFFSET_64) {
-            if (!*is_reloc || phdr->p_vaddr >= 0x80000000) {
-                continue;
+            if (!*is_reloc) {
+                panic(true, "elf: Lower half PHDRs are not allowed");
             }
             lower_to_higher = true;
-            slide = FIXED_HIGHER_HALF_OFFSET_64;
         } else {
             if (lower_to_higher) {
-                panic(true, "elf: Mix of lower and higher half PHDRs");
+                panic(true, "elf: Mix of lower and higher half PHDRs in relocatable kernel");
             }
         }
 
@@ -733,7 +732,7 @@ bool elf64_load(uint8_t *elf, uint64_t *entry_point, uint64_t *_slide, uint32_t
             }
 
             if (phdr_in->p_vaddr < FIXED_HIGHER_HALF_OFFSET_64) {
-                if (!*is_reloc || phdr->p_vaddr >= 0x80000000) {
+                if (!*is_reloc) {
                     continue;
                 }
             }
@@ -781,6 +780,10 @@ bool elf64_load(uint8_t *elf, uint64_t *entry_point, uint64_t *_slide, uint32_t
         panic(true, "elf: No usable PHDRs exist");
     }
 
+    if (lower_to_higher) {
+        slide = FIXED_HIGHER_HALF_OFFSET_64 - min_vaddr;
+    }
+
     image_size = max_vaddr - min_vaddr;
 
     *physical_base = (uintptr_t)ext_mem_alloc_type_aligned(image_size, alloc_type, max_align);
@@ -792,7 +795,7 @@ bool elf64_load(uint8_t *elf, uint64_t *entry_point, uint64_t *_slide, uint32_t
 
 again:
     if (*is_reloc && kaslr) {
-        slide = (rand32() & ~(max_align - 1)) + (lower_to_higher ? FIXED_HIGHER_HALF_OFFSET_64 : 0);
+        slide = (rand32() & ~(max_align - 1)) + (lower_to_higher ? FIXED_HIGHER_HALF_OFFSET_64 - min_vaddr : 0);
 
         if (*virtual_base + slide + image_size < 0xffffffff80000000 /* this comparison relies on overflow */) {
             if (++try_count == max_simulated_tries) {
@@ -811,12 +814,6 @@ again:
             continue;
         }
 
-        if (phdr->p_vaddr < FIXED_HIGHER_HALF_OFFSET_64) {
-            if (!*is_reloc || phdr->p_vaddr >= 0x80000000) {
-                continue;
-            }
-        }
-
         // Sanity checks
         if (phdr->p_filesz > phdr->p_memsz) {
             panic(true, "elf: p_filesz > p_memsz");
diff --git a/test/limine.c b/test/limine.c
index 187bfa87..607a69f7 100644
--- a/test/limine.c
+++ b/test/limine.c
@@ -252,6 +252,7 @@ static void limine_main(void) {
 
     uint64_t kernel_slide = (uint64_t)kernel_start - 0xffffffff80000000;
 
+    e9_printf("Kernel start: %x", kernel_start);
     e9_printf("Kernel slide: %x", kernel_slide);
 
 FEAT_START
diff --git a/test/linker.ld b/test/linker.ld
index 23b5aa41..50649326 100644
--- a/test/linker.ld
+++ b/test/linker.ld
@@ -1,7 +1,7 @@
 SECTIONS
 {
     . = SIZEOF_HEADERS;
-    kernel_start = .;
+    kernel_start = . - SIZEOF_HEADERS;
 
     .rodata ALIGN(CONSTANT(MAXPAGESIZE)) : {
         *(.rodata .rodata.*)
tab: 248 wrap: offon