Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 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
5 changes: 5 additions & 0 deletions Doc/library/sys.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1933,6 +1933,11 @@ 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_exec pid script_path

When the code is executed in the remote process, an :ref:`auditing event <auditing>`
``remote_exec`` is raised with the *pid* and the path to the script file.

.. audit-event:: remote_debugger_script script_path

When the script is executed in the remote process, an
Expand Down
20 changes: 20 additions & 0 deletions Lib/test/audit-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,26 @@ 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 = ""
def hook(event, args):
if event != "remote_exec": return
nonlocal event_pid
event_pid = args[0]
nonlocal event_script_path
event_script_path = args[1]

sys.addaudithook(hook)
with tempfile.NamedTemporaryFile(mode='w+', delete=True) as tmp_file:
tmp_file.write("print('Hello from remote_exec!')\n")
tmp_file.flush()
sys.remote_exec(pid, tmp_file.name)
assertEqual(pid, event_pid)
assertEqual(tmp_file.name, event_script_path)

if __name__ == "__main__":
from test.support import suppress_msvcrt_asserts
Expand Down
19 changes: 19 additions & 0 deletions Lib/test/support/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -3069,6 +3070,24 @@ 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(test):
if not sys.is_remote_debug_enabled():
return unittest.skip("Remote debugging is not enabled")(test)
if sys.platform != "darwin" and sys.platform != "linux" and sys.platform != "win32":
return unittest.skip("Test only runs on Linux, Windows and MacOS")(test)
if sys.platform == "linux" and not _supports_remote_attaching():
return unittest.skip("Test only runs on Linux with process_vm_readv support")(test)
return _id(test)

class EqualToForwardRef:
"""Helper to ease use of annotationlib.ForwardRef in tests.
Expand Down
7 changes: 6 additions & 1 deletion Lib/test/test_audit.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

AUDIT_TESTS_PY = support.findfile("audit-tests.py")


class AuditTest(unittest.TestCase):
maxDiff = None

Expand Down Expand Up @@ -322,6 +321,12 @@ 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, stdout, stderr = self.run_python("test_sys_remote_exec")
if returncode:
self.fail(stderr)

if __name__ == "__main__":
unittest.main()
17 changes: 1 addition & 16 deletions Lib/test/test_sys.py
Original file line number Diff line number Diff line change
Expand Up @@ -1943,22 +1943,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):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Emit ``remote_exec`` audit event when :func:`sys.remote_exec` is called.
4 changes: 4 additions & 0 deletions Python/sysmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2485,6 +2485,10 @@ sys_remote_exec_impl(PyObject *module, int pid, PyObject *script)
PyObject *path;
const char *debugger_script_path;

if (PySys_Audit("remote_exec", "iO", pid, script) < 0) {
return NULL;
}

if (PyUnicode_FSConverter(script, &path) == 0) {
return NULL;
}
Expand Down
Loading