From efb19cfa245b974f5d4e5d97b35fc23cf4130c19 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Sun, 16 Jun 2019 22:51:26 -0700 Subject: [PATCH] [LibOS] support stack protector with compile time option Signed-off-by: Isaku Yamahata --- LibOS/shim/include/shim_internal.h | 1 + LibOS/shim/include/shim_thread.h | 8 ++++ LibOS/shim/include/shim_tls.h | 12 ++++++ LibOS/shim/src/.gitignore | 1 + LibOS/shim/src/Makefile | 22 ++++++++++- LibOS/shim/src/bookkeep/shim_thread.c | 10 ++++- LibOS/shim/src/generated-offsets.c | 5 +++ LibOS/shim/src/shim_init.c | 16 ++++++-- LibOS/shim/src/shim_stack_protector.c | 54 +++++++++++++++++++++++++++ LibOS/shim/src/start.S | 4 ++ Makefile.configs | 3 ++ Makefile.rules | 7 ++++ 12 files changed, 136 insertions(+), 7 deletions(-) create mode 100644 LibOS/shim/src/shim_stack_protector.c diff --git a/LibOS/shim/include/shim_internal.h b/LibOS/shim/include/shim_internal.h index 636af352..132b38b5 100644 --- a/LibOS/shim/include/shim_internal.h +++ b/LibOS/shim/include/shim_internal.h @@ -142,6 +142,7 @@ static inline PAL_HANDLE __open_shim_stdio (void) return shim_stdio; } +noreturn void* shim_init (int argc, void * args); noreturn void shim_terminate (int err); /* assertions */ diff --git a/LibOS/shim/include/shim_thread.h b/LibOS/shim/include/shim_thread.h index c93da15a..d450ec97 100644 --- a/LibOS/shim/include/shim_thread.h +++ b/LibOS/shim/include/shim_thread.h @@ -145,7 +145,15 @@ void put_thread (struct shim_thread * thread); void get_simple_thread (struct shim_simple_thread * thread); void put_simple_thread (struct shim_simple_thread * thread); +void __allocate_tls (__libc_tcb_t * tcb_location, bool user, struct shim_thread * thread); +#ifdef ENABLE_STACK_PROTECTOR void allocate_tls (__libc_tcb_t * tcb_location, bool user, struct shim_thread * thread); +#else +static inline void allocate_tls (__libc_tcb_t * tcb_location, bool user, struct shim_thread * thread) +{ + __allocate_tls(tcb_location, user, thread); +} +#endif void populate_tls (__libc_tcb_t * tcb_location, bool user); void debug_setprefix (shim_tcb_t * tcb); diff --git a/LibOS/shim/include/shim_tls.h b/LibOS/shim/include/shim_tls.h index 24960a44..98b0038e 100644 --- a/LibOS/shim/include/shim_tls.h +++ b/LibOS/shim/include/shim_tls.h @@ -54,6 +54,10 @@ struct debug_buf; typedef struct shim_tcb shim_tcb_t; struct shim_tcb { uint64_t canary; +#ifdef ENABLE_STACK_PROTECTOR +#define STACK_PROTECTOR_CANARY_DEFAULT 0xbadbadbadbadUL + uint64_t stack_protector_canary; +#endif shim_tcb_t * self; struct shim_thread * tp; struct shim_context context; @@ -94,7 +98,15 @@ struct __libc_tcb_t #include +void __init_tcb (shim_tcb_t * tcb); +#ifdef ENABLE_STACK_PROTECTOR void init_tcb (shim_tcb_t * tcb); +#else +static inline void init_tcb (shim_tcb_t * tcb) +{ + __init_tcb(tcb); +} +#endif static inline bool shim_tls_check_canary(void) { diff --git a/LibOS/shim/src/.gitignore b/LibOS/shim/src/.gitignore index 576c6e45..5aa5f6b0 100644 --- a/LibOS/shim/src/.gitignore +++ b/LibOS/shim/src/.gitignore @@ -1,3 +1,4 @@ +/.Makefile.stack-protector /libsysdb.so.cached /asm-offsets.h /generated-offsets.s diff --git a/LibOS/shim/src/Makefile b/LibOS/shim/src/Makefile index 952b8ab5..f257fa88 100644 --- a/LibOS/shim/src/Makefile +++ b/LibOS/shim/src/Makefile @@ -9,7 +9,7 @@ CFLAGS = -Wall -fPIC -std=c11 -Winline -Wwrite-strings \ -fmerge-all-constants -Wstrict-prototypes \ -Werror=implicit-function-declaration \ $(cc-option, -Wnull-dereference) \ - -fno-stack-protector -fno-builtin -Wno-inline \ + -fno-builtin -Wno-inline \ -I../include -I../../../Pal/lib -I../../../Pal/include/pal EXTRAFLAGS = -Wextra @@ -69,6 +69,26 @@ ifeq ($(PROFILING), 1) CFLAGS += -DPROFILE endif +.Makefile.stack-protector: asm-offsets.h + $(call cmd,makefile_stack_protector) + +ifeq ($(CONFIG_SHIM_STACK_PROTECTOR),y) +objs += shim_stack_protector +CFLAGS-shim_stack_protector.o += -fno-stack-protector +# gcc 8 or later is required for the folloings options +# -mstack-protector-guard-offset, -mstack-protector-guard-reg +include .Makefile.stack-protector +$(addsuffix .o,$(objs)): .Makefile.stack-protector +ASFLAGS += -DENABLE_STACK_PROTECTOR=1 +CFLAGS += -DENABLE_STACK_PROTECTOR=1 +ifneq ($(CONFIG_STACK_PROTECTOR_GUARD_OFFSET),) +CFLAGS += -mstack-protector-guard-offset=$(CONFIG_STACK_PROTECTOR_GUARD_OFFSET) +endif +CFLAGS += -mstack-protector-guard-reg=%fs +else +CFLAGS += -fno-stack-protector +endif + $(files_to_install): $(RUNTIME_DIR)/%: % $(call cmd,ln_sf) diff --git a/LibOS/shim/src/bookkeep/shim_thread.c b/LibOS/shim/src/bookkeep/shim_thread.c index 674ebd03..b63dea82 100644 --- a/LibOS/shim/src/bookkeep/shim_thread.c +++ b/LibOS/shim/src/bookkeep/shim_thread.c @@ -765,12 +765,15 @@ BEGIN_RS_FUNC(running_thread) thread->pal_handle = handle; } else { __libc_tcb_t * libc_tcb = thread->tcb; +#ifdef ENABLE_STACK_PROTECTOR + uint64_t stack_protector_canary = shim_libc_tcb()->shim_tcb.stack_protector_canary; +#endif if (libc_tcb) { shim_tcb_t * tcb = &libc_tcb->shim_tcb; assert(tcb->context.regs && tcb->context.regs->rsp); tcb->debug_buf = shim_get_tls()->debug_buf; - allocate_tls(libc_tcb, thread->user_tcb, thread); + __allocate_tls(libc_tcb, thread->user_tcb, thread); /* Temporarily disable preemption until the thread resumes. */ __disable_preempt(tcb); debug_setprefix(tcb); @@ -785,12 +788,15 @@ BEGIN_RS_FUNC(running_thread) * user_tcb = false * in_vm = false */ - init_tcb(&shim_libc_tcb()->shim_tcb); + __init_tcb(&shim_libc_tcb()->shim_tcb); set_cur_thread(thread); } thread->in_vm = thread->is_alive = true; thread->pal_handle = PAL_CB(first_thread); +#ifdef ENABLE_STACK_PROTECTOR + shim_libc_tcb()->shim_tcb.stack_protector_canary = stack_protector_canary; +#endif } DEBUG_RS("tid=%d", thread->tid); diff --git a/LibOS/shim/src/generated-offsets.c b/LibOS/shim/src/generated-offsets.c index f9235a7c..46270035 100644 --- a/LibOS/shim/src/generated-offsets.c +++ b/LibOS/shim/src/generated-offsets.c @@ -16,5 +16,10 @@ void dummy(void) /* definitions */ DEFINE(RED_ZONE_SIZE, RED_ZONE_SIZE); + +#ifdef ENABLE_STACK_PROTECTOR + /* stack protector*/ + OFFSET_T(STACK_PROTECTOR_CANARY, __libc_tcb_t, shim_tcb.stack_protector_canary); +#endif } diff --git a/LibOS/shim/src/shim_init.c b/LibOS/shim/src/shim_init.c index 9e29dfc4..e0b3e61e 100644 --- a/LibOS/shim/src/shim_init.c +++ b/LibOS/shim/src/shim_init.c @@ -71,9 +71,14 @@ void warn (const char *format, ...) } -void __stack_chk_fail (void) +#ifdef ENABLE_STACK_PROTECTOR +noreturn void __stack_chk_fail (void) { + __SYS_PRINTF("stack protector: libos stack is corrupted in %p", + __builtin_return_address(0)); + __abort(); } +#endif static int pal_errno_to_unix_errno [PAL_ERROR_BOUND + 1] = { /* reserved */ 0, @@ -183,7 +188,7 @@ char ** library_paths = NULL; struct shim_lock __master_lock; bool lock_enabled; -void init_tcb (shim_tcb_t * tcb) +void __init_tcb (shim_tcb_t * tcb) { tcb->canary = SHIM_TLS_CANARY; tcb->self = tcb; @@ -193,6 +198,9 @@ void copy_tcb (shim_tcb_t * new_tcb, const shim_tcb_t * old_tcb) { memset(new_tcb, 0, sizeof(shim_tcb_t)); new_tcb->canary = SHIM_TLS_CANARY; +#ifdef ENABLE_STACK_PROTECTOR + new_tcb->stack_protector_canary = old_tcb->stack_protector_canary; +#endif new_tcb->self = new_tcb; new_tcb->tp = old_tcb->tp; memcpy(&new_tcb->context, &old_tcb->context, sizeof(struct shim_context)); @@ -201,11 +209,11 @@ void copy_tcb (shim_tcb_t * new_tcb, const shim_tcb_t * old_tcb) } /* This function is used to allocate tls before interpreter start running */ -void allocate_tls (__libc_tcb_t * tcb, bool user, struct shim_thread * thread) +void __allocate_tls (__libc_tcb_t * tcb, bool user, struct shim_thread * thread) { assert(tcb); tcb->tcb = tcb; - init_tcb(&tcb->shim_tcb); + __init_tcb(&tcb->shim_tcb); if (thread) { thread->tcb = tcb; diff --git a/LibOS/shim/src/shim_stack_protector.c b/LibOS/shim/src/shim_stack_protector.c new file mode 100644 index 00000000..bf1c3423 --- /dev/null +++ b/LibOS/shim/src/shim_stack_protector.c @@ -0,0 +1,54 @@ +/* Copyright 2019 Intel Corporation. + Copyright 2019 Isaku Yamahata + + This file is part of Graphene Library OS. + + Graphene Library OS is free software: you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + Graphene Library OS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . + */ + +#include +#include +#include + +#include "asm-offsets.h" + +noreturn void __shim_init (int argc, void * args) +{ + static uint64_t tcb[STACK_PROTECTOR_CANARY + 8 / sizeof(uint64_t)] = + { [STACK_PROTECTOR_CANARY / sizeof(uint64_t)] = STACK_PROTECTOR_CANARY_DEFAULT }; + DkSegmentRegister(PAL_SEGMENT_FS, &tcb); + shim_init(argc, args); +} + +static void reset_stack_protector_canary (shim_tcb_t * tcb) +{ + uint64_t stack_protector_canary; + int ret = DkRandomBitsRead(&stack_protector_canary, sizeof(stack_protector_canary)); + if (ret < 0) + stack_protector_canary = STACK_PROTECTOR_CANARY_DEFAULT; + tcb->stack_protector_canary = stack_protector_canary; +} + +void init_tcb (shim_tcb_t * tcb) +{ + __init_tcb(tcb); + reset_stack_protector_canary(tcb); +} + +/* This function is used to allocate tls before interpreter start running */ +void allocate_tls (__libc_tcb_t * tcb, bool user, struct shim_thread * thread) +{ + __allocate_tls(tcb, user, thread); + reset_stack_protector_canary(&tcb->shim_tcb); +} diff --git a/LibOS/shim/src/start.S b/LibOS/shim/src/start.S index c2a68ed6..a694c059 100644 --- a/LibOS/shim/src/start.S +++ b/LibOS/shim/src/start.S @@ -34,7 +34,11 @@ shim_start: # Required by System V AMD64 ABI. andq $~0xF, %rsp +#ifdef ENABLE_STACK_PROTECTOR + callq *__shim_init@GOTPCREL(%rip) +#else callq *shim_init@GOTPCREL(%rip) +#endif # TODO: Call initial %rdi to execute atexit callbacks. .cfi_endproc diff --git a/Makefile.configs b/Makefile.configs index 2064845e..619790ca 100644 --- a/Makefile.configs +++ b/Makefile.configs @@ -14,3 +14,6 @@ OBJCOPY ?= objcopy CONFIG_PAL_STACK_PROTECTOR = n # CONFIG_PAL_STACK_PROTECTOR = y + +CONFIG_SHIM_STACK_PROTECTOR = n +# CONFIG_SHIM_STACK_PROTECTOR = y diff --git a/Makefile.rules b/Makefile.rules index b4a47aae..5fb500d9 100644 --- a/Makefile.rules +++ b/Makefile.rules @@ -109,3 +109,10 @@ quiet_cmd_ld = [ $@ ] # OBJCOPY quiet_cmd_objcopy = [ $@ ] cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS-$@) $< $@ + +# stack protector +quiet_cmd_makefile_stack_protector = [ $@ ] + cmd_makefile_stack_protector = \ + (set -e; \ + awk '/\#define STACK_PROTECTOR_CANARY/{print "CONFIG_STACK_PROTECTOR_GUARD_OFFSET="$$3}' $^; \ + ) > $@