mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 04:22:50 +02:00
crt0/dynamic: refactoring + add support for reprotecting relro segment
This commit is contained in:
parent
3a5d0dae35
commit
4ff1c52869
@ -1,34 +1,42 @@
|
||||
#include "result.h"
|
||||
#include "kernel/svc.h"
|
||||
#include "runtime/diag.h"
|
||||
#include <elf.h>
|
||||
#include <string.h>
|
||||
|
||||
void __nx_dynamic(uintptr_t base, const Elf64_Dyn* dyn)
|
||||
typedef struct Mod0Header {
|
||||
u32 magic_mod0;
|
||||
s32 dyn_offset;
|
||||
s32 bss_start_offset;
|
||||
s32 bss_end_offset;
|
||||
s32 eh_frame_hdr_start_offset;
|
||||
s32 eh_frame_hdr_end_offset;
|
||||
s32 unused;
|
||||
|
||||
u32 magic_lny0;
|
||||
s32 got_start_offset;
|
||||
s32 got_end_offset;
|
||||
|
||||
u32 magic_lny1;
|
||||
s32 relro_start_offset;
|
||||
s32 relro_end_offset;
|
||||
} Mod0Header;
|
||||
|
||||
NX_INLINE void* _dynResolveOffset(const Mod0Header* mod0, s32 offset)
|
||||
{
|
||||
const Elf64_Rela* rela = NULL;
|
||||
u64 relasz = 0;
|
||||
return (void*)((uintptr_t)mod0 + offset);
|
||||
}
|
||||
|
||||
for (; dyn->d_tag != DT_NULL; dyn++)
|
||||
{
|
||||
switch (dyn->d_tag)
|
||||
{
|
||||
case DT_RELA:
|
||||
rela = (const Elf64_Rela*)(base + dyn->d_un.d_ptr);
|
||||
static void _dynProcessRela(uintptr_t base, const Elf64_Rela* rela, size_t relasz)
|
||||
{
|
||||
for (; relasz--; rela++) {
|
||||
switch (ELF64_R_TYPE(rela->r_info)) {
|
||||
default: {
|
||||
diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_BadReloc));
|
||||
break;
|
||||
case DT_RELASZ:
|
||||
relasz = dyn->d_un.d_val / sizeof(Elf64_Rela);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rela == NULL)
|
||||
diagAbortWithResult(MAKERESULT(Module_Libnx, LibnxError_BadReloc));
|
||||
|
||||
for (; relasz--; rela++)
|
||||
{
|
||||
switch (ELF64_R_TYPE(rela->r_info))
|
||||
{
|
||||
case R_AARCH64_RELATIVE:
|
||||
{
|
||||
case R_AARCH64_RELATIVE: {
|
||||
u64* ptr = (u64*)(base + rela->r_offset);
|
||||
*ptr = base + rela->r_addend;
|
||||
break;
|
||||
@ -36,3 +44,57 @@ void __nx_dynamic(uintptr_t base, const Elf64_Dyn* dyn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __nx_dynamic(uintptr_t base, const Mod0Header* mod0)
|
||||
{
|
||||
// Return early if MOD0 header has been invalidated
|
||||
if (mod0->magic_mod0 != 0x30444f4d) { // MOD0
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear the BSS area
|
||||
u8* bss_start = _dynResolveOffset(mod0, mod0->bss_start_offset);
|
||||
u8* bss_end = _dynResolveOffset(mod0, mod0->bss_end_offset);
|
||||
if (bss_start != bss_end) {
|
||||
memset(bss_start, 0, bss_end - bss_start);
|
||||
}
|
||||
|
||||
// Retrieve pointer to the ELF dynamic section
|
||||
const Elf64_Dyn* dyn = _dynResolveOffset(mod0, mod0->dyn_offset);
|
||||
|
||||
// Extract relevant information from the ELF dynamic section
|
||||
const Elf64_Rela* rela = NULL;
|
||||
size_t relasz = 0;
|
||||
for (; dyn->d_tag != DT_NULL; dyn++) {
|
||||
switch (dyn->d_tag) {
|
||||
case DT_RELA:
|
||||
rela = (const Elf64_Rela*)(base + dyn->d_un.d_ptr);
|
||||
break;
|
||||
|
||||
case DT_RELASZ:
|
||||
relasz = dyn->d_un.d_val / sizeof(Elf64_Rela);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply RELA relocations if present
|
||||
if (rela && relasz) {
|
||||
_dynProcessRela(base, rela, relasz);
|
||||
}
|
||||
|
||||
// Return early if LNY0/LNY1 extensions are not present
|
||||
if (mod0->magic_lny0 != 0x30594e4c || mod0->magic_lny1 != 0x31594e4c) { // LNY0, LNY1
|
||||
return;
|
||||
}
|
||||
|
||||
// Reprotect relro segment as read-only now that we're done processing relocations
|
||||
u8* relro_start = _dynResolveOffset(mod0, mod0->relro_start_offset);
|
||||
size_t relro_sz = (u8*)_dynResolveOffset(mod0, mod0->relro_end_offset) - relro_start;
|
||||
Result rc = svcSetMemoryPermission(relro_start, relro_sz, Perm_R);
|
||||
if (R_FAILED(rc)) {
|
||||
diagAbortWithResult(rc);
|
||||
}
|
||||
|
||||
// Lock the relro segment's permissions
|
||||
svcSetMemoryAttribute(relro_start, relro_sz, MemAttr_IsPermissionLocked, MemAttr_IsPermissionLocked);
|
||||
}
|
||||
|
@ -23,36 +23,20 @@ _start:
|
||||
b __libnx_exception_entry
|
||||
|
||||
.Lcrt0_main_entry:
|
||||
// Get pointer to MOD0 struct (contains offsets to important places)
|
||||
adr x28, __nx_mod0
|
||||
|
||||
// Calculate BSS address/size
|
||||
ldp w8, w9, [x28, #8] // load BSS start/end offset from MOD0
|
||||
sub w9, w9, w8 // calculate BSS size
|
||||
add w9, w9, #7 // round up to 8
|
||||
bic w9, w9, #7 // ^
|
||||
add x8, x28, x8 // fixup the start pointer
|
||||
|
||||
// Clear the BSS in 8-byte units
|
||||
1: subs w9, w9, #8
|
||||
str xzr, [x8], #8
|
||||
bne 1b
|
||||
|
||||
// Preserve registers across function calls
|
||||
mov x25, x0 // entrypoint argument 0
|
||||
mov x26, x1 // entrypoint argument 1
|
||||
mov x27, x30 // loader return address
|
||||
mov x28, sp // initial stack pointer
|
||||
|
||||
// Perform runtime linking on ourselves (including relocations)
|
||||
adr x0, _start // get aslr base
|
||||
adr x1, __nx_mod0 // get pointer to MOD0 struct
|
||||
bl __nx_dynamic
|
||||
|
||||
// Save initial stack pointer
|
||||
mov x8, sp
|
||||
adrp x9, __stack_top
|
||||
str x8, [x9, #:lo12:__stack_top]
|
||||
|
||||
// Parse ELF .dynamic section (which applies relocations to our module)
|
||||
adr x0, _start // get aslr base
|
||||
ldr w1, [x28, #4] // pointer to .dynamic section
|
||||
add x1, x28, x1
|
||||
bl __nx_dynamic
|
||||
str x28, [x9, #:lo12:__stack_top]
|
||||
|
||||
// Perform system initialization
|
||||
mov x0, x25
|
||||
@ -65,8 +49,8 @@ _start:
|
||||
ldr w0, [x0, #:lo12:__system_argc]
|
||||
adrp x1, __system_argv // argv
|
||||
ldr x1, [x1, #:lo12:__system_argv]
|
||||
adrp x30, exit
|
||||
add x30, x30, #:lo12:exit
|
||||
adrp x30, :got:exit
|
||||
ldr x30, [x30, #:got_lo12:exit]
|
||||
b main
|
||||
|
||||
.global __nx_exit
|
||||
@ -95,6 +79,10 @@ __nx_mod0:
|
||||
.word __got_start__ - __nx_mod0
|
||||
.word __got_end__ - __nx_mod0
|
||||
|
||||
.ascii "LNY1"
|
||||
.word __relro_start - __nx_mod0
|
||||
.word __data_start - __nx_mod0
|
||||
|
||||
.section .bss.__stack_top, "aw", %nobits
|
||||
.global __stack_top
|
||||
.align 3
|
||||
|
Loading…
Reference in New Issue
Block a user