kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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 }