https://github.com/python/cpython/commit/0370cb42daa3035280ec5c6ef4967366314824f5
commit: 0370cb42daa3035280ec5c6ef4967366314824f5
branch: 3.14
author: Miss Islington (bot) <31488909+miss-isling...@users.noreply.github.com>
committer: zooba <steve.do...@microsoft.com>
date: 2025-06-19T20:51:06Z
summary:

gh-135543: Emit sys.remote_exec audit event when sys.remote_exec is called 
(GH-135544)

(cherry picked from commit 1ddfe593200fec992d283a9b4d6ad2f1b535c018)

Co-authored-by: Nadeshiko Manju <m...@manjusaka.me>

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst
M Doc/library/sys.rst
M Lib/test/audit-tests.py
M Lib/test/support/__init__.py
M Lib/test/test_audit.py
M Lib/test/test_sys.py
M Python/ceval_gil.c
M Python/sysmodule.c

diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst
index 71f9999464ab52..f8f727f4a23410 100644
--- a/Doc/library/sys.rst
+++ b/Doc/library/sys.rst
@@ -1933,12 +1933,21 @@ always available. Unless explicitly noted otherwise, 
all variables are read-only
    interpreter is pre-release (alpha, beta, or release candidate) then the
    local and remote interpreters must be the same exact version.
 
-   .. audit-event:: remote_debugger_script script_path
+   .. audit-event:: sys.remote_exec pid script_path
+
+      When the code is executed in the remote process, an
+      :ref:`auditing event <auditing>` ``sys.remote_exec`` is raised with
+      the *pid* and the path to the script file.
+      This event is raised in the process that called :func:`sys.remote_exec`.
+
+   .. audit-event:: cpython.remote_debugger_script script_path
 
       When the script is executed in the remote process, an
       :ref:`auditing event <auditing>`
-      ``sys.remote_debugger_script`` is raised
+      ``cpython.remote_debugger_script`` is raised
       with the path in the remote process.
+      This event is raised in the remote process, not the one
+      that called :func:`sys.remote_exec`.
 
    .. availability:: Unix, Windows.
    .. versionadded:: 3.14
diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py
index 08b638e4b8d524..6884ac0dbe6ff0 100644
--- a/Lib/test/audit-tests.py
+++ b/Lib/test/audit-tests.py
@@ -643,6 +643,34 @@ def test_assert_unicode():
     else:
         raise RuntimeError("Expected sys.audit(9) to fail.")
 
+def test_sys_remote_exec():
+    import tempfile
+
+    pid = os.getpid()
+    event_pid = -1
+    event_script_path = ""
+    remote_event_script_path = ""
+    def hook(event, args):
+        if event not in ["sys.remote_exec", "cpython.remote_debugger_script"]:
+            return
+        print(event, args)
+        match event:
+            case "sys.remote_exec":
+                nonlocal event_pid, event_script_path
+                event_pid = args[0]
+                event_script_path = args[1]
+            case "cpython.remote_debugger_script":
+                nonlocal remote_event_script_path
+                remote_event_script_path = args[0]
+
+    sys.addaudithook(hook)
+    with tempfile.NamedTemporaryFile(mode='w+', delete=True) as tmp_file:
+        tmp_file.write("a = 1+1\n")
+        tmp_file.flush()
+        sys.remote_exec(pid, tmp_file.name)
+        assertEqual(event_pid, pid)
+        assertEqual(event_script_path, tmp_file.name)
+        assertEqual(remote_event_script_path, tmp_file.name)
 
 if __name__ == "__main__":
     from test.support import suppress_msvcrt_asserts
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 7ac95f078095cd..8afc9c28182ba5 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -46,6 +46,7 @@
     # sys
     "MS_WINDOWS", "is_jython", "is_android", "is_emscripten", "is_wasi",
     "is_apple_mobile", "check_impl_detail", "unix_shell", "setswitchinterval",
+    "support_remote_exec_only",
     # os
     "get_pagesize",
     # network
@@ -3070,6 +3071,27 @@ def is_libssl_fips_mode():
         return False  # more of a maybe, unless we add this to the _ssl module.
     return get_fips_mode() != 0
 
+def _supports_remote_attaching():
+    PROCESS_VM_READV_SUPPORTED = False
+
+    try:
+        from _remote_debugging import PROCESS_VM_READV_SUPPORTED
+    except ImportError:
+        pass
+
+    return PROCESS_VM_READV_SUPPORTED
+
+def _support_remote_exec_only_impl():
+    if not sys.is_remote_debug_enabled():
+        return unittest.skip("Remote debugging is not enabled")
+    if sys.platform not in ("darwin", "linux", "win32"):
+        return unittest.skip("Test only runs on Linux, Windows and macOS")
+    if sys.platform == "linux" and not _supports_remote_attaching():
+        return unittest.skip("Test only runs on Linux with process_vm_readv 
support")
+    return _id
+
+def support_remote_exec_only(test):
+    return _support_remote_exec_only_impl()(test)
 
 class EqualToForwardRef:
     """Helper to ease use of annotationlib.ForwardRef in tests.
diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py
index 5f9eb381f605d9..077765fcda210a 100644
--- a/Lib/test/test_audit.py
+++ b/Lib/test/test_audit.py
@@ -322,6 +322,14 @@ def test_assert_unicode(self):
         if returncode:
             self.fail(stderr)
 
+    @support.support_remote_exec_only
+    @support.cpython_only
+    def test_sys_remote_exec(self):
+        returncode, events, stderr = self.run_python("test_sys_remote_exec")
+        self.assertTrue(any(["sys.remote_exec" in event for event in events]))
+        self.assertTrue(any(["cpython.remote_debugger_script" in event for 
event in events]))
+        if returncode:
+            self.fail(stderr)
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index 94004b4d45cb78..577a075a1aaa1b 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -1942,22 +1942,7 @@ def write(self, s):
         self.assertEqual(out, b"")
         self.assertEqual(err, b"")
 
-
-def _supports_remote_attaching():
-    PROCESS_VM_READV_SUPPORTED = False
-
-    try:
-        from _remote_debugging import PROCESS_VM_READV_SUPPORTED
-    except ImportError:
-        pass
-
-    return PROCESS_VM_READV_SUPPORTED
-
-@unittest.skipIf(not sys.is_remote_debug_enabled(), "Remote debugging is not 
enabled")
-@unittest.skipIf(sys.platform != "darwin" and sys.platform != "linux" and 
sys.platform != "win32",
-                    "Test only runs on Linux, Windows and MacOS")
-@unittest.skipIf(sys.platform == "linux" and not _supports_remote_attaching(),
-                    "Test only runs on Linux with process_vm_readv support")
+@test.support.support_remote_exec_only
 @test.support.cpython_only
 class TestRemoteExec(unittest.TestCase):
     def tearDown(self):
@@ -2116,7 +2101,7 @@ def audit_hook(event, arg):
         returncode, stdout, stderr = self._run_remote_exec_test(script, 
prologue=prologue)
         self.assertEqual(returncode, 0)
         self.assertIn(b"Remote script executed successfully!", stdout)
-        self.assertIn(b"Audit event: remote_debugger_script, arg: ", stdout)
+        self.assertIn(b"Audit event: cpython.remote_debugger_script, arg: ", 
stdout)
         self.assertEqual(stderr, b"")
 
     def test_remote_exec_with_exception(self):
diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst
new file mode 100644
index 00000000000000..6efe2a47bac5d4
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst
@@ -0,0 +1,2 @@
+Emit ``sys.remote_exec`` audit event when :func:`sys.remote_exec` is called
+and migrate ``remote_debugger_script`` to ``cpython.remote_debugger_script``.
diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c
index 6d2383ac7c1c65..57d8f68b000b60 100644
--- a/Python/ceval_gil.c
+++ b/Python/ceval_gil.c
@@ -1220,7 +1220,7 @@ static inline int run_remote_debugger_source(PyObject 
*source)
 // that would be an easy target for a ROP gadget.
 static inline void run_remote_debugger_script(PyObject *path)
 {
-    if (0 != PySys_Audit("remote_debugger_script", "O", path)) {
+    if (0 != PySys_Audit("cpython.remote_debugger_script", "O", path)) {
         PyErr_FormatUnraisable(
             "Audit hook failed for remote debugger script %U", path);
         return;
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index 8692caa238a64d..7c6fd1d0e2400e 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -2487,6 +2487,11 @@ sys_remote_exec_impl(PyObject *module, int pid, PyObject 
*script)
     if (PyUnicode_FSConverter(script, &path) == 0) {
         return NULL;
     }
+
+    if (PySys_Audit("sys.remote_exec", "iO", pid, script) < 0) {
+        return NULL;
+    }
+
     debugger_script_path = PyBytes_AS_STRING(path);
 #ifdef MS_WINDOWS
     PyObject *unicode_path;

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: arch...@mail-archive.com

Reply via email to