Last active
July 17, 2022 16:39
-
-
Save josephcsible/c8ce72a6084634fe56928c4bd20e6d52 to your computer and use it in GitHub Desktop.
Make it impossible for strace to force a syscall
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _GNU_SOURCE | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <fcntl.h> | |
#include <sys/mman.h> | |
#include <sys/syscall.h> | |
struct mapping_list { | |
void *start; | |
size_t len; | |
struct mapping_list *next; | |
}; | |
typedef void unmap_all_t(struct mapping_list *list, void *start, size_t len); | |
extern unmap_all_t unmap_all; | |
extern const char unmap_all_end[]; | |
__asm__("\n" | |
"unmap_all:\n" | |
" endbr64\n" | |
" movq %rsi, %r8 # save start\n" | |
" movq %rdi, %r9 # save list\n" | |
".unmap_list_element:\n" | |
" movq (%r9), %rdi # pass list->start as addr\n" | |
" movq 8(%r9), %rsi # pass list->len as length\n" | |
" movl $11, %eax # SYS_munmap\n" | |
" syscall\n" | |
" movq 16(%r9), %r9 # advance to the next list element\n" | |
" testq %r9, %r9\n" | |
" jne .unmap_list_element\n" | |
" movl $11, %eax # SYS_munmap\n" | |
" movq %r8, %rdi # pass start as addr\n" | |
" movq %rdx, %rsi # pass len as length\n" | |
" jmp .final_syscall\n" | |
" .org unmap_all+4094 # make sure the upcoming syscall instruction is at the very end of the page,\n" | |
".final_syscall: # given that unmap_all started at the very beginning of it\n" | |
" syscall\n" | |
".loop_forever:\n" | |
" jmp .loop_forever\n" | |
"unmap_all_end:\n" | |
); | |
int main(void) { | |
FILE *maps = fopen("/proc/self/maps", "r"); | |
if(!maps) { | |
perror("fopen"); | |
return 1; | |
} | |
struct mapping_list *list = NULL; | |
unsigned long start, end; | |
char r, w, x; | |
while(fscanf(maps, "%lx-%lx %c%c%c", &start, &end, &r, &w, &x) == 5) { | |
while(fgetc(maps) != '\n'); | |
if(x != 'x') continue; | |
struct mapping_list *new_list = malloc(sizeof(struct mapping_list)); | |
new_list->start = (void*)start; | |
new_list->len = end - start; | |
new_list->next = list; | |
list = new_list; | |
} | |
if(fclose(maps)) { | |
perror("fclose"); | |
return 1; | |
} | |
int memfd = syscall(SYS_memfd_create, "unmap_all", 2 /* MFD_ALLOW_SEALING */); | |
if(memfd == -1) { | |
perror("memfd_create"); | |
return 1; | |
} | |
if(ftruncate(memfd, 8192)) { | |
perror("ftruncate"); | |
return 1; | |
} | |
char *pages = mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_SHARED, memfd, 0); | |
if(pages == MAP_FAILED) { | |
perror("mmap"); | |
return 1; | |
} | |
memcpy(pages, unmap_all, unmap_all_end - (const char*)unmap_all); | |
if(munmap(pages, 8192)) { | |
perror("munmap"); | |
return 1; | |
} | |
char *path; | |
if(asprintf(&path, "/proc/self/fd/%d", memfd) == -1) { | |
perror("asprintf"); | |
return 1; | |
} | |
int memfd_ro = open(path, O_RDONLY); | |
if(memfd_ro == -1) { | |
perror("open"); | |
return 1; | |
} | |
free(path); | |
if(fcntl(memfd, 1033 /* F_ADD_SEALS */, 15 /* F_SEAL_SEAL|F_SEAL_SHRINK|F_SEAL_GROW|F_SEAL_WRITE */)) { | |
perror("fcntl"); | |
return 1; | |
} | |
if(close(memfd)) { | |
perror("close"); | |
return 1; | |
} | |
pages = mmap(NULL, 8192, PROT_READ|PROT_EXEC, MAP_SHARED, memfd_ro, 0); | |
if(pages == MAP_FAILED) { | |
perror("mmap"); | |
return 1; | |
} | |
if(close(memfd_ro)) { | |
perror("close"); | |
return 1; | |
} | |
((unmap_all_t*)pages)(list, pages, 4096); | |
__builtin_unreachable(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment