mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
Reserve space for redirect table and install trampolines
The rt0_64 code reserves space for _rt0_redirect_table using the output from the redirect tool's "count" command as a hint to the size of the table. The table itself is located in the .goredirectstbl section which the linker moves to a dedicated section in the final ELF image. When the kernel boots, the _rt0_install_redirect_trampolines function iterates the _rt0_redirect_table entries (populated as a post-link step) and overwrite the original function code with a trampoline that redirects control to the destination function. The trampoline is implemented as a 14-byte instruction that exploits rip-relative addressing to ensure that no registers are made dirty. The actual trampoline code looks like this: jmp [rip+0] ; 6-bytes dq abs_address_to_jump_to ; 8-bytes The _rt0_install_redirect_trampolines function sets up the abs_address to "dst" for each (src, dst) tuple and then copies the trampoline to "src". After the trampoline is installed, any calls to "src" will be transparently redirected to "dst". This hack (modifying code in the .text section) is only possible because the code runs in supervisor mode before memory protection is enabled.
This commit is contained in:
parent
275664219e
commit
d17f582c0b
@ -40,6 +40,7 @@ section .text
|
||||
;------------------------------------------------------------------------------
|
||||
global _rt0_64_entry
|
||||
_rt0_64_entry:
|
||||
call _rt0_install_redirect_trampolines
|
||||
call _rt0_64_load_idt
|
||||
|
||||
; According to the x86_64 ABI, the fs:0 should point to the address of
|
||||
@ -239,7 +240,6 @@ _rt0_64_gate_dispatcher_with_code:
|
||||
add rsp, 16 ; pop handler address and exception code off the stack before returning
|
||||
iretq
|
||||
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; This dispatcher is invoked by gate entries that do not use exception codes.
|
||||
; It performs the following functions:
|
||||
@ -307,3 +307,69 @@ write_string:
|
||||
|
||||
.done:
|
||||
ret
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; Install redirect trampolines. This hack allows us to redirect calls to Go
|
||||
; runtime functions to the kernel's own implementation without the need to
|
||||
; export/globalize any symbols. This works by first setting up a redirect table
|
||||
; (populated by a post-link step) that contains the addresses of the symbol to
|
||||
; hook and the address where calls to that symbol should be redirected.
|
||||
;
|
||||
; This function iterates the redirect table entries and for each entry it
|
||||
; sets up a trampoline to the dst symbol and overwrites the code in src with
|
||||
; the 14-byte long _rt0_redirect_trampoline code.
|
||||
;
|
||||
; Note: this code modification is only possible because we are currently
|
||||
; operating in supervisor mode with no memory protection enabled. Under normal
|
||||
; conditions the .text section should be flagged as read-only.
|
||||
;------------------------------------------------------------------------------
|
||||
_rt0_install_redirect_trampolines:
|
||||
mov rax, _rt0_redirect_table
|
||||
mov rdx, NUM_REDIRECTS
|
||||
|
||||
_rt0_install_redirect_rampolines.next:
|
||||
mov rdi, [rax] ; the symbol address to hook
|
||||
mov rbx, [rax+8] ; the symbol to redirect to
|
||||
|
||||
; setup trampoline target and copy it to the hooked symbol
|
||||
mov rsi, _rt0_redirect_trampoline
|
||||
mov qword [rsi+6], rbx
|
||||
mov rcx, 14
|
||||
rep movsb ; copy rcx bytes from rsi to rdi
|
||||
|
||||
add rax, 16
|
||||
dec rdx
|
||||
jnz _rt0_install_redirect_rampolines.next
|
||||
|
||||
ret
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; This trampoline exploits rip-relative addressing to allow a jump to a
|
||||
; 64-bit address without the need to touch any registers. The generated
|
||||
; code is equivalent to:
|
||||
;
|
||||
; jmp [rip+0]
|
||||
; dq abs_address_to_jump_to
|
||||
;------------------------------------------------------------------------------
|
||||
_rt0_redirect_trampoline:
|
||||
db 0xff ; the first 6 bytes encode a "jmp [rip+0]" instruction
|
||||
db 0x25
|
||||
dd 0x00
|
||||
dq 0x00 ; the absolute address to jump to
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
; The redirect table is placed in a dedicated section allowing us to easily
|
||||
; find its offset in the kernel image file. As the VMA addresses of the src
|
||||
; and target symbols for the redirect are now known in advance we just reserve
|
||||
; enough space space for the src and dst addresses using the NUM_REDIRECTS
|
||||
; define which is calculated by the Makefile and passed to nasm.
|
||||
;------------------------------------------------------------------------------
|
||||
section .goredirectstbl
|
||||
|
||||
_rt0_redirect_table:
|
||||
%rep NUM_REDIRECTS
|
||||
dq 0 ; src: address of the symbol we want to redirect
|
||||
dq 0 ; dst: address of the symbol where calls to src are redirected to
|
||||
%endrep
|
||||
|
||||
|
||||
|
@ -38,6 +38,15 @@ SECTIONS {
|
||||
*(COMMON)
|
||||
*(.bss)
|
||||
}
|
||||
|
||||
/* Go function redirection table. This table is used for hooking
|
||||
* Go runtime function symbols so that calls to them are redirected to
|
||||
* functions provided by the kernel.
|
||||
*/
|
||||
.goredirectstbl ALIGN(4K): AT(ADDR(.goredirectstbl) - PAGE_OFFSET)
|
||||
{
|
||||
*(.goredirectstbl)
|
||||
}
|
||||
|
||||
_kernel_end = ALIGN(4K);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user