-
-
Notifications
You must be signed in to change notification settings - Fork 710
/
heap.py
218 lines (184 loc) · 8.98 KB
/
heap.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
"""
Heap commands test module
"""
from tests.utils import (ARCH, GefUnitTestGeneric, _target, findlines,
gdb_run_cmd, gdb_run_silent_cmd, gdb_start_silent_cmd,
is_32b, is_64b)
class HeapCommand(GefUnitTestGeneric):
"""Generic class for command testing, that defines all helpers"""
def setUp(self) -> None:
# ensure those values reflects the allocations in the C source
self.expected_tcache_bin_size = 0x20 if ARCH == "i686" or is_64b() else 0x18
self.expected_small_bin_size = 0x20 if ARCH == "i686" or is_64b() else 0x18
self.expected_large_bin_size = 0x420 if ARCH == "i686" or is_64b() else 0x418
self.expected_unsorted_bin_size = 0x430 if ARCH == "i686" or is_64b() else 0x428
return super().setUp()
def test_cmd_heap_arenas(self):
cmd = "heap arenas"
target = _target("heap")
self.assertFailIfInactiveSession(gdb_run_cmd(cmd, target=target))
res = gdb_start_silent_cmd(cmd, target=target)
self.assertNoException(res)
self.assertIn("Arena(base=", res)
def test_cmd_heap_set_arena(self):
cmd = "heap set-arena &main_arena"
target = _target("heap")
self.assertFailIfInactiveSession(gdb_run_cmd(cmd, target=target))
res = gdb_run_silent_cmd(cmd, target=target, after=["heap arenas"])
self.assertNoException(res)
self.assertIn("Arena(base=", res)
def test_cmd_heap_chunk_no_arg(self):
cmd = "heap chunk p1"
target = _target("heap")
self.assertFailIfInactiveSession(gdb_run_cmd(cmd, target=target))
res = gdb_run_silent_cmd(cmd, target=target)
self.assertNoException(res)
self.assertIn("PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA", res)
def test_cmd_heap_chunk_with_number(self):
target = _target("heap")
cmd = "heap chunk --number 2 p1"
self.assertFailIfInactiveSession(gdb_run_cmd(cmd, target=target))
res = gdb_run_silent_cmd(cmd, target=target)
self.assertNoException(res)
chunklines = findlines("Chunk(addr=", res)
self.assertEqual(len(chunklines), 2)
def test_cmd_heap_chunks(self):
cmd = "heap chunks"
target = _target("heap")
self.assertFailIfInactiveSession(gdb_run_cmd(cmd, target=target))
res = gdb_run_silent_cmd(cmd, target=target)
self.assertNoException(res)
self.assertIn("Chunk(addr=", res)
self.assertIn("top chunk", res)
cmd = "heap chunks"
target = _target("heap-non-main")
res = gdb_run_silent_cmd(cmd, target=target)
self.assertNoException(res)
self.assertIn("Chunk(addr=", res)
self.assertIn("top chunk", res)
chunks = [line for line in res.splitlines() if "Chunk(addr=" in line]
cmd = "python gdb.execute(f'heap chunks {int(list(gef.heap.arenas)[1]):#x}')"
target = _target("heap-non-main")
res = gdb_run_silent_cmd(cmd, target=target)
self.assertNoException(res)
self.assertNotIn("using '&main_arena' instead", res)
self.assertIn("Chunk(addr=", res)
self.assertIn("top chunk", res)
non_main_chunks = [line for line in res.splitlines() if "Chunk(addr=" in line]
# make sure that the chunks of each arena are distinct
self.assertNotEqual(chunks, non_main_chunks)
def test_cmd_heap_chunks_mult_heaps(self):
py_cmd = 'gdb.execute(f"heap set-arena {int(list(gef.heap.arenas)[1]):#x}")'
before = ['run', 'python ' + py_cmd]
cmd = "heap chunks"
target = _target("heap-multiple-heaps")
res = gdb_run_silent_cmd(cmd, before=before, target=target)
self.assertNoException(res)
self.assertIn("Chunk(addr=", res)
self.assertIn("top chunk", res)
def test_cmd_heap_chunks_summary(self):
cmd = "heap chunks --summary"
target = _target("heap")
self.assertFailIfInactiveSession(gdb_run_cmd(cmd, target=target))
res = gdb_run_silent_cmd(cmd, target=target)
self.assertNoException(res)
self.assertIn("== Chunk distribution by size", res)
self.assertIn("== Chunk distribution by flag", res)
def test_cmd_heap_chunks_min_size_filter(self):
cmd = "heap chunks --min-size 16"
target = _target("heap")
self.assertFailIfInactiveSession(gdb_run_cmd(cmd, target=target))
res = gdb_run_silent_cmd(cmd, target=target)
self.assertNoException(res)
self.assertIn("Chunk(addr=", res)
cmd = "heap chunks --min-size 1048576"
target = _target("heap")
self.assertFailIfInactiveSession(gdb_run_cmd(cmd, target=target))
res = gdb_run_silent_cmd(cmd, target=target)
self.assertNoException(res)
self.assertNotIn("Chunk(addr=", res)
def test_cmd_heap_chunks_max_size_filter(self):
cmd = "heap chunks --max-size 160"
target = _target("heap")
self.assertFailIfInactiveSession(gdb_run_cmd(cmd, target=target))
res = gdb_run_silent_cmd(cmd, target=target)
self.assertNoException(res)
self.assertIn("Chunk(addr=", res)
cmd = "heap chunks --max-size 16"
target = _target("heap")
self.assertFailIfInactiveSession(gdb_run_cmd(cmd, target=target))
res = gdb_run_silent_cmd(cmd, target=target)
self.assertNoException(res)
self.assertNotIn("Chunk(addr=", res)
def test_cmd_heap_bins_fast(self):
cmd = "heap bins fast"
before = ["set environment GLIBC_TUNABLES glibc.malloc.tcache_count=0"]
target = _target("heap-fastbins")
self.assertFailIfInactiveSession(gdb_run_cmd(cmd, before=before, target=target))
res = gdb_run_silent_cmd(cmd, before=before, target=target)
self.assertNoException(res)
# ensure fastbins is populated
self.assertIn("Fastbins[idx=0, size=", res)
self.assertIn("Chunk(addr=", res)
def test_cmd_heap_bins_large(self):
cmd = "heap bins large"
target = _target("heap-bins")
res = gdb_run_silent_cmd(cmd, target=target)
self.assertNoException(res)
self.assertIn("Found 1 chunks in 1 large non-empty bins", res)
self.assertIn("Chunk(addr=", res)
self.assertIn(f"size={self.expected_large_bin_size:#x}", res)
def test_cmd_heap_bins_non_main(self):
cmd = "python gdb.execute(f'heap bins fast {gef.heap.main_arena.next:#x}')"
before = ["set environment GLIBC_TUNABLES glibc.malloc.tcache_count=0"]
target = _target("heap-non-main")
res = gdb_run_silent_cmd(cmd, before=before, target=target)
self.assertNoException(res)
self.assertIn("size=0x20", res)
def test_cmd_heap_bins_small(self):
cmd = "heap bins small"
before = ["set environment GLIBC_TUNABLES glibc.malloc.tcache_count=0"]
target = _target("heap-bins")
res = gdb_run_silent_cmd(cmd, before=before, target=target)
self.assertNoException(res)
self.assertIn("Found 1 chunks in 1 small non-empty bins", res)
self.assertIn("Chunk(addr=", res)
self.assertIn(f"size={self.expected_small_bin_size:#x}", res)
def test_cmd_heap_bins_tcache(self):
cmd = "heap bins tcache"
target = _target("heap-non-main")
res = gdb_run_silent_cmd(cmd, target=target)
self.assertNoException(res)
tcachelines = findlines("Tcachebins[idx=", res)
self.assertEqual(len(tcachelines), 1)
if ARCH in ("i686",):
self.assertIn("Tcachebins[idx=1, size=0x20, count=1]", tcachelines[0])
elif is_32b():
self.assertIn("Tcachebins[idx=2, size=0x20, count=1]", tcachelines[0])
else:
self.assertIn("Tcachebins[idx=0, size=0x20, count=1]", tcachelines[0])
def test_cmd_heap_bins_tcache_all(self):
cmd = "heap bins tcache all"
target = _target("heap-tcache")
res = gdb_run_silent_cmd(cmd, target=target)
self.assertNoException(res)
# ensure there's 2 tcachebins
tcachelines = findlines("Tcachebins[idx=", res)
self.assertEqual(len(tcachelines), 2)
if ARCH in ("i686",):
self.assertIn("Tcachebins[idx=1, size=0x20, count=3]", tcachelines[0])
self.assertIn("Tcachebins[idx=2, size=0x30, count=3]", tcachelines[1])
elif is_32b():
self.assertIn("Tcachebins[idx=1, size=0x18, count=3]", tcachelines[0])
self.assertIn("Tcachebins[idx=4, size=0x30, count=3]", tcachelines[1])
else:
self.assertIn("Tcachebins[idx=0, size=0x20, count=3]", tcachelines[0])
self.assertIn("Tcachebins[idx=1, size=0x30, count=3]", tcachelines[1])
def test_cmd_heap_bins_unsorted(self):
cmd = "heap bins unsorted"
target = _target("heap-bins")
res = gdb_run_silent_cmd(cmd, target=target)
self.assertNoException(res)
self.assertIn("Found 1 chunks in unsorted bin", res)
self.assertIn("Chunk(addr=", res)
self.assertIn(f"size={self.expected_unsorted_bin_size:#x}", res)