Open drop-stones opened 4 years ago
int main ()
{
int i, sum, fib, f1, f2;
sum = 0;
for (i = 0; i < 10; i++) {
if (i == 0 || i == 1) {
f1 = f2 = fib = 1;
} else {
sum += i;
fib = f1 + f2;
f1 = f2;
f2 = fib;
}
}
return 0;
}
$ cc -g break.c
$ gdb a.out
...
(gdb) b break.c:13
(gdb) run
Starting program: /home/shizuku/Documents/sysdev/gdb/a.out
Breakpoint 1, main () at break.c:13 13 f2 = fib; (gdb) p i $1 = 2 (gdb) p fib $2 = 2 (gdb) c Continuing.
Breakpoint 1, main () at break.c:13 13 f2 = fib; (gdb) p i $3 = 3 (gdb) p fib $4 = 3 (gdb) c Continuing.
Breakpoint 1, main () at break.c:13 13 f2 = fib; (gdb) p i $5 = 4 (gdb) p fib $6 = 5 ... (gdb) p i $7 = 8 (gdb) p fib $8 = 34
検査対象: 配列外参照
int main ()
{
char arr [5];
for (int i = 0; i < 10; i++)
arr [i] = 'a' + i; // buffer overflow
}
前準備: coreファイルが生成できるように、coreファイルのサイズを無制限に
$ ulimit -c
0
$ ulimit -c unlimited
$ ulimit -c
unlimited
実行するとcoreファイルが生成される
$ cc -g crash.c
$ ./a.out
*** stack smashing detected ***: terminated
Aborted (core dumped)
$ ls
a.out crash.c core
gdbでデバッグすると、SIGABRTによって停止させられたとわかる。
$ gdb a.out core
...
Reading symbols from a.out...
[New LWP 41496]
Core was generated by `./a.out'.
Program terminated with signal SIGABRT, Aborted.
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
50 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) b crash.c:6
(gdb) run
Starting program: /home/shizuku/Documents/sysdev/gdb/a.out
Breakpoint 1, main () at crash.c:6 6 arr [i] = 'a' + i; // buffer overflow (gdb) c ... (gdb) p arr[8] $7 = 105 'i' (gdb) c Continuing. stack smashing detected : terminated
Program received signal SIGABRT, Aborted. __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50 50 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
- objdumpしてみると、スタックオーバーフローを検知するコードが見つかった!!
$ objdump -M intel -d a.out ... 1155: 64 48 8b 04 25 28 00 mov rax,QWORD PTR fs:0x28 115c: 00 00 115e: 48 89 45 f8 mov QWORD PTR [rbp-0x8],rax ... 1191: 64 48 33 0c 25 28 00 xor rcx,QWORD PTR fs:0x28 1198: 00 00 119a: 74 05 je 11a1 <main+0x58> 119c: e8 af fe ff ff call 1050 __stack_chk_fail@plt
#include <stdio.h>
int main() { printf ("debug1\n"); asm("int3"); printf("debug2\n"); printf("debug3\n"); }
- 実行結果
- `Program received signal SIGTRAP, Trace/breakpoint trap.`
- int3命令によるシグナルが捕捉されているのがわかる。
$ clang -g -o int3 int3.c $ gdb ./int3 ... (gdb) b int3.c:7 Breakpoint 1 at 0x40114a: file int3.c, line 7. (gdb) run Starting program: /home/shizuku/Documents/sysdev/gdb/int3 debug1
Program received signal SIGTRAP, Trace/breakpoint trap. main () at int3.c:7 7 printf("debug2\n"); (gdb) c Continuing.
Breakpoint 1, main () at int3.c:7 7 printf("debug2\n"); (gdb) c Continuing. debug2 debug3
- アセンブリコードを覗いてみると、int3命令がある(当然)
$ clang -S -masm=intel int3.c $ cat int3.s ... call printf
int3
#NO_APP
...
$ clang -g -o break break.c
$ gdb ./break
...
(gdb) start
Temporary breakpoint 1 at 0x40111b: file break.c, line 5.
Starting program: /home/shizuku/Documents/sysdev/gdb/break
Temporary breakpoint 1, main () at break.c:5 5 sum = 0; (gdb) watch fib Hardware watchpoint 2: fib (gdb) c Continuing.
Hardware watchpoint 2: fib
Old value = -8048 New value = 1 0x000000000040114e in main () at break.c:8 8 f1 = f2 = fib = 1; (gdb) c Continuing.
Hardware watchpoint 2: fib
Old value = 1 New value = 2 main () at break.c:12 12 f1 = f2; (gdb) c Continuing.
Hardware watchpoint 2: fib
Old value = 2 New value = 3 main () at break.c:12 12 f1 = f2; ... (gdb) c Continuing.
Hardware watchpoint 2: fib
Old value = 8 New value = 13 main () at break.c:12 12 f1 = f2; (gdb) c Continuing.
Hardware watchpoint 2: fib
Old value = 13 New value = 21 main () at break.c:12 12 f1 = f2;
実装途中に致命的なバグが発生しなかった
実装の最新バージョンをgit push
したいのだが、詰まってしまったので次の授業を見てからやる
gdb-pedaというものを友達に教えてもらったので導入してみた。 参考url
info vtbl object
: objectのvtableを確認info symbol address
: addressに何があるか確認
$ gdb ./schedule_fcfs
...
gdb-peda$ b main.cpp:28
Breakpoint 1 at 0x4018c0: file ./schedule_fcfs.hpp, line 21.
gdb-peda$ run
...
gdb-peda$ print fcfs
$1 = {
<cpu> = {
_vptr$cpu = 0x4040a0 <vtable for fcfs_cpu+16>
},
members of fcfs_cpu:
task_list = std::deque with 5 elements = {{
name = <incomplete type>,
tid = 0x0,
priority = 0x4,
burst = 0x5,
wait = 0x0
}, {
name = <incomplete type>,
tid = 0x0,
priority = 0x1,
burst = 0x3,
wait = 0x0
}, {
name = <incomplete type>,
tid = 0x0,
priority = 0x2,
burst = 0x1,
wait = 0x0
}, {
name = <incomplete type>,
tid = 0x0,
priority = 0x2,
burst = 0x7,
wait = 0x0
}, {
name = <incomplete type>,
tid = 0x0,
priority = 0x3,
burst = 0x4,
wait = 0x0
}},
quantum = 0xa,
duration = 0x0,
sum_wait = 0x401250
}
gdb-peda$ info vtbl fcfs
vtable for 'fcfs_cpu' @ 0x4040a0 (subobject @ 0x7fffffffdf28):
[0]: 0x4019a0 <fcfs_cpu::~fcfs_cpu()>
[1]: 0x401a40 <fcfs_cpu::~fcfs_cpu()>
[2]: 0x401860 <fcfs_cpu::insert(task&)>
[3]: 0x4018b0 <fcfs_cpu::run()>
gdb-peda$ info symbol 0x4018b0
fcfs_cpu::run() in section .text of /home/shizuku/Documents/os/scheduling/schedule_fcfs
演習1: 自分のOSSプロダクトをUBサニタイザで検査してみよ
int main (int argc, char *argv []) { if (strcmp (argv [1], "foo")) printf ("foo!\n"); else printf ("Not foo...\n"); }
$ ./a.out UndefinedBehaviorSanitizer:DEADLYSIGNAL ==42316==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x000000000000 (pc 0x7fff6f355850 bp 0x7ffee200c750 sp 0x7ffee200c750 T925157) ==42316==The signal is caused by a READ memory access. ==42316==Hint: address points to the zero page.
0 0x7fff6f355850 in _platform_strcmp+0x50 (libsystem_platform.dylib:x86_64+0x850)
==42316==Register values: rax = 0x0000000000000000 rbx = 0x0000000000000000 rcx = 0x0000000000000000 rdx = 0x00007ffee200c701
rdi = 0x0000000000000000 rsi = 0x000000010dbf6f8d rbp = 0x00007ffee200c750 rsp = 0x00007ffee200c750
r8 = 0x0000000000000001 r9 = 0x0000000000000070 r10 = 0x000000010ffda420 r11 = 0x00007fff6f355800
r12 = 0x0000000000000000 r13 = 0x0000000000000000 r14 = 0x0000000000000000 r15 = 0x0000000000000000
UndefinedBehaviorSanitizer can not provide additional info. SUMMARY: UndefinedBehaviorSanitizer: SEGV (libsystem_platform.dylib:x86_64+0x850) in _platform_strcmp+0x50 ==42316==ABORTING zsh: abort ./a.out
include
include
include
int main (int argc, char *argv []) { if (argc < 2) { fprintf (stderr, "Usage: %s\n", argv [0]);
exit (1);
}
if (strcmp (argv [1], "foo")) printf ("foo!\n"); else printf ("Not foo...\n"); }
$ ./a.out Usage: ./a.out
$ ./a.out aa
foo!
$ clang -fsanitize=undefined -S -masm=intel -o crash_sanitized.s crash.c $ wc -l crash_sanitized.s 235 crash_sanitized.s $ clang -S -masm=intel -o crash.s crash.c $ wc -l crash.s 42 crash.s