Skip to content

Commit ce01e65

Browse files
committed
Patch related to #6124
1 parent 7eb06ce commit ce01e65

3 files changed

Lines changed: 47 additions & 1 deletion

File tree

lib/core/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from thirdparty import six
2121

2222
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
23-
VERSION = "1.10.9.14"
23+
VERSION = "1.10.9.15"
2424
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
2525
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
2626
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)

sqlmap.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,19 @@
1212

1313
sys.dont_write_bytecode = True
1414

15+
# Reference: https://github.com/python/cpython/issues/156319 - CPython's tier-2 optimizer can
16+
# corrupt frame locals (raising exceptions the executed code cannot produce) whenever an active
17+
# sys.monitoring tool (an attached debugger/profiler/coverage run) coincides with enough hot
18+
# code. sqlmap never needs one attached during a scan, so silence any already-registered tool
19+
# up front, before any hot code runs (name stays registered so the owning tool can still free it)
20+
if hasattr(sys, "monitoring"):
21+
for _ in range(6): # valid tool id range (Reference: https://docs.python.org/3/library/sys.monitoring.html)
22+
try:
23+
if sys.monitoring.get_tool(_) is not None:
24+
sys.monitoring.set_events(_, sys.monitoring.events.NO_EVENTS)
25+
except Exception:
26+
pass
27+
1528
try:
1629
__import__("lib.utils.versioncheck") # this has to be the first non-standard import
1730
except ImportError:

tests/test_jit_guard.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,5 +81,38 @@ def test_normal_path_is_untouched_without_jit(self):
8181
self.assertIn(PROMPT, out)
8282

8383

84+
# Tool id 3 is unused by CPython's own well-known ids (DEBUGGER=0, COVERAGE=1, PROFILER=2, OPTIMIZER=5)
85+
_TEST_TOOL_ID = 3
86+
87+
_MONITORING_DRIVER = """
88+
import sys
89+
sys.path.insert(0, %r)
90+
sys.monitoring.use_tool_id(%d, "test-tool")
91+
sys.monitoring.set_events(%d, sys.monitoring.events.PY_START)
92+
import sqlmap
93+
print(sys.monitoring.get_tool(%d))
94+
print(sys.monitoring.get_events(%d))
95+
""" % (ROOT, _TEST_TOOL_ID, _TEST_TOOL_ID, _TEST_TOOL_ID, _TEST_TOOL_ID)
96+
97+
98+
class TestMonitoringGuard(unittest.TestCase):
99+
"""
100+
The other half of the cpython#156319 mitigation: the tier-2 corruption needs BOTH the JIT and
101+
an active sys.monitoring tool (debugger/profiler/coverage) at once. sqlmap has no legitimate
102+
reason to run a scan with one attached, so it silences any already-registered tool's events as
103+
the very first thing at import time (Reference: 'https://github.com/python/cpython/issues/156319').
104+
"""
105+
106+
def test_active_tool_is_silenced_but_not_unregistered(self):
107+
if not hasattr(sys, "monitoring"):
108+
self.skipTest("interpreter has no sys.monitoring (needs 3.12+)")
109+
110+
out = subprocess.check_output([sys.executable, "-c", _MONITORING_DRIVER], cwd=ROOT)
111+
tool, events = out.decode("utf-8").strip().splitlines()
112+
113+
self.assertEqual(tool, "test-tool") # still registered - its own owner can still free it
114+
self.assertEqual(events, "0") # events cleared to NO_EVENTS, so nothing fires
115+
116+
84117
if __name__ == "__main__":
85118
unittest.main()

0 commit comments

Comments
 (0)