From c72164fff03d08b838f6806c60a6de68732a641a Mon Sep 17 00:00:00 2001 From: flysand7 Date: Sun, 23 Jul 2023 18:19:53 +1100 Subject: [PATCH] Write proper plt relocations in entry assembly, fix stack checking not working correctly --- build.sh | 15 +++++--------- src/linux/crt_entry.asm | 42 ++++++++++++++-------------------------- src/linux/entry.c | 8 ++++---- src/linux/syscall.c | 43 +++++++++++++++++++++++++++++++++++++++++ test.c | 8 ++++++++ test.sh | 8 -------- tests/empty.c | 2 +- 7 files changed, 76 insertions(+), 50 deletions(-) create mode 100644 test.c delete mode 100755 test.sh diff --git a/build.sh b/build.sh index a87dd3d..31fef76 100755 --- a/build.sh +++ b/build.sh @@ -3,17 +3,12 @@ [ ! -d "lib" ] && mkdir "lib" [ ! -d "bin" ] && mkdir "bin" +[ "$1" != "-shared" ] && echo "static" + nasm -f elf64 "src/linux/crt_entry.asm" -o "bin/crt_entry.o" clang -fPIC -nostdlib -I "include" -g "src/linux/crt_ctors.c" -c -o "bin/crt_ctors.o" clang -fPIC -nostdlib -I "include" -g "src/ciabatta.c" -c -o "bin/ciabatta.o" -rm "$LIB_FILE" 2> /dev/null - -if [ "$1" != "-shared" ]; then - [ -f "lib/ciabatta.a" ] && rm "lib/ciabatta.a" - llvm-ar -q "lib/ciabatta.a" "bin/crt_ctors.o" "bin/crt_entry.o" "bin/ciabatta.o" -else - clang -fPIC -nostdlib -shared -o "lib/ciabatta.so" "bin/ciabatta.o" - cp "bin/crt_ctors.o" "lib/ctors.o" - cp "bin/crt_entry.o" "lib/entry.o" -fi +# Create a test executable +clang -pie -nostdlib -Iinclude \ + tests/empty.c bin/ciabatta.o bin/crt_ctors.o bin/crt_entry.o diff --git a/src/linux/crt_entry.asm b/src/linux/crt_entry.asm index cf24e6b..10641e3 100644 --- a/src/linux/crt_entry.asm +++ b/src/linux/crt_entry.asm @@ -2,20 +2,12 @@ bits 64 section .text - -global _start -; global _init -; global _fini -extern __libc_global_fini -extern __libc_global_init -extern __libc_start_main -extern main - -; _init: -; push ebp -; mov ebp, esp -; _fini: - + default rel + global _start + extern __libc_global_fini + extern __libc_global_init + extern __libc_start_main + extern main _start: xor ebp, ebp ;; Save rtld_fini address to r9 @@ -28,20 +20,16 @@ _start: push rax push rsp ;; Load fini and init initializers as function parameters - %ifdef CIA_SHARED - mov rcx, __libc_global_init wrt ..got - mov r8, __libc_global_fini wrt ..got - %else - mov rcx, __libc_global_init - mov r8, __libc_global_fini - %endif - mov rdi, main + push rbx + lea rbx, [__libc_global_init wrt ..plt] + mov rcx, rbx + lea rbx, [__libc_global_fini wrt ..plt] + mov r8, rbx + lea rbx, [main wrt ..plt] + mov rdi, rbx + pop rbx ;; Call start main - %ifdef CIA_SHARED - call __libc_start_main wrt ..plt - %else - call __libc_start_main - %endif + call __libc_start_main wrt ..plt ;; No idea why halt it, I guess that's a funny ;; way to crash your application if the function we called ;; returns instead of calling the exit syscall diff --git a/src/linux/entry.c b/src/linux/entry.c index 27040d4..bc7b0f9 100644 --- a/src/linux/entry.c +++ b/src/linux/entry.c @@ -10,15 +10,15 @@ void __libc_start_main( int argc, char **argv, int (*init)(int, char**, char**), void (*fini)(void), - void (*runtime_ld_fini)(void), + void (*dl_fini)(void), void *stack_end ) { + // Get the envp char **envp = argv + (argc + 1); init(argc, argv, envp); main(argc, argv, envp); fini(); - if(runtime_ld_fini != NULL) { - runtime_ld_fini(); - } + // glibc bug + dl_fini(); syscall_exit(0); } diff --git a/src/linux/syscall.c b/src/linux/syscall.c index c11889e..d5a5da9 100644 --- a/src/linux/syscall.c +++ b/src/linux/syscall.c @@ -1,10 +1,35 @@ #if os_is_linux() +// Standard handles file descriptors #define STDIN_FILENO 0 #define STDOUT_FILENO 1 #define STDERR_FILENO 2 +// arch_prctl syscall codes +#define ARCH_SET_GS 0x1001 +#define ARCH_SET_FS 0x1002 +#define ARCH_GET_FS 0x1003 +#define ARCH_GET_GS 0x1004 +#define ARCH_GET_CPUID 0x1011 +#define ARCH_SET_CPUID 0x1012 + +// open syscall modes +#define O_ACCMODE 0003 +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 +#define O_CREAT 0100 /* not fcntl */ +#define O_EXCL 0200 /* not fcntl */ +#define O_NOCTTY 0400 /* not fcntl */ +#define O_TRUNC 01000 /* not fcntl */ +#define O_APPEND 02000 +#define O_NONBLOCK 04000 +#define O_NDELAY O_NONBLOCK +#define O_SYNC 010000 +#define O_FSYNC O_SYNC +#define O_ASYNC 020000 + #define SYS_read 0 #define SYS_write 1 #define SYS_open 2 @@ -67,6 +92,8 @@ #define SYS_execve 59 #define SYS_exit 60 +#define SYS_arch_prctl 158 + // Syscall stubs static __inline i64 __syscall0(i64 n) { @@ -132,10 +159,26 @@ static inline i64 syscall_write(u32 fd, char const *buf, u64 count) { return __syscall3(SYS_write, (i64)fd, (i64)buf, (u64)count); } +static inline i64 syscall_open(char const *filename, int flags, int mode) { + return __syscall3(SYS_open, (i64)filename, (i64)flags, (i64)mode); +} + +static inline i64 syscall_close(u32 fd) { + return __syscall1(SYS_close, fd); +} + static inline i64 syscall_exit(int code) { return __syscall1(SYS_exit, (i64)code); } +static inline i64 syscall_arch_prctl_set(int code, u64 value) { + return __syscall2(SYS_arch_prctl, code, (i64)value); +} + +static inline i64 syscall_arch_prctl_get(int code, u64 *value) { + return __syscall2(SYS_arch_prctl, code, (i64)value); +} + #else #error "syscall.h should only be included in LINUX code" #endif \ No newline at end of file diff --git a/test.c b/test.c new file mode 100644 index 0000000..bd95da0 --- /dev/null +++ b/test.c @@ -0,0 +1,8 @@ + +#include + +int main() { + char string[] = "hi"; + printf("%s\n", string); + return 0; +} diff --git a/test.sh b/test.sh deleted file mode 100755 index 44faf72..0000000 --- a/test.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -if [ "$1" != "-shared" ]; then - clang -static -nostdlib tests/empty.c lib/ciabatta.a -Iinclude -else - clang -g -fno-stack-protector -fPIE tests/empty.c -c -o tests/empty.o - ld -no-pie -nostdlib lib/entry.o tests/empty.o lib/ciabatta.so lib/ctors.o -Iinclude -fi \ No newline at end of file diff --git a/tests/empty.c b/tests/empty.c index 9fe76e4..925a5b1 100644 --- a/tests/empty.c +++ b/tests/empty.c @@ -15,8 +15,8 @@ static inline i64 syscall_write(u32 fd, char const *buf, u64 count) { return __syscall3(SYS_write, (i64)fd, (i64)buf, (u64)count); } -char string[] = "Hello, world!\n"; int main(int argc, char **argv, char **envp) { + char string[] = "Hello, world!\n"; syscall_write(STDOUT_FILENO, string, sizeof string); return 0; }