# How ELF exec ## Explore ELF test.c is as following: ```c #include <stdio.h> #include <unistd.h> #define THREAD_INTERVAL 500 #define cr_start() \ static int __s = 0; \ switch (__s) { \ case 0: #define cr_yield \ { \ __s = __LINE__; \ return; \ case __LINE__:; \ } #define cr_end() \ } \ __s = 0; static int condition = 1; static void user_thread_1() { cr_start(); for (;;) { /* do something */ printf("Run %s\n", __FUNCTION__); cr_yield; } cr_end(); } static void user_thread_2() { cr_start(); for (;;) { if (condition) { /* do something conditional */ printf("Run %s - (1)\n", __FUNCTION__); cr_yield; } /* do something */ printf("Run %s - (2)\n", __FUNCTION__); condition = !condition; cr_yield; } cr_end(); } int main() { for (;;) { user_thread_1(); user_thread_2(); } return 0; } ``` test is an elf file compiled by gcc. use `objdump`, we can see it is essentially a binary code file from asssembly code. ```shell $ objdump -d test ``` :::spoiler output ```bash test 檔案格式 elf64-x86-64 .init 區段的反組譯: 0000000000001000 <_init>: 1000: f3 0f 1e fa endbr64 1004: 48 83 ec 08 sub $0x8,%rsp 1008: 48 8b 05 d9 2f 00 00 mov 0x2fd9(%rip),%rax # 3fe8 <__gmon_start__@Base> 100f: 48 85 c0 test %rax,%rax 1012: 74 02 je 1016 <_init+0x16> 1014: ff d0 call *%rax 1016: 48 83 c4 08 add $0x8,%rsp 101a: c3 ret .plt 區段的反組譯: 0000000000001020 <.plt>: 1020: ff 35 9a 2f 00 00 push 0x2f9a(%rip) # 3fc0 <_GLOBAL_OFFSET_TABLE_+0x8> 1026: ff 25 9c 2f 00 00 jmp *0x2f9c(%rip) # 3fc8 <_GLOBAL_OFFSET_TABLE_+0x10> 102c: 0f 1f 40 00 nopl 0x0(%rax) 1030: f3 0f 1e fa endbr64 1034: 68 00 00 00 00 push $0x0 1039: e9 e2 ff ff ff jmp 1020 <_init+0x20> 103e: 66 90 xchg %ax,%ax .plt.got 區段的反組譯: 0000000000001040 <__cxa_finalize@plt>: 1040: f3 0f 1e fa endbr64 1044: ff 25 ae 2f 00 00 jmp *0x2fae(%rip) # 3ff8 <__cxa_finalize@GLIBC_2.2.5> 104a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) .plt.sec 區段的反組譯: 0000000000001050 <printf@plt>: 1050: f3 0f 1e fa endbr64 1054: ff 25 76 2f 00 00 jmp *0x2f76(%rip) # 3fd0 <printf@GLIBC_2.2.5> 105a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) .text 區段的反組譯: 0000000000001060 <_start>: 1060: f3 0f 1e fa endbr64 1064: 31 ed xor %ebp,%ebp 1066: 49 89 d1 mov %rdx,%r9 1069: 5e pop %rsi 106a: 48 89 e2 mov %rsp,%rdx 106d: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp 1071: 50 push %rax 1072: 54 push %rsp 1073: 45 31 c0 xor %r8d,%r8d 1076: 31 c9 xor %ecx,%ecx 1078: 48 8d 3d ba 01 00 00 lea 0x1ba(%rip),%rdi # 1239 <main> 107f: ff 15 53 2f 00 00 call *0x2f53(%rip) # 3fd8 <__libc_start_main@GLIBC_2.34> 1085: f4 hlt 1086: 66 2e 0f 1f 84 00 00 cs nopw 0x0(%rax,%rax,1) 108d: 00 00 00 0000000000001090 <deregister_tm_clones>: 1090: 48 8d 3d 81 2f 00 00 lea 0x2f81(%rip),%rdi # 4018 <__TMC_END__> 1097: 48 8d 05 7a 2f 00 00 lea 0x2f7a(%rip),%rax # 4018 <__TMC_END__> 109e: 48 39 f8 cmp %rdi,%rax 10a1: 74 15 je 10b8 <deregister_tm_clones+0x28> 10a3: 48 8b 05 36 2f 00 00 mov 0x2f36(%rip),%rax # 3fe0 <_ITM_deregisterTMCloneTable@Base> 10aa: 48 85 c0 test %rax,%rax 10ad: 74 09 je 10b8 <deregister_tm_clones+0x28> 10af: ff e0 jmp *%rax 10b1: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 10b8: c3 ret 10b9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 00000000000010c0 <register_tm_clones>: 10c0: 48 8d 3d 51 2f 00 00 lea 0x2f51(%rip),%rdi # 4018 <__TMC_END__> 10c7: 48 8d 35 4a 2f 00 00 lea 0x2f4a(%rip),%rsi # 4018 <__TMC_END__> 10ce: 48 29 fe sub %rdi,%rsi 10d1: 48 89 f0 mov %rsi,%rax 10d4: 48 c1 ee 3f shr $0x3f,%rsi 10d8: 48 c1 f8 03 sar $0x3,%rax 10dc: 48 01 c6 add %rax,%rsi 10df: 48 d1 fe sar $1,%rsi 10e2: 74 14 je 10f8 <register_tm_clones+0x38> 10e4: 48 8b 05 05 2f 00 00 mov 0x2f05(%rip),%rax # 3ff0 <_ITM_registerTMCloneTable@Base> 10eb: 48 85 c0 test %rax,%rax 10ee: 74 08 je 10f8 <register_tm_clones+0x38> 10f0: ff e0 jmp *%rax 10f2: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 10f8: c3 ret 10f9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 0000000000001100 <__do_global_dtors_aux>: 1100: f3 0f 1e fa endbr64 1104: 80 3d 09 2f 00 00 00 cmpb $0x0,0x2f09(%rip) # 4014 <completed.0> 110b: 75 2b jne 1138 <__do_global_dtors_aux+0x38> 110d: 55 push %rbp 110e: 48 83 3d e2 2e 00 00 cmpq $0x0,0x2ee2(%rip) # 3ff8 <__cxa_finalize@GLIBC_2.2.5> 1115: 00 1116: 48 89 e5 mov %rsp,%rbp 1119: 74 0c je 1127 <__do_global_dtors_aux+0x27> 111b: 48 8b 3d e6 2e 00 00 mov 0x2ee6(%rip),%rdi # 4008 <__dso_handle> 1122: e8 19 ff ff ff call 1040 <__cxa_finalize@plt> 1127: e8 64 ff ff ff call 1090 <deregister_tm_clones> 112c: c6 05 e1 2e 00 00 01 movb $0x1,0x2ee1(%rip) # 4014 <completed.0> 1133: 5d pop %rbp 1134: c3 ret 1135: 0f 1f 00 nopl (%rax) 1138: c3 ret 1139: 0f 1f 80 00 00 00 00 nopl 0x0(%rax) 0000000000001140 <frame_dummy>: 1140: f3 0f 1e fa endbr64 1144: e9 77 ff ff ff jmp 10c0 <register_tm_clones> 0000000000001149 <user_thread_1>: 1149: f3 0f 1e fa endbr64 114d: 55 push %rbp 114e: 48 89 e5 mov %rsp,%rbp 1151: 8b 05 c1 2e 00 00 mov 0x2ec1(%rip),%eax # 4018 <__TMC_END__> 1157: 85 c0 test %eax,%eax 1159: 74 05 je 1160 <user_thread_1+0x17> 115b: 83 f8 1c cmp $0x1c,%eax 115e: 75 2a jne 118a <user_thread_1+0x41> 1160: 48 8d 05 c9 0e 00 00 lea 0xec9(%rip),%rax # 2030 <__FUNCTION__.2> 1167: 48 89 c6 mov %rax,%rsi 116a: 48 8d 05 97 0e 00 00 lea 0xe97(%rip),%rax # 2008 <_IO_stdin_used+0x8> 1171: 48 89 c7 mov %rax,%rdi 1174: b8 00 00 00 00 mov $0x0,%eax 1179: e8 d2 fe ff ff call 1050 <printf@plt> 117e: c7 05 90 2e 00 00 1c movl $0x1c,0x2e90(%rip) # 4018 <__TMC_END__> 1185: 00 00 00 1188: eb 0a jmp 1194 <user_thread_1+0x4b> 118a: c7 05 84 2e 00 00 00 movl $0x0,0x2e84(%rip) # 4018 <__TMC_END__> 1191: 00 00 00 1194: 5d pop %rbp 1195: c3 ret 0000000000001196 <user_thread_2>: 1196: f3 0f 1e fa endbr64 119a: 55 push %rbp 119b: 48 89 e5 mov %rsp,%rbp 119e: 8b 05 78 2e 00 00 mov 0x2e78(%rip),%eax # 401c <__s.1> 11a4: 83 f8 2f cmp $0x2f,%eax 11a7: 74 10 je 11b9 <user_thread_2+0x23> 11a9: 83 f8 2f cmp $0x2f,%eax 11ac: 7f 7f jg 122d <user_thread_2+0x97> 11ae: 85 c0 test %eax,%eax 11b0: 74 08 je 11ba <user_thread_2+0x24> 11b2: 83 f8 29 cmp $0x29,%eax 11b5: 74 38 je 11ef <user_thread_2+0x59> 11b7: eb 74 jmp 122d <user_thread_2+0x97> 11b9: 90 nop 11ba: 8b 05 50 2e 00 00 mov 0x2e50(%rip),%eax # 4010 <condition> 11c0: 85 c0 test %eax,%eax 11c2: 74 2a je 11ee <user_thread_2+0x58> 11c4: 48 8d 05 75 0e 00 00 lea 0xe75(%rip),%rax # 2040 <__FUNCTION__.0> 11cb: 48 89 c6 mov %rax,%rsi 11ce: 48 8d 05 3b 0e 00 00 lea 0xe3b(%rip),%rax # 2010 <_IO_stdin_used+0x10> 11d5: 48 89 c7 mov %rax,%rdi 11d8: b8 00 00 00 00 mov $0x0,%eax 11dd: e8 6e fe ff ff call 1050 <printf@plt> 11e2: c7 05 30 2e 00 00 29 movl $0x29,0x2e30(%rip) # 401c <__s.1> 11e9: 00 00 00 11ec: eb 49 jmp 1237 <user_thread_2+0xa1> 11ee: 90 nop 11ef: 48 8d 05 4a 0e 00 00 lea 0xe4a(%rip),%rax # 2040 <__FUNCTION__.0> 11f6: 48 89 c6 mov %rax,%rsi 11f9: 48 8d 05 1e 0e 00 00 lea 0xe1e(%rip),%rax # 201e <_IO_stdin_used+0x1e> 1200: 48 89 c7 mov %rax,%rdi 1203: b8 00 00 00 00 mov $0x0,%eax 1208: e8 43 fe ff ff call 1050 <printf@plt> 120d: 8b 05 fd 2d 00 00 mov 0x2dfd(%rip),%eax # 4010 <condition> 1213: 85 c0 test %eax,%eax 1215: 0f 94 c0 sete %al 1218: 0f b6 c0 movzbl %al,%eax 121b: 89 05 ef 2d 00 00 mov %eax,0x2def(%rip) # 4010 <condition> 1221: c7 05 f1 2d 00 00 2f movl $0x2f,0x2df1(%rip) # 401c <__s.1> 1228: 00 00 00 122b: eb 0a jmp 1237 <user_thread_2+0xa1> 122d: c7 05 e5 2d 00 00 00 movl $0x0,0x2de5(%rip) # 401c <__s.1> 1234: 00 00 00 1237: 5d pop %rbp 1238: c3 ret 0000000000001239 <main>: 1239: f3 0f 1e fa endbr64 123d: 55 push %rbp 123e: 48 89 e5 mov %rsp,%rbp 1241: b8 00 00 00 00 mov $0x0,%eax 1246: e8 fe fe ff ff call 1149 <user_thread_1> 124b: b8 00 00 00 00 mov $0x0,%eax 1250: e8 41 ff ff ff call 1196 <user_thread_2> 1255: 90 nop 1256: eb e9 jmp 1241 <main+0x8> .fini 區段的反組譯: 0000000000001258 <_fini>: 1258: f3 0f 1e fa endbr64 125c: 48 83 ec 08 sub $0x8,%rsp 1260: 48 83 c4 08 add $0x8,%rsp 1264: c3 ret ``` ::: <hr/> ![image](https://hackmd.io/_uploads/B14sdjh0kx.png) As shown in the above image, the kernel does the following: 1. Validates the ELF format. 2. Parses the ELF header to determine sections like .text, .data, .bss, etc. 3. Configures the new process’s memory layout (including setting up virtual memory mappings for each section). 4. If the ELF is dynamically linked (which most binaries are), it identifies the interpreter from the ELF header (PT_INTERP segment), typically /lib64/ld-linux-x86-64.so.2. then the dynamic linker -> C runtime(CRT). in the elf header, there is info parsed and used to be loaded into the mem: ```shell $ readelf test -e ``` :::spoiler output ```bash ELF 檔頭: 魔術位元組: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 類別: ELF64 資料: 2 的補數,小尾序(little endian) Version: 1 (current) OS/ABI: UNIX - System V ABI 版本: 0 類型: DYN (Position-Independent Executable file) 系統架構: Advanced Micro Devices X86-64 版本: 0x1 進入點位址: 0x1060 程式標頭起點: 64 (檔案內之位元組) 區段標頭起點: 15424 (檔案內之位元組) 旗標: 0x0 Size of this header: 64 (bytes) Size of program headers: 56 (bytes) Number of program headers: 13 Size of section headers: 64 (bytes) Number of section headers: 37 Section header string table index: 36 區段標頭: [號] 名稱 類型 位址 偏移量 大小 全體大小 旗標 連結 資訊 對齊 [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1] .interp PROGBITS 0000000000000318 00000318 000000000000001c 0000000000000000 A 0 0 1 [ 2] .note.gnu.pr[...] NOTE 0000000000000338 00000338 0000000000000030 0000000000000000 A 0 0 8 [ 3] .note.gnu.bu[...] NOTE 0000000000000368 00000368 0000000000000024 0000000000000000 A 0 0 4 [ 4] .note.ABI-tag NOTE 000000000000038c 0000038c 0000000000000020 0000000000000000 A 0 0 4 [ 5] .gnu.hash GNU_HASH 00000000000003b0 000003b0 0000000000000024 0000000000000000 A 6 0 8 [ 6] .dynsym DYNSYM 00000000000003d8 000003d8 00000000000000a8 0000000000000018 A 7 1 8 [ 7] .dynstr STRTAB 0000000000000480 00000480 000000000000008f 0000000000000000 A 0 0 1 [ 8] .gnu.version VERSYM 0000000000000510 00000510 000000000000000e 0000000000000002 A 6 0 2 [ 9] .gnu.version_r VERNEED 0000000000000520 00000520 0000000000000030 0000000000000000 A 7 1 8 [10] .rela.dyn RELA 0000000000000550 00000550 00000000000000c0 0000000000000018 A 6 0 8 [11] .rela.plt RELA 0000000000000610 00000610 0000000000000018 0000000000000018 AI 6 24 8 [12] .init PROGBITS 0000000000001000 00001000 000000000000001b 0000000000000000 AX 0 0 4 [13] .plt PROGBITS 0000000000001020 00001020 0000000000000020 0000000000000010 AX 0 0 16 [14] .plt.got PROGBITS 0000000000001040 00001040 0000000000000010 0000000000000010 AX 0 0 16 [15] .plt.sec PROGBITS 0000000000001050 00001050 0000000000000010 0000000000000010 AX 0 0 16 [16] .text PROGBITS 0000000000001060 00001060 00000000000001f8 0000000000000000 AX 0 0 16 [17] .fini PROGBITS 0000000000001258 00001258 000000000000000d 0000000000000000 AX 0 0 4 [18] .rodata PROGBITS 0000000000002000 00002000 000000000000004e 0000000000000000 A 0 0 8 [19] .eh_frame_hdr PROGBITS 0000000000002050 00002050 0000000000000044 0000000000000000 A 0 0 4 [20] .eh_frame PROGBITS 0000000000002098 00002098 00000000000000e8 0000000000000000 A 0 0 8 [21] .init_array INIT_ARRAY 0000000000003db8 00002db8 0000000000000008 0000000000000008 WA 0 0 8 [22] .fini_array FINI_ARRAY 0000000000003dc0 00002dc0 0000000000000008 0000000000000008 WA 0 0 8 [23] .dynamic DYNAMIC 0000000000003dc8 00002dc8 00000000000001f0 0000000000000010 WA 7 0 8 [24] .got PROGBITS 0000000000003fb8 00002fb8 0000000000000048 0000000000000008 WA 0 0 8 [25] .data PROGBITS 0000000000004000 00003000 0000000000000014 0000000000000000 WA 0 0 8 [26] .bss NOBITS 0000000000004014 00003014 000000000000000c 0000000000000000 WA 0 0 4 [27] .comment PROGBITS 0000000000000000 00003014 000000000000002b 0000000000000001 MS 0 0 1 [28] .debug_aranges PROGBITS 0000000000000000 0000303f 0000000000000030 0000000000000000 0 0 1 [29] .debug_info PROGBITS 0000000000000000 0000306f 0000000000000162 0000000000000000 0 0 1 [30] .debug_abbrev PROGBITS 0000000000000000 000031d1 00000000000000e5 0000000000000000 0 0 1 [31] .debug_line PROGBITS 0000000000000000 000032b6 000000000000009d 0000000000000000 0 0 1 [32] .debug_str PROGBITS 0000000000000000 00003353 0000000000000113 0000000000000001 MS 0 0 1 [33] .debug_line_str PROGBITS 0000000000000000 00003466 0000000000000036 0000000000000001 MS 0 0 1 [34] .symtab SYMTAB 0000000000000000 000034a0 0000000000000408 0000000000000018 35 25 8 [35] .strtab STRTAB 0000000000000000 000038a8 000000000000022c 0000000000000000 0 0 1 [36] .shstrtab STRTAB 0000000000000000 00003ad4 000000000000016a 0000000000000000 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), D (mbind), l (large), p (processor specific) 程式標頭: 類型 偏移量 虛擬位址 實體位址 檔案大小 記憶大小 旗標 對齊 PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040 0x00000000000002d8 0x00000000000002d8 R 0x8 INTERP 0x0000000000000318 0x0000000000000318 0x0000000000000318 0x000000000000001c 0x000000000000001c R 0x1 [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000628 0x0000000000000628 R 0x1000 LOAD 0x0000000000001000 0x0000000000001000 0x0000000000001000 0x0000000000000265 0x0000000000000265 R E 0x1000 LOAD 0x0000000000002000 0x0000000000002000 0x0000000000002000 0x0000000000000180 0x0000000000000180 R 0x1000 LOAD 0x0000000000002db8 0x0000000000003db8 0x0000000000003db8 0x000000000000025c 0x0000000000000268 RW 0x1000 DYNAMIC 0x0000000000002dc8 0x0000000000003dc8 0x0000000000003dc8 0x00000000000001f0 0x00000000000001f0 RW 0x8 NOTE 0x0000000000000338 0x0000000000000338 0x0000000000000338 0x0000000000000030 0x0000000000000030 R 0x8 NOTE 0x0000000000000368 0x0000000000000368 0x0000000000000368 0x0000000000000044 0x0000000000000044 R 0x4 GNU_PROPERTY 0x0000000000000338 0x0000000000000338 0x0000000000000338 0x0000000000000030 0x0000000000000030 R 0x8 GNU_EH_FRAME 0x0000000000002050 0x0000000000002050 0x0000000000002050 0x0000000000000044 0x0000000000000044 R 0x4 GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 0x0000000000000000 RW 0x10 GNU_RELRO 0x0000000000002db8 0x0000000000003db8 0x0000000000003db8 0x0000000000000248 0x0000000000000248 R 0x1 區段到節區映射中: 節區段… 00 01 .interp 02 .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt 03 .init .plt .plt.got .plt.sec .text .fini 04 .rodata .eh_frame_hdr .eh_frame 05 .init_array .fini_array .dynamic .got .data .bss 06 .dynamic 07 .note.gnu.property 08 .note.gnu.build-id .note.ABI-tag 09 .note.gnu.property 10 .eh_frame_hdr 11 12 .init_array .fini_array .dynamic .got ``` ::: Notly, INTERP is where the dynamic linker performs and be requested. ## Examine with `strace` `stace` 關注於 child process 因此不會記錄 fork 與親代配置 child process 等過程,稍後利用 `bpftrace` 追蹤此類系統呼叫。 ```shell $ stace ls /tmp ``` ```bash= execve("/usr/bin/ls", ["ls", "/tmp/"], 0x7ffd2e161198 /* 49 vars */) = 0 ←- 在 child process 執行 execve 系統呼叫 / 用 $PATH 找到 file system 系統的紀錄 (inode) brk(NULL) = 0x5b2dab683000 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7e58f85c4000 mmap(NULL, 105367, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7e58f85aa000 close(3) = 0 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 ⇒ 所以 /usr/bin/ls 是動態連結的 ELF read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\220\243\2\0\0\0\0\0"..., 832) = 832 pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784 fstat(3, {st_mode=S_IFREG|0755, st_size=2125328, ...}) = 0 pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784 mmap(NULL, 2170256, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7e58f8200000 ⇒ mmap? 為何執行程式時需要配置記憶體空間? stack vs. heap (motivation) ``` 從第六行可以發現 ls 會讀取並配置 `libc.so.6` (動態連結),所以 /usr/bin/ls 是動態連結的 ELF。 若在 gcc 編譯時提供 `--static` 則不會出現該動態連結檔。 ### 為何 stack 空間小於 heap?(motivation) 觀察 PID=1 (init) 的行程的記憶體映射狀況 ```shell $ sudo cat /proc/1/maps ``` ```bash ba55ec796000-ba55ecad7000 rw-p 00000000 00:00 0 [heap] ffffd8184000-ffffd81a5000 rw-p 00000000 00:00 0 [stack] ``` 其中可以發現 `[heap]` 在略高地址,而 `[stack]` 在高地址,且 `[heap]` $\rightarrow$ $ba55ec796000-ba55ecad7000 = (-3,411,968)_{10}$ `[stack]` $\rightarrow$ $ffffd8184000-ffffd81a5000 = (-135,168)_{10}$ `[heap]` 空間較大,而 `[stack]` 較小。 #### 如果 heap 和 stack 在相同記憶體空間? ```bash [---------- /usr/bin/ls —-------] [--- heap + stack —] ELF image 額外 (runtime overhead) ``` :::info function call 過程中需要額外的空間去保存 stack frame malloc / free 過程中需要額外空間 ::: 則當 stack overflow 時,還原時就有可能會釋放到其他空間,甚至沒有其他呼叫可以使用,如輸出,還原等,因為使用呼叫需要 function call。 #### ==為何 stack 空間小於 heap?(motivation)== 為了讓 stack overflow 及早被發現,對於系統設計者,不希望開發者寫出很差的程式,讓 stack overflow 就算發生,早點發生,反之,不知道程式碼怎麼被寫,希望讓開發者有較多空間配置記憶體、從系統要記憶體,設定 stack 是對開發者有限制。就如同 kernel 的 stack 空間很小,其犯錯空間很小,也就是犯錯很容易被發現。 ## Use `bpftrace` to 在 aarch64 上執行 利用 python 觀察 `stace ls` ```python from bcc import BPF # Define the eBPF program bpf_program = """ #include <uapi/linux/ptrace.h> int trace_execve(struct pt_regs *ctx) { bpf_trace_printk("execve called\\n"); return 0; } int trace_mmap(struct pt_regs *ctx) { bpf_trace_printk("mmap called\\n"); return 0; } int trace_fork(struct pt_regs *ctx) { bpf_trace_printk("fork called\\n"); return 0; } """ # Load and attach probes b = BPF(text=bpf_program) b.attach_kprobe(event="__arm64_sys_execve", fn_name="trace_execve") b.attach_kprobe(event="__arm64_sys_mmap", fn_name="trace_mmap") b.attach_kprobe(event="__arm64_sys_fork", fn_name="trace_fork") b.attach_kprobe(event="__arm64_sys_clone", fn_name="trace_fork") print("Tracing... Ctrl-C to end.") try: b.trace_print() except KeyboardInterrupt: pass ``` :::spoiler output ```bash Tracing... Ctrl-C to end. b' bash-1511871 [003] d..21 1295829.603542: bpf_trace_printk: fork called' b'' b' bash-14565 [002] d..21 1295829.604759: bpf_trace_printk: execve called' b'' b' bash-14565 [002] d..21 1295829.606079: bpf_trace_printk: mmap called' b'' b' bash-14565 [002] d..21 1295829.606219: bpf_trace_printk: mmap called' b'' b' bash-14565 [002] d..21 1295829.606329: bpf_trace_printk: mmap called' b'' b' bash-14565 [002] d..21 1295829.606348: bpf_trace_printk: mmap called' b'' b' bash-14565 [002] d..21 1295829.606472: bpf_trace_printk: mmap called' b'' b' bash-14565 [002] d..21 1295829.606526: bpf_trace_printk: mmap called' b'' b' bash-14565 [002] d..21 1295829.609314: bpf_trace_printk: mmap called' b'' b' bash-14565 [002] d..21 1295829.609892: bpf_trace_printk: fork called' b'' b' strace-14565 [002] d..21 1295829.610613: bpf_trace_printk: fork called' b'' b' strace-14565 [002] d..21 1295829.611975: bpf_trace_printk: fork called' b'' b' strace-14568 [000] d..21 1295829.613332: bpf_trace_printk: execve called' b'' b' strace-14568 [000] d..21 1295829.615507: bpf_trace_printk: mmap called' b'' b' strace-14565 [001] d..21 1295829.616501: bpf_trace_printk: mmap called' b'' b' strace-14565 [001] d..21 1295829.616731: bpf_trace_printk: mmap called' b'' b' ls-14568 [000] d..21 1295829.618575: bpf_trace_printk: mmap called' b'' b' ls-14568 [000] d..21 1295829.620229: bpf_trace_printk: mmap called' b'' b' ls-14568 [000] d..21 1295829.620482: bpf_trace_printk: mmap called' b'' b' ls-14568 [000] d..21 1295829.621413: bpf_trace_printk: mmap called' b'' b' ls-14568 [000] d..21 1295829.621697: bpf_trace_printk: mmap called' b'' b' ls-14568 [000] d..21 1295829.622946: bpf_trace_printk: mmap called' b'' b' ls-14568 [000] d..21 1295829.623163: bpf_trace_printk: mmap called' b'' b' ls-14568 [000] d..21 1295829.623869: bpf_trace_printk: mmap called' b'' b' ls-14568 [000] d..21 1295829.624183: bpf_trace_printk: mmap called' b'' b' ls-14568 [000] d..21 1295829.625580: bpf_trace_printk: mmap called' b'' b' ls-14568 [000] d..21 1295829.625852: bpf_trace_printk: mmap called' b'' b' ls-14568 [000] d..21 1295829.626607: bpf_trace_printk: mmap called' b'' b' ls-14568 [000] d..21 1295829.627150: bpf_trace_printk: mmap called' b'' b' ls-14568 [000] d..21 1295829.632824: bpf_trace_printk: mmap called' b'' ``` :::