Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions kernelguard.py
Original file line number Diff line number Diff line change
Expand Up @@ -2202,6 +2202,35 @@ def _has_ver(expr: ast.AST | None) -> bool:
continue
if not is_entrypoint_name(node.name):
continue
params = {arg.arg for arg in node.args.args}

guarded_input_state: set[str] = set()
for child in ast.walk(node):
if not isinstance(child, ast.If):
continue
test_roots = _expr_names(child.test)
assigned_from_input = {
_ast_root_name(target)
for stmt in child.body
if isinstance(stmt, ast.Assign) and (_expr_names(stmt.value) & params)
for target in stmt.targets
} - {None}
guarded_input_state.update(test_roots & assigned_from_input)

if len(guarded_input_state) >= 2:
for stmt in node.body:
if not isinstance(stmt, ast.Return) or stmt.value is None:
continue
returned_state = _expr_names(stmt.value) & guarded_input_state
if len(returned_state) >= 2:
return [{
"pattern": "LAST_CALL_REPLAY",
"severity": "critical",
"evidence": (
f"{entrypoint_name} combines multiple first-call "
"state slots initialized from live input"
),
}]

signature_features: dict[str, set[str]] = defaultdict(set)
saved_state_features: dict[str, set[str]] = defaultdict(set)
Expand Down