draugr.git


draugr

~ single ELF file analysis tool
git clone https://github.com/djnnvx/draugr.git
log | files | refs | archive | README

checksec_test.odin (3656B)

      1 package elf
      2 
      3 import "core:testing"
      4 
      5 checksec_info :: proc(phdrs: []Program_Header, dyn: [][2]u64) -> ELF_Info {
      6 	info: ELF_Info
      7 	info.program_hdrs = make([dynamic]Program_Header)
      8 	info.section_hdrs = make([dynamic]Section_Header)
      9 	info.symbols = make([dynamic]Symbol)
     10 	info.dyn_symbols = make([dynamic]Symbol)
     11 	info.dyn_entries = make([dynamic]Dyn_Entry)
     12 	info.needed = make([dynamic]string)
     13 	info.relocs = make([dynamic]Reloc)
     14 	info.header.type = ET_DYN
     15 
     16 	for p in phdrs {
     17 		append(&info.program_hdrs, p)
     18 	}
     19 	for e in dyn {
     20 		append(&info.dyn_entries, Dyn_Entry{tag = e[0], val = e[1]})
     21 	}
     22 	return info
     23 }
     24 
     25 @(test)
     26 test_relro_needs_bind_now_for_full :: proc(t: ^testing.T) {
     27 	none := checksec_info({}, {})
     28 	defer destroy(&none)
     29 	testing.expect_value(t, relro_state(&none), Relro.None)
     30 
     31 	partial := checksec_info({{type = PT_GNU_RELRO}}, {})
     32 	defer destroy(&partial)
     33 	testing.expect_value(t, relro_state(&partial), Relro.Partial)
     34 
     35 	full := checksec_info({{type = PT_GNU_RELRO}}, {{DT_FLAGS, DF_BIND_NOW}})
     36 	defer destroy(&full)
     37 	testing.expect_value(t, relro_state(&full), Relro.Full)
     38 
     39 	full1 := checksec_info({{type = PT_GNU_RELRO}}, {{DT_FLAGS_1, DF_1_NOW}})
     40 	defer destroy(&full1)
     41 	testing.expect_value(t, relro_state(&full1), Relro.Full)
     42 }
     43 
     44 @(test)
     45 test_nx_absent_segment_is_unknown :: proc(t: ^testing.T) {
     46 	unknown := checksec_info({}, {})
     47 	defer destroy(&unknown)
     48 	testing.expect_value(t, nx_state(&unknown), Nx.Unknown)
     49 
     50 	on := checksec_info({{type = PT_GNU_STACK, flags = PF_R | PF_W}}, {})
     51 	defer destroy(&on)
     52 	testing.expect_value(t, nx_state(&on), Nx.Enabled)
     53 
     54 	off := checksec_info({{type = PT_GNU_STACK, flags = PF_R | PF_W | PF_X}}, {})
     55 	defer destroy(&off)
     56 	testing.expect_value(t, nx_state(&off), Nx.Disabled)
     57 }
     58 
     59 @(test)
     60 test_pie_distinguishes_shared_library_from_executable :: proc(t: ^testing.T) {
     61 	pie := checksec_info({{type = PT_INTERP}}, {})
     62 	defer destroy(&pie)
     63 	testing.expect_value(t, pie_state(&pie), Pie.Pie)
     64 
     65 	lib := checksec_info({}, {{DT_SONAME, 1}})
     66 	defer destroy(&lib)
     67 	testing.expect_value(t, pie_state(&lib), Pie.Shared_Library)
     68 
     69 	spie := checksec_info({}, {{DT_FLAGS_1, DF_1_PIE}})
     70 	defer destroy(&spie)
     71 	testing.expect_value(t, pie_state(&spie), Pie.Static_Pie)
     72 
     73 	exe := checksec_info({}, {})
     74 	defer destroy(&exe)
     75 	exe.header.type = ET_EXEC
     76 	testing.expect_value(t, pie_state(&exe), Pie.None)
     77 }
     78 
     79 @(test)
     80 test_rwx_and_textrel_are_flagged :: proc(t: ^testing.T) {
     81 	clean := checksec_info({{type = PT_LOAD, flags = PF_R | PF_X}}, {})
     82 	defer destroy(&clean)
     83 	testing.expect(t, !has_rwx_segment(&clean), "R X segment is not RWX")
     84 	testing.expect(t, !has_textrel(&clean), "no DT_TEXTREL")
     85 
     86 	rwx := checksec_info({{type = PT_LOAD, flags = PF_R | PF_W | PF_X}}, {{DT_TEXTREL, 0}})
     87 	defer destroy(&rwx)
     88 	testing.expect(t, has_rwx_segment(&rwx), "RWX PT_LOAD must be flagged")
     89 	testing.expect(t, has_textrel(&rwx), "DT_TEXTREL must be flagged")
     90 
     91 	flagged := checksec_info({}, {{DT_FLAGS, DF_TEXTREL}})
     92 	defer destroy(&flagged)
     93 	testing.expect(t, has_textrel(&flagged), "DF_TEXTREL must be flagged")
     94 }
     95 
     96 @(test)
     97 test_fortify_excludes_stack_canary :: proc(t: ^testing.T) {
     98 	info := checksec_info({}, {})
     99 	defer destroy(&info)
    100 
    101 	append(&info.dyn_symbols, Symbol{name = "__stack_chk_fail"})
    102 	append(&info.dyn_symbols, Symbol{name = "__memcpy_chk"})
    103 	append(&info.dyn_symbols, Symbol{name = "memcpy"})
    104 	append(&info.dyn_symbols, Symbol{name = "strcpy"})
    105 
    106 	fortified, fortifiable, partial := fortify_counts(&info)
    107 	testing.expect_value(t, fortified, 1)
    108 	testing.expect_value(t, fortifiable, 2)
    109 	testing.expect_value(t, partial, 1)
    110 
    111 	c := checksec(&info)
    112 	testing.expect(t, c.canary, "__stack_chk_fail must still set the canary flag")
    113 }