From 12601d1facafce315951daa2a74afa533fda6a8c Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Fri, 23 Oct 2026 17:38:06 -0500 Subject: [PATCH] Pin model runtime source imports before ambient hooks --- .../models/runtime_bridge/bootstrap.py | 32 +++++++++++++++++ .../models/runtime_bridge/guard-policy.json | 2 +- .../starpilot/models/runtime_bridge/native.py | 3 +- .../models/runtime_bridge/runtime.py | 2 +- .../models/tests/runtime_bridge_fixtures.py | 2 ++ .../models/tests/test_role_bootstrap.py | 36 +++++++++++++++++++ prebuilt.json | 2 +- 7 files changed, 75 insertions(+), 4 deletions(-) diff --git a/openpilot/starpilot/models/runtime_bridge/bootstrap.py b/openpilot/starpilot/models/runtime_bridge/bootstrap.py index de0a2b2070..7af77677e7 100644 --- a/openpilot/starpilot/models/runtime_bridge/bootstrap.py +++ b/openpilot/starpilot/models/runtime_bridge/bootstrap.py @@ -1,6 +1,7 @@ """Select the integrity-pinned driving and monitoring runtime before imports.""" import hashlib import importlib +import importlib.abc import importlib.machinery import importlib.util import json @@ -90,6 +91,34 @@ def _namespace(name, directory): return importlib.util.module_from_spec(spec) +class _PinnedSourceImports(importlib.abc.MetaPathFinder): + """Resolve only verified source files, before ambient editable/import hooks.""" + + def __init__(self, root): + self.roots = {'tinygrad': root / 'tinygrad', 'examples': root / 'examples', + 'tinygrad_repo': root, 'extra': root / 'extra'} + + def find_spec(self, fullname, path=None, target=None): + family, *parts = fullname.split('.') + if family not in self.roots: + return None + leaf = self.roots[family].joinpath(*parts) + source = leaf / '__init__.py' if (leaf / '__init__.py').is_file() else leaf.with_suffix('.py') + if source.is_file(): + _plain_path(source) + return importlib.util.spec_from_file_location(fullname, source) + if leaf.is_dir(): + _plain_path(leaf) + return _namespace(fullname, leaf).__spec__ + raise ModuleNotFoundError('Module is outside selected runtime source: ' + fullname, name=fullname) + + +def _pin_source_imports(root): + finder = _PinnedSourceImports(root) + sys.meta_path.insert(0, finder) + return finder + + def _check_source_package(name, expected): spec = importlib.util.find_spec(name) if (spec is None or not isinstance(spec.loader, importlib.machinery.SourceFileLoader) or @@ -153,6 +182,7 @@ def activate(bundle, manifest_sha256, compiler_revision, role, cache_root): _private_cache(cache) _private_cache(cache / 'xdg') old_path, old_bytecode, old_cache_prefix = sys.path[:], sys.dont_write_bytecode, sys.pycache_prefix + old_meta_path = sys.meta_path[:] old_env = {key: os.environ.get(key) for key in _ENV_KEYS} try: sys.path[:0] = [str(bundle), str(tg_root)] @@ -164,11 +194,13 @@ def activate(bundle, manifest_sha256, compiler_revision, role, cache_root): # Fixed parent paths prevent namespace merging with the global runtime tree. sys.modules['tinygrad_repo'] = _namespace('tinygrad_repo', tg_root) sys.modules['extra'] = _namespace('extra', tg_root / 'extra') + _pin_source_imports(tg_root) importlib.invalidate_caches() _check_source_package('tinygrad', tg_root / 'tinygrad/__init__.py') _check_source_package('examples', tg_root / 'examples/__init__.py') except BaseException: sys.path[:] = old_path + sys.meta_path[:] = old_meta_path sys.dont_write_bytecode = old_bytecode sys.pycache_prefix = old_cache_prefix for name in ('tinygrad_repo', 'extra'): diff --git a/openpilot/starpilot/models/runtime_bridge/guard-policy.json b/openpilot/starpilot/models/runtime_bridge/guard-policy.json index 821fd52d84..d0f1d1c144 100644 --- a/openpilot/starpilot/models/runtime_bridge/guard-policy.json +++ b/openpilot/starpilot/models/runtime_bridge/guard-policy.json @@ -1 +1 @@ -{"compiler_revision":"9d0446a4ba8a532c8b674fb6ad795af015cd9dcf","files":{"bootstrap.py":"dcb4a3469f4e3cf93b7f2384a47e72a5559ed859d3a94c6f1b78ba72d5efa86c","bounded_wait.c":"a9e1a82e50ebefd983b3dbc6f784adc465cbd06848debed11dfff80cc8a832fe","capture.py":"834cf5d83725729f30aec68a7ba5ca4897701dd4aa34147f0b49d8b0a9b9e81a","libbounded_wait.so":"24ed559861c8636c1026cad9a244854bb2236b5ee8b91bf21c5efbf688fa4a69","libusb_guards.so":"66a3dfe48ac17899862ab80160cf6dac2c9b9707234527ba0d808f3b68404114","qcom.py":"5f35de06bae649342953bfef48c54267f0c7971756537b8758e1d0d2ec6fa7b0","usb.py":"a2e84aa6d6be4cd7b8db7bf9dae85f67a6008de5c6e93ecb288fefede2b46e23","usb_guards.c":"8b3c207de74f92b74980da35428cff6f4a198ce97f9f8b6e64aded74e0110316"},"native_abi":"linux-aarch64-64bit","runtime_manifest_sha256":"20ca9e77010c1ab788f2adb824103db3d595b0da8c4069d6e32b1266f7977b1f"} +{"compiler_revision":"9d0446a4ba8a532c8b674fb6ad795af015cd9dcf","files":{"bootstrap.py":"2efd3aaffb98d30e316fb950dac77b16f0866dfeed1c9767b97dad915e4d0c63","bounded_wait.c":"a9e1a82e50ebefd983b3dbc6f784adc465cbd06848debed11dfff80cc8a832fe","capture.py":"834cf5d83725729f30aec68a7ba5ca4897701dd4aa34147f0b49d8b0a9b9e81a","libbounded_wait.so":"24ed559861c8636c1026cad9a244854bb2236b5ee8b91bf21c5efbf688fa4a69","libusb_guards.so":"66a3dfe48ac17899862ab80160cf6dac2c9b9707234527ba0d808f3b68404114","qcom.py":"5f35de06bae649342953bfef48c54267f0c7971756537b8758e1d0d2ec6fa7b0","usb.py":"a2e84aa6d6be4cd7b8db7bf9dae85f67a6008de5c6e93ecb288fefede2b46e23","usb_guards.c":"8b3c207de74f92b74980da35428cff6f4a198ce97f9f8b6e64aded74e0110316"},"native_abi":"linux-aarch64-64bit","runtime_manifest_sha256":"20ca9e77010c1ab788f2adb824103db3d595b0da8c4069d6e32b1266f7977b1f"} diff --git a/openpilot/starpilot/models/runtime_bridge/native.py b/openpilot/starpilot/models/runtime_bridge/native.py index 39d6102952..8ea101b544 100644 --- a/openpilot/starpilot/models/runtime_bridge/native.py +++ b/openpilot/starpilot/models/runtime_bridge/native.py @@ -14,7 +14,7 @@ from typing import TYPE_CHECKING, Protocol, cast from openpilot.starpilot.models.runtime_selection import NATIVE_REVISION from openpilot.starpilot.models.runtime_bridge.bootstrap import ( - IMPORT_FAMILIES, _check_source_package, _namespace, _private_cache, + IMPORT_FAMILIES, _check_source_package, _namespace, _private_cache, _pin_source_imports, ) if TYPE_CHECKING: @@ -199,6 +199,7 @@ def prepare(role, plan): os.environ.update(CACHEDB=str(cache / 'tinygrad.db'), XDG_CACHE_HOME=str(cache / 'xdg'), PYTHONDONTWRITEBYTECODE='1') sys.modules['tinygrad_repo'] = _namespace('tinygrad_repo', tg_root) sys.modules['extra'] = _namespace('extra', tg_root / 'extra') + _pin_source_imports(tg_root) importlib.invalidate_caches() _check_source_package('tinygrad', tg_root / 'tinygrad/__init__.py') _check_source_package('examples', tg_root / 'examples/__init__.py') diff --git a/openpilot/starpilot/models/runtime_bridge/runtime.py b/openpilot/starpilot/models/runtime_bridge/runtime.py index a1bf2f5db6..ea3bdbe8a5 100644 --- a/openpilot/starpilot/models/runtime_bridge/runtime.py +++ b/openpilot/starpilot/models/runtime_bridge/runtime.py @@ -15,7 +15,7 @@ _GUARD_HASHES = { 'libbounded_wait.so': '24ed559861c8636c1026cad9a244854bb2236b5ee8b91bf21c5efbf688fa4a69', 'libusb_guards.so': '66a3dfe48ac17899862ab80160cf6dac2c9b9707234527ba0d808f3b68404114', } -_POLICY_SHA256 = 'c7eae9e0fab99e8c5fa56854b5a1e1ca8c36c81ef73668dd18ede27de61e3f4b' +_POLICY_SHA256 = 'ff9a762b130207dcf9919714bccd7aabc6d3f6e9d707e0b3a0dbd7fce5858aed' _selection = None _protection = None _plan = None diff --git a/openpilot/starpilot/models/tests/runtime_bridge_fixtures.py b/openpilot/starpilot/models/tests/runtime_bridge_fixtures.py index 08d97b949d..de27059560 100644 --- a/openpilot/starpilot/models/tests/runtime_bridge_fixtures.py +++ b/openpilot/starpilot/models/tests/runtime_bridge_fixtures.py @@ -31,6 +31,7 @@ class ProcessCustody(unittest.TestCase): saved_modules = sys.modules.copy() saved_env = dict(os.environ) saved_path = sys.path[:] + saved_meta_path = sys.meta_path[:] saved_importers = sys.path_importer_cache.copy() saved_bytecode = sys.dont_write_bytecode saved_prefix = sys.pycache_prefix @@ -41,6 +42,7 @@ class ProcessCustody(unittest.TestCase): os.environ.clear() os.environ.update(saved_env) sys.path[:] = saved_path + sys.meta_path[:] = saved_meta_path sys.dont_write_bytecode = saved_bytecode sys.pycache_prefix = saved_prefix importlib.invalidate_caches() diff --git a/openpilot/starpilot/models/tests/test_role_bootstrap.py b/openpilot/starpilot/models/tests/test_role_bootstrap.py index aea4425ed0..0715bb7fdd 100644 --- a/openpilot/starpilot/models/tests/test_role_bootstrap.py +++ b/openpilot/starpilot/models/tests/test_role_bootstrap.py @@ -1,5 +1,7 @@ """Integrity and import isolation of the production role bootstrap.""" import importlib +import importlib.abc +import importlib.util import os import sys import types @@ -148,3 +150,37 @@ class BootstrapTests(BootstrapFixture): if __name__ == '__main__': unittest.main() + + +class SourceHookTests(BootstrapFixture): + def test_selected_source_wins_over_ambient_meta_path_hook(self): + outside = self.base / 'ambient' + (outside / 'tinygrad').mkdir(parents=True) + (outside / 'tinygrad/__init__.py').write_text("raise AssertionError('ambient source executed')") + + class AmbientHook(importlib.abc.MetaPathFinder): + def find_spec(hook, fullname, path=None, target=None): + if fullname == 'tinygrad': + return importlib.util.spec_from_file_location(fullname, outside / 'tinygrad/__init__.py') + return None + + sys.meta_path.insert(0, AmbientHook()) + self.activate() + selected = importlib.import_module('tinygrad') + self.assertEqual(selected.IDENTITY, 'selected legacy') + self.assertEqual(selected.__file__, str(self.bundle / 'tinygrad_repo/tinygrad/__init__.py')) + + def test_selected_children_cannot_fall_back_to_ambient_hook(self): + outside = self.base / 'unowned.py' + outside.write_text("raise AssertionError('unowned child executed')") + + class AmbientHook(importlib.abc.MetaPathFinder): + def find_spec(hook, fullname, path=None, target=None): + if fullname == 'tinygrad.unowned': + return importlib.util.spec_from_file_location(fullname, outside) + return None + + sys.meta_path.insert(0, AmbientHook()) + self.activate(role='monitoring') + with self.assertRaises(ModuleNotFoundError): + importlib.import_module('tinygrad.unowned') diff --git a/prebuilt.json b/prebuilt.json index 558af752bc..311cdfa873 100644 --- a/prebuilt.json +++ b/prebuilt.json @@ -1 +1 @@ -{"protected_inventory_sha256": "f29a00c7be8a21d34adb6a9262fe9786de0f9648a9fa30e91d880b036c77035d", "schema_version": 1} +{"protected_inventory_sha256": "270b5ff419c82d41512039c2b6188e14cb3a3a8115b334effb74d2090ef54cb5", "schema_version": 1}