Skip to content

Commit 9b0ca19

Browse files
authored
Merge pull request #1671 from volatilityfoundation/fix_tracing_plugins
Fix several bugs found in the tracing plugins during mass testing
2 parents e935254 + 14778cd commit 9b0ca19

File tree

2 files changed

+35
-22
lines changed

2 files changed

+35
-22
lines changed

volatility3/framework/plugins/linux/tracing/ftrace.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# Public researches: https://i.blackhat.com/USA21/Wednesday-Handouts/us-21-Fixing-A-Memory-Forensics-Blind-Spot-Linux-Kernel-Tracing-wp.pdf
66

77
import logging
8-
from typing import Dict, List, Iterable, Optional
8+
from typing import Dict, List, Generator
99
from enum import Enum
1010
from dataclasses import dataclass
1111

@@ -67,7 +67,7 @@ class CheckFtrace(interfaces.plugins.PluginInterface):
6767
Investigate the ftrace infrastructure to uncover kernel attached callbacks, which can be leveraged
6868
to hook kernel functions and modify their behaviour."""
6969

70-
_version = (1, 0, 0)
70+
_version = (2, 0, 0)
7171
_required_framework_version = (2, 19, 0)
7272

7373
@classmethod
@@ -103,32 +103,35 @@ def get_requirements(cls) -> List[interfaces.configuration.RequirementInterface]
103103
def extract_hash_table_filters(
104104
cls,
105105
ftrace_ops: interfaces.objects.ObjectInterface,
106-
) -> Optional[Iterable[interfaces.objects.ObjectInterface]]:
106+
) -> Generator[interfaces.objects.ObjectInterface, None, None]:
107107
"""Wrap the process of walking to every ftrace_func_entry of an ftrace_ops.
108108
Those are stored in a hash table of filters that indicates the addresses hooked.
109109
110110
Args:
111111
ftrace_ops: The ftrace_ops struct to walk through
112112
113-
Returns:
113+
Return, None, None:
114114
An iterable of ftrace_func_entry structs
115115
"""
116116

117+
if hasattr(ftrace_ops, "func_hash"):
118+
ftrace_hash = ftrace_ops.func_hash.filter_hash
119+
else:
120+
ftrace_hash = ftrace_ops.filter_hash
121+
117122
try:
118-
current_bucket_ptr = ftrace_ops.func_hash.filter_hash.buckets.first
123+
current_bucket_ptr = ftrace_hash.buckets.first
119124
except exceptions.InvalidAddressException:
120125
vollog.log(
121126
constants.LOGLEVEL_VV,
122127
f"ftrace_func_entry list of ftrace_ops@{ftrace_ops.vol.offset:#x} is empty/invalid. Skipping it...",
123128
)
124-
return []
129+
return
125130

126131
while current_bucket_ptr.is_readable():
127132
yield current_bucket_ptr.dereference().cast("ftrace_func_entry")
128133
current_bucket_ptr = current_bucket_ptr.next
129134

130-
return None
131-
132135
@classmethod
133136
def parse_ftrace_ops(
134137
cls,
@@ -137,7 +140,7 @@ def parse_ftrace_ops(
137140
known_modules: Dict[str, List[extensions.module]],
138141
ftrace_ops: interfaces.objects.ObjectInterface,
139142
run_hidden_modules: bool = True,
140-
) -> Optional[Iterable[ParsedFtraceOps]]:
143+
) -> Generator[ParsedFtraceOps, None, None]:
141144
"""Parse an ftrace_ops struct to highlight ftrace kernel hooking.
142145
Iterates over embedded ftrace_func_entry entries, which point to hooked memory areas.
143146
@@ -234,12 +237,10 @@ def parse_ftrace_ops(
234237
formatted_ftrace_flags,
235238
)
236239

237-
return None
238-
239240
@classmethod
240241
def iterate_ftrace_ops_list(
241242
cls, context: interfaces.context.ContextInterface, kernel_name: str
242-
) -> Optional[Iterable[interfaces.objects.ObjectInterface]]:
243+
) -> Generator[interfaces.objects.ObjectInterface, None, None]:
243244
"""Iterate over (ftrace_ops *)ftrace_ops_list.
244245
245246
Returns:

volatility3/framework/plugins/linux/tracing/tracepoints.py

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -116,18 +116,25 @@ def parse_tracepoint(
116116
known_modules: A dict of known modules, used to locate callbacks origin. Typically obtained through modxview.run_modules_scanners().
117117
tracepoint: The tracepoint struct to parse
118118
run_hidden_modules: Whether to run the hidden_modules plugin or not. Note: it won't be run, even if specified, \
119-
if the "hidden_modules" key is present in known_modules.
119+
if the "hidden_modules" key is present in known_modules.
120120
121121
Yields:
122122
An iterable of ParsedTracepointFunc dataclasses, containing a selection of useful fields related to a tracepoint struct
123123
"""
124-
125124
kernel = context.modules[kernel_name]
126125
kernel_layer = context.layers[kernel.layer_name]
127126

128127
for tracepoint_func in cls.iterate_tracepoint_funcs(
129128
context, kernel_layer.name, tracepoint
130129
):
130+
try:
131+
tracepoint_name = utility.pointer_to_string(tracepoint.name, count=512)
132+
except exceptions.InvalidAddressException:
133+
vollog.debug(
134+
f"Tracepoint function at {tracepoint.vol.offset:#x} is smeared."
135+
)
136+
continue
137+
131138
probe_handler_address = tracepoint_func.func
132139
probe_handler_symbol = module_address = module_name = None
133140

@@ -183,16 +190,21 @@ def parse_tracepoint(
183190
probe_handler_address
184191
)
185192
else:
186-
vollog.warning(
193+
vollog.debug(
187194
f"Could not determine tracepoint@{tracepoint.vol.offset:#x} probe handler {probe_handler_address:#x} module origin.",
188195
)
189196

197+
if hasattr(tracepoint_func, "prio"):
198+
prio = tracepoint_func.prio
199+
else:
200+
prio = None
201+
190202
yield ParsedTracepointFunc(
191-
utility.pointer_to_string(tracepoint.name, count=512),
203+
tracepoint_name,
192204
tracepoint.vol.offset,
193205
probe_handler_symbol,
194206
probe_handler_address,
195-
tracepoint_func.prio,
207+
prio,
196208
module_name,
197209
module_address,
198210
)
@@ -258,11 +270,11 @@ def _generator(self):
258270
kernel_layer = self.context.layers[kernel.layer_name]
259271

260272
if not kernel.has_symbol("__start___tracepoints_ptrs"):
261-
raise exceptions.SymbolError(
262-
"__start___tracepoints_ptrs",
263-
self.vmlinux.symbol_table_name,
264-
'The provided symbol table does not include the "__start___tracepoints_ptrs" symbol. This means you are either analyzing an unsupported kernel version or that your symbol table is corrupted.',
273+
vollog.error(
274+
'The provided symbol table does not include the "__start___tracepoints_ptrs" symbol.'
275+
"This means you are either analyzing an unsupported kernel version or that your symbol table is corrupted."
265276
)
277+
return
266278

267279
known_modules = modxview.Modxview.run_modules_scanners(
268280
self.context, kernel_name, run_hidden_modules=False
@@ -281,7 +293,7 @@ def _generator(self):
281293
format_hints.Hex(tracepoint_parsed.tracepoint_address),
282294
tracepoint_parsed.probe_name or NotAvailableValue(),
283295
format_hints.Hex(tracepoint_parsed.probe_address),
284-
tracepoint_parsed.probe_priority,
296+
tracepoint_parsed.probe_priority or NotAvailableValue(),
285297
tracepoint_parsed.module_name or NotAvailableValue(),
286298
(
287299
format_hints.Hex(tracepoint_parsed.module_address)

0 commit comments

Comments
 (0)