owned this note
owned this note
Published
Linked with GitHub
# 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/>

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''
```
:::