55# Public researches: https://i.blackhat.com/USA21/Wednesday-Handouts/us-21-Fixing-A-Memory-Forensics-Blind-Spot-Linux-Kernel-Tracing-wp.pdf
66
77import logging
8- from typing import Dict , List , Iterable , Optional
8+ from typing import Dict , List , Generator
99from enum import Enum
1010from 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:
0 commit comments