-
Notifications
You must be signed in to change notification settings - Fork 0
/
mrs_ext.py
129 lines (97 loc) · 4.67 KB
/
mrs_ext.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
@register
class MrsCommand(GenericCommand):
"""Base command to get information about heap caprevocation state."""
_cmdline_ = "mrs"
_syntax_ = f"{_cmdline_} (info|chunk|quarantine)"
def __init__(self) -> None:
super().__init__(prefix=True)
return
@only_if_gdb_running
def do_invoke(self, _: List[str]) -> None:
self.usage()
return
@register
class MrsInfoCommand(GenericCommand):
"""Display information about the mrs quarantine, global state and
the revocation bitmap."""
_cmdline_ = "mrs info"
_syntax_ = f"{_cmdline_} [-h] [all] [thread_ids...]"
def __init__(self) -> None:
super().__init__(complete=gdb.COMPLETE_NONE)
return
@only_if_gdb_running
def do_invoke(self, argv: List[str], **kwargs: Any) -> None:
current_thread = gdb.selected_thread()
if current_thread is None:
err("Couldn't find current thread")
return
# As a nicety, we want to display threads in ascending order by gdb number
threads = sorted(gdb.selected_inferior().threads(), key=lambda t: t.num)
if argv:
if "all" in argv:
tids = [t.num for t in threads]
else:
tids = self.check_thread_ids([int(a) for a in argv])
else:
tids = [current_thread.num]
# loop through all selected threads (default current thread)
for thread in threads:
if thread.num not in tids:
continue
thread.switch()
gef_print(titlify(f"Thread {thread.num:d}"))
gef_print(f"Allocated size: {gef.heap_caprevoke.allocated_size:#x}")
gef_print(f"Max allocated size: {gef.heap_caprevoke.max_allocated_size:#x}")
gef_print(f"Quarantine size: {gef.heap_caprevoke.quarantine_size:#x}")
gef_print(f"Quarantine max size: {gef.heap_caprevoke.quarantine_max_size:#x}")
entire_revocation_bitmap = gef.heap_caprevoke.entire_shadow
gef_print(f"Entire revocation map capability: {str(entire_revocation_bitmap)}")
# XXXR3: epochs? cheri_revoke_info?
current_thread.switch()
@register
class MrsQuarantineCommand(GenericCommand):
"""Display information about the mrs quarantine, global state and
the revocation bitmap."""
_cmdline_ = "mrs quarantine"
_syntax_ = f"{_cmdline_} [-h]"
def __init__(self) -> None:
super().__init__(complete=gdb.COMPLETE_NONE)
return
@only_if_gdb_running
def do_invoke(self, argv: List[str], **kwargs: Any) -> None:
# display quarantined chunks as capabilities as they are stored
quarantined_chunks = gef.heap_caprevoke.chunks
chunk_sizes = gef.heap_caprevoke.chunk_sizes
gef_print(f"application_quarantine[size={gef.heap_caprevoke.quarantine_size:#x}, count={len(quarantined_chunks)}] ")
for chunk, chunk_size in zip(quarantined_chunks, chunk_sizes):
gef_print(f" {RIGHT_ARROW} {Color.colorify('Chunk', 'yellow bold underline')}(addr={chunk:#x}, size={chunk_size:#x})")
@register
class MrsChunkCommand(GenericCommand):
"""Display information about the mrs quarantine, global state and
the revocation bitmap."""
_cmdline_ = "mrs chunk"
_syntax_ = f"{_cmdline_} [-h] address"
def __init__(self) -> None:
super().__init__(complete=gdb.COMPLETE_NONE)
return
@parse_arguments({"address": ""}, {})
@only_if_gdb_running
def do_invoke(self, _: List[str], **kwargs: Any) -> None:
args = kwargs["arguments"]
if not args.address:
err("Missing heap address")
self.usage()
return
addr = parse_address(args.address)
# XXXR3: use this command with the underlying allocation address or this breaks.
# But this is allocator specific... So query jemalloc heap manager or snmalloc heap
# manager first.
revocation_bit_addr = gef.heap_caprevoke.get_shadow_bit_addr(addr)
revocation_bit = gef.heap_caprevoke.get_shadow_bit(addr)
revocation_status = Color.colorify('Yes', 'green') if revocation_bit == 1 else Color.colorify('No', 'red')
quarantined_chunks = gef.heap_caprevoke.chunks
quarantine_status = Color.colorify('Yes', 'green') if addr in quarantined_chunks else Color.colorify('No', 'red')
gef_print(f"{Color.colorify('Chunk', 'yellow bold underline')}(addr={addr:#x})")
gef_print(f"In quarantine: {quarantine_status}") # quarantined chunk is the underlying allocation
gef_print(f"Revocation bit address: {revocation_bit_addr:#x}")
gef_print(f"Revocation bit set (first word): {revocation_status}")