commit 77d5ba4e5bb35f91d026a3240ad0a91a2d4b662a Author: Cédric VINCENT Date: Fri Feb 20 14:28:55 2015 +0100 Set tracee's stack executable when the loaded program requires this. This is required for UMEQ and for some older versions of PRoot. For example: $ proot -q umeq-arm64-dce01957 -R ~/gentoo-arm64-20140718 Before: proot info: vpid 1 terminated with signal 11 Now, it is OK. diff --git a/src/compat.h b/src/compat.h index 2b603f1..5009490 100644 --- a/src/compat.h +++ b/src/compat.h @@ -243,5 +243,17 @@ # ifndef MAP_ANONYMOUS # define MAP_ANONYMOUS 0x20 # endif +# ifndef PROT_READ +# define PROT_READ 0x1 +# endif +# ifndef PROT_WRITE +# define PROT_WRITE 0x2 +# endif +# ifndef PROT_EXEC +# define PROT_EXEC 0x4 +# endif +# ifndef PROT_GROWSDOWN +# define PROT_GROWSDOWN 0x01000000 +# endif #endif /* COMPAT_H */ diff --git a/src/execve/elf.h b/src/execve/elf.h index 3ced10c..a5b367b 100644 --- a/src/execve/elf.h +++ b/src/execve/elf.h @@ -108,7 +108,8 @@ typedef union { typedef enum { PT_LOAD = 1, PT_DYNAMIC = 2, - PT_INTERP = 3 + PT_INTERP = 3, + PT_GNU_STACK = 0x6474e551, } SegmentType; typedef struct { diff --git a/src/execve/enter.c b/src/execve/enter.c index cb84ec6..f0f3e7f 100644 --- a/src/execve/enter.c +++ b/src/execve/enter.c @@ -252,6 +252,11 @@ static int add_load_info(const ElfHeader *elf_header, return status; break; + case PT_GNU_STACK: + data->load_info->needs_executable_stack |= + ((PROGRAM_FIELD(*elf_header, *program_header, flags) & PF_X) != 0); + break; + default: break; } diff --git a/src/execve/execve.h b/src/execve/execve.h index 11eca10..98b8d03 100644 --- a/src/execve/execve.h +++ b/src/execve/execve.h @@ -49,6 +49,7 @@ typedef struct load_info { char *raw_path; Mapping *mappings; ElfHeader elf_header; + bool needs_executable_stack; struct load_info *interp; } LoadInfo; diff --git a/src/execve/exit.c b/src/execve/exit.c index e6eff44..36cc51f 100644 --- a/src/execve/exit.c +++ b/src/execve/exit.c @@ -174,6 +174,9 @@ static void *transcript_mappings(void *cursor, const Mapping *mappings) static int transfer_load_script(Tracee *tracee) { const word_t stack_pointer = peek_reg(tracee, CURRENT, STACK_POINTER); + static word_t page_size = 0; + static word_t page_mask = 0; + word_t entry_point; size_t script_size; @@ -190,10 +193,22 @@ static int transfer_load_script(Tracee *tracee) void *buffer; size_t buffer_size; + bool needs_executable_stack; LoadStatement *statement; void *cursor; int status; + if (page_size == 0) { + page_size = sysconf(_SC_PAGE_SIZE); + if ((int) page_size <= 0) + page_size = 0x1000; + page_mask = ~(page_size - 1); + } + + needs_executable_stack = (tracee->load_info->needs_executable_stack + || ( tracee->load_info->interp != NULL + && tracee->load_info->interp->needs_executable_stack)); + /* Strings addresses are required to generate the load script, * for "open" actions. Since I want to generate it in one * pass, these strings will be put right below the current @@ -208,7 +223,7 @@ static int transfer_load_script(Tracee *tracee) : strlen(tracee->load_info->raw_path) + 1); /* A padding will be appended at the end of the load script - * (a.k.a "strings area") to ensure this latter is aligned on + * (a.k.a "strings area") to ensure this latter is aligned to * a word boundary, for sake of performance. */ padding_size = (stack_pointer - string1_size - string2_size - string3_size) % sizeof_word(tracee); @@ -229,6 +244,7 @@ static int transfer_load_script(Tracee *tracee) : LOAD_STATEMENT_SIZE(*statement, open) + (LOAD_STATEMENT_SIZE(*statement, mmap) * talloc_array_length(tracee->load_info->interp->mappings))) + + (needs_executable_stack ? LOAD_STATEMENT_SIZE(*statement, make_stack_exec) : 0) + LOAD_STATEMENT_SIZE(*statement, start); /* Allocate enough room for both the load script and the @@ -266,6 +282,16 @@ static int transfer_load_script(Tracee *tracee) else entry_point = ELF_FIELD(tracee->load_info->elf_header, entry); + if (needs_executable_stack) { + /* Load script statement: stack_exec. */ + statement = cursor; + + statement->action = LOAD_ACTION_MAKE_STACK_EXEC; + statement->make_stack_exec.start = stack_pointer & page_mask; + + cursor += LOAD_STATEMENT_SIZE(*statement, make_stack_exec); + } + /* Load script statement: start. */ statement = cursor; @@ -352,7 +378,7 @@ static int transfer_load_script(Tracee *tracee) * | mmap file | * +------------+ * | open | - * +------------+ <- stack pointer, sysarg1 (word aligned) + * +------------+ <- stack pointer, userarg1 (word aligned) */ /* Remember we are in the sysexit stage, so be sure the diff --git a/src/loader/assembly-arm.h b/src/loader/assembly-arm.h index ee5bb85..59a7fe0 100644 --- a/src/loader/assembly-arm.h +++ b/src/loader/assembly-arm.h @@ -89,4 +89,5 @@ #define EXECVE 11 #define EXIT 1 #define PRCTL 172 +#define MPROTECT 125 diff --git a/src/loader/assembly-x86.h b/src/loader/assembly-x86.h index c83b3ef..4045144 100644 --- a/src/loader/assembly-x86.h +++ b/src/loader/assembly-x86.h @@ -65,3 +65,4 @@ extern word_t syscall_1(word_t number, word_t arg1); #define EXECVE 11 #define EXIT 1 #define PRCTL 172 +#define MPROTECT 125 diff --git a/src/loader/assembly-x86_64.h b/src/loader/assembly-x86_64.h index c581208..6f431be 100644 --- a/src/loader/assembly-x86_64.h +++ b/src/loader/assembly-x86_64.h @@ -93,3 +93,4 @@ #define EXECVE 59 #define EXIT 60 #define PRCTL 157 +#define MPROTECT 10 diff --git a/src/loader/loader.c b/src/loader/loader.c index 5b31b02..9c2037b 100644 --- a/src/loader/loader.c +++ b/src/loader/loader.c @@ -171,6 +171,14 @@ void _start(void *cursor) cursor += LOAD_STATEMENT_SIZE(*stmt, mmap); break; + case LOAD_ACTION_MAKE_STACK_EXEC: + SYSCALL(MPROTECT, 3, + stmt->make_stack_exec.start, 1, + PROT_READ | PROT_WRITE | PROT_EXEC | PROT_GROWSDOWN); + + cursor += LOAD_STATEMENT_SIZE(*stmt, make_stack_exec); + break; + case LOAD_ACTION_START_TRACED: traced = true; /* Fall through. */ diff --git a/src/loader/script.h b/src/loader/script.h index bb48af5..6ae7621 100644 --- a/src/loader/script.h +++ b/src/loader/script.h @@ -42,6 +42,10 @@ struct load_statement { word_t clear_length; } mmap; + struct { + word_t start; + } make_stack_exec; + struct { word_t stack_pointer; word_t entry_point; @@ -67,7 +71,8 @@ typedef struct load_statement LoadStatement; #define LOAD_ACTION_OPEN 1 #define LOAD_ACTION_MMAP_FILE 2 #define LOAD_ACTION_MMAP_ANON 3 -#define LOAD_ACTION_START_TRACED 4 -#define LOAD_ACTION_START 5 +#define LOAD_ACTION_MAKE_STACK_EXEC 4 +#define LOAD_ACTION_START_TRACED 5 +#define LOAD_ACTION_START 6 #endif /* SCRIPT */ commit d649854ddb66779950954aac99d960379c631a71 Author: Nicolas Cornu Date: Wed Jul 29 14:52:57 2015 +0200 Fix use of size diff --git a/src/execve/enter.c b/src/execve/enter.c index 8f22d9c..4c163a1 100644 --- a/src/execve/enter.c +++ b/src/execve/enter.c @@ -454,10 +454,10 @@ static int expand_runner(Tracee* tracee, char host_path[PATH_MAX], char user_pat } extern unsigned char _binary_loader_exe_start; -extern unsigned char _binary_loader_exe_size; +extern unsigned char _binary_loader_exe_end; extern unsigned char WEAK _binary_loader_m32_exe_start; -extern unsigned char WEAK _binary_loader_m32_exe_size; +extern unsigned char WEAK _binary_loader_m32_exe_end; /** * Extract the built-in loader. This function returns NULL if an @@ -483,11 +483,11 @@ static char *extract_loader(const Tracee *tracee, bool wants_32bit_version) if (wants_32bit_version) { start = (void *) &_binary_loader_m32_exe_start; - size = (size_t) &_binary_loader_m32_exe_size; + size = (size_t)(&_binary_loader_m32_exe_end-&_binary_loader_m32_exe_start); } else { start = (void *) &_binary_loader_exe_start; - size = (size_t) &_binary_loader_exe_size; + size = (size_t) (&_binary_loader_exe_end-&_binary_loader_exe_start); } status2 = write(fd, start, size);