stack_protector.c (4629B)
1 #include "cg/internal.h" 2 3 static KitSym stack_linkage_name(KitCg* g, const char* name) { 4 Sym source = pool_intern_slice(g->c->global, slice_from_cstr(name)); 5 return kit_cg_c_linkage_name((KitCompiler*)g->c, source); 6 } 7 8 static KitCgSym stack_guard_decl(KitCg* g, KitCgTypeId ty, 9 const char* name) { 10 KitCgDecl decl; 11 memset(&decl, 0, sizeof decl); 12 decl.kind = KIT_CG_DECL_OBJECT; 13 decl.linkage_name = stack_linkage_name(g, name); 14 decl.display_name = decl.linkage_name; 15 decl.type = ty; 16 decl.sym.bind = KIT_SB_GLOBAL; 17 decl.sym.visibility = KIT_CG_VIS_DEFAULT; 18 return kit_cg_decl(g, decl); 19 } 20 21 static KitCgSym stack_func_decl(KitCg* g, const char* name, 22 KitCgTypeId param, int noreturn) { 23 KitCgFuncParam p; 24 KitCgFuncResult result; 25 KitCgFuncSig sig; 26 KitCgDecl decl; 27 memset(&p, 0, sizeof p); 28 memset(&result, 0, sizeof result); 29 memset(&sig, 0, sizeof sig); 30 memset(&decl, 0, sizeof decl); 31 p.type = param; 32 result.type = kit_cg_type_builtin((KitCompiler*)g->c, KIT_CG_BUILTIN_VOID); 33 sig.result = result; 34 sig.params = param ? &p : NULL; 35 sig.nparams = param ? 1u : 0u; 36 sig.call_conv = KIT_CG_CC_TARGET_C; 37 decl.kind = KIT_CG_DECL_FUNC; 38 decl.linkage_name = stack_linkage_name(g, name); 39 decl.display_name = decl.linkage_name; 40 decl.type = kit_cg_type_func((KitCompiler*)g->c, sig); 41 decl.sym.bind = KIT_SB_GLOBAL; 42 decl.sym.visibility = KIT_CG_VIS_DEFAULT; 43 if (noreturn) decl.as.func.flags |= KIT_CG_FUNC_NORETURN; 44 return kit_cg_decl(g, decl); 45 } 46 47 static KitCgMemAccess stack_guard_access(KitCg* g) { 48 KitCgMemAccess access; 49 memset(&access, 0, sizeof access); 50 access.type = g->stack_guard_type; 51 access.align = g->c->target.ptr_align ? g->c->target.ptr_align 52 : g->c->target.ptr_size; 53 return access; 54 } 55 56 static int stack_guard_uses_x64_tls(KitTargetSpec spec) { 57 return spec.arch == KIT_ARCH_X86_64 && 58 (spec.os == KIT_OS_LINUX || spec.os == KIT_OS_ANDROID); 59 } 60 61 /* Push the process/thread's current guard value. Most supported ABIs expose 62 * __stack_chk_guard as an ordinary object. Linux and Android x86-64 instead 63 * reserve the word at fs:0x28, so route that read through the native backend 64 * without manufacturing an undefined object reference. */ 65 static void stack_guard_push_current(KitCg* g) { 66 if (g->stack_guard_tls) { 67 CGLocal local = api_alloc_temp_local(g, g->stack_guard_type); 68 Operand dst = api_op_local(local, g->stack_guard_type); 69 g->target->intrinsic(g->target, INTRIN_STACK_GUARD, &dst, 1, NULL, 0); 70 api_push(g, api_make_sv(dst, g->stack_guard_type)); 71 return; 72 } 73 kit_cg_push_symbol_addr(g, g->stack_guard_sym, 0); 74 kit_cg_deref(g, 0); 75 kit_cg_load(g, stack_guard_access(g)); 76 } 77 78 void kit_cg_stack_protector_enable(KitCg* g) { 79 KitTargetSpec spec; 80 KitCgBuiltinType guard_builtin; 81 KitCgLocalAttrs attrs; 82 KitCgMemAccess access; 83 if (!g || g->stack_protected || 84 g->stack_protector_mode == KIT_STACK_PROTECTOR_NONE || 85 g->fn_ret_type == KIT_CG_TYPE_NONE) 86 return; 87 88 spec = kit_compiler_target_spec((KitCompiler*)g->c); 89 guard_builtin = spec.ptr_size == 4u ? KIT_CG_BUILTIN_I32 90 : KIT_CG_BUILTIN_I64; 91 g->stack_guard_type = 92 kit_cg_type_builtin((KitCompiler*)g->c, guard_builtin); 93 g->stack_guard_tls = stack_guard_uses_x64_tls(spec) ? 1u : 0u; 94 if (!g->stack_guard_tls) 95 g->stack_guard_sym = 96 stack_guard_decl(g, g->stack_guard_type, "__stack_chk_guard"); 97 g->stack_fail_sym = 98 stack_func_decl(g, "__stack_chk_fail", KIT_CG_TYPE_NONE, 1); 99 100 memset(&attrs, 0, sizeof attrs); 101 attrs.name = pool_intern_slice(g->c->global, SLICE_LIT("__kit_stack_guard")); 102 attrs.align = spec.ptr_align; 103 attrs.flags = KIT_CG_LOCAL_ARTIFICIAL | KIT_CG_LOCAL_MEMORY_REQUIRED; 104 g->stack_guard_local = kit_cg_local(g, g->stack_guard_type, attrs); 105 106 access = stack_guard_access(g); 107 kit_cg_push_local(g, g->stack_guard_local); 108 stack_guard_push_current(g); 109 kit_cg_store(g, access); 110 g->stack_protected = 1; 111 } 112 113 void api_stack_protector_check(KitCg* g) { 114 KitCgMemAccess access; 115 KitCgCallAttrs attrs; 116 if (!g || !g->stack_protected) return; 117 access = stack_guard_access(g); 118 memset(&attrs, 0, sizeof attrs); 119 120 { 121 KitCgLabel ok = kit_cg_label_new(g); 122 kit_cg_push_local(g, g->stack_guard_local); 123 kit_cg_load(g, access); 124 stack_guard_push_current(g); 125 kit_cg_int_cmp(g, KIT_CG_INT_NE); 126 kit_cg_branch_false(g, ok); 127 kit_cg_call_symbol(g, g->stack_fail_sym, 0, attrs); 128 kit_cg_unreachable(g); 129 kit_cg_label_place(g, ok); 130 } 131 }