bpo-39184: Add audit events to command execution functions in os and pty modules (GH-17824)
diff --git a/Doc/library/os.rst b/Doc/library/os.rst
index f59423c..bfc0322 100644
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -3314,6 +3314,8 @@
you can check whether or not it is available using :data:`os.supports_fd`.
If it is unavailable, using it will raise a :exc:`NotImplementedError`.
+ .. audit-event:: os.exec path,args,env os.execl
+
.. availability:: Unix, Windows.
.. versionadded:: 3.3
@@ -3670,6 +3672,8 @@
:c:data:`POSIX_SPAWN_SETSCHEDPARAM` and :c:data:`POSIX_SPAWN_SETSCHEDULER`
flags.
+ .. audit-event:: os.posix_spawn path,argv,env os.posix_spawn
+
.. versionadded:: 3.8
.. availability:: Unix.
@@ -3684,6 +3688,8 @@
for the *executable* file in the list of directories specified by the
:envvar:`PATH` environment variable (in the same way as for ``execvp(3)``).
+ .. audit-event:: os.posix_spawn path,argv,env os.posix_spawnp
+
.. versionadded:: 3.8
.. availability:: See :func:`posix_spawn` documentation.
@@ -3784,6 +3790,8 @@
L = ['cp', 'index.html', '/dev/null']
os.spawnvpe(os.P_WAIT, 'cp', L, os.environ)
+ .. audit-event:: os.spawn mode,path,args,env os.spawnl
+
.. availability:: Unix, Windows. :func:`spawnlp`, :func:`spawnlpe`, :func:`spawnvp`
and :func:`spawnvpe` are not available on Windows. :func:`spawnle` and
:func:`spawnve` are not thread-safe on Windows; we advise you to use the
@@ -3853,6 +3861,8 @@
function is not resolved until this function is first called. If the function
cannot be resolved, :exc:`NotImplementedError` will be raised.
+ .. audit-event:: os.startfile path,operation os.startfile
+
.. availability:: Windows.
diff --git a/Doc/library/pty.rst b/Doc/library/pty.rst
index 1226843..e85d2e2 100644
--- a/Doc/library/pty.rst
+++ b/Doc/library/pty.rst
@@ -69,6 +69,7 @@
*select* throws an error on your platform when passed three empty lists. This
is a bug, documented in `issue 26228 <https://bugs.python.org/issue26228>`_.
+ .. audit-event:: pty.spawn argv pty.spawn
.. versionchanged:: 3.4
:func:`spawn` now returns the status value from :func:`os.waitpid`
diff --git a/Lib/pty.py b/Lib/pty.py
index e841f12..a324320 100644
--- a/Lib/pty.py
+++ b/Lib/pty.py
@@ -8,6 +8,7 @@
from select import select
import os
+import sys
import tty
__all__ = ["openpty","fork","spawn"]
@@ -151,6 +152,7 @@
"""Create a spawned process."""
if type(argv) == type(''):
argv = (argv,)
+ sys.audit('pty.spawn', argv)
pid, master_fd = fork()
if pid == CHILD:
os.execlp(argv[0], *argv)
diff --git a/Misc/NEWS.d/next/Security/2020-01-07-00-42-08.bpo-39184.fe7NgK.rst b/Misc/NEWS.d/next/Security/2020-01-07-00-42-08.bpo-39184.fe7NgK.rst
new file mode 100644
index 0000000..1ab5d4d
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2020-01-07-00-42-08.bpo-39184.fe7NgK.rst
@@ -0,0 +1 @@
+Add audit events to command execution functions in os and pty modules.
\ No newline at end of file
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index b71eddf..ec3da4f 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -5234,6 +5234,12 @@
return NULL;
}
+ if (PySys_Audit("os.exec", "OOO", path->object ? path->object : Py_None,
+ argv, Py_None) < 0) {
+ free_string_array(argvlist, argc);
+ return NULL;
+ }
+
_Py_BEGIN_SUPPRESS_IPH
#ifdef HAVE_WEXECV
_wexecv(path->wide, argvlist);
@@ -5277,7 +5283,7 @@
if (!PyList_Check(argv) && !PyTuple_Check(argv)) {
PyErr_SetString(PyExc_TypeError,
"execve: argv must be a tuple or list");
- goto fail;
+ goto fail_0;
}
argc = PySequence_Size(argv);
if (argc < 1) {
@@ -5288,22 +5294,27 @@
if (!PyMapping_Check(env)) {
PyErr_SetString(PyExc_TypeError,
"execve: environment must be a mapping object");
- goto fail;
+ goto fail_0;
}
argvlist = parse_arglist(argv, &argc);
if (argvlist == NULL) {
- goto fail;
+ goto fail_0;
}
if (!argvlist[0][0]) {
PyErr_SetString(PyExc_ValueError,
"execve: argv first element cannot be empty");
- goto fail;
+ goto fail_0;
}
envlist = parse_envlist(env, &envc);
if (envlist == NULL)
- goto fail;
+ goto fail_0;
+
+ if (PySys_Audit("os.exec", "OOO", path->object ? path->object : Py_None,
+ argv, env) < 0) {
+ goto fail_1;
+ }
_Py_BEGIN_SUPPRESS_IPH
#ifdef HAVE_FEXECVE
@@ -5321,9 +5332,9 @@
/* If we get here it's definitely an error */
posix_path_error(path);
-
+ fail_1:
free_string_array(envlist, envc);
- fail:
+ fail_0:
if (argvlist)
free_string_array(argvlist, argc);
return NULL;
@@ -5654,6 +5665,11 @@
}
attrp = &attr;
+ if (PySys_Audit("os.posix_spawn", "OOO",
+ path->object ? path->object : Py_None, argv, env) < 0) {
+ goto exit;
+ }
+
_Py_BEGIN_SUPPRESS_IPH
#ifdef HAVE_POSIX_SPAWNP
if (use_posix_spawnp) {
@@ -5894,6 +5910,13 @@
mode = _P_OVERLAY;
#endif
+ if (PySys_Audit("os.spawn", "iOOO", mode,
+ path->object ? path->object : Py_None, argv,
+ Py_None) < 0) {
+ free_string_array(argvlist, argc);
+ return NULL;
+ }
+
Py_BEGIN_ALLOW_THREADS
_Py_BEGIN_SUPPRESS_IPH
#ifdef HAVE_WSPAWNV
@@ -6003,6 +6026,11 @@
mode = _P_OVERLAY;
#endif
+ if (PySys_Audit("os.spawn", "iOOO", mode,
+ path->object ? path->object : Py_None, argv, env) < 0) {
+ goto fail_2;
+ }
+
Py_BEGIN_ALLOW_THREADS
_Py_BEGIN_SUPPRESS_IPH
#ifdef HAVE_WSPAWNV
@@ -6021,6 +6049,7 @@
else
res = Py_BuildValue(_Py_PARSE_INTPTR, spawnval);
+ fail_2:
while (--envc >= 0)
PyMem_DEL(envlist[envc]);
PyMem_DEL(envlist);
@@ -11701,6 +11730,12 @@
"startfile not available on this platform");
}
+ if (PySys_Audit("os.startfile", "Ou",
+ filepath->object ? filepath->object : Py_None,
+ operation) < 0) {
+ return NULL;
+ }
+
Py_BEGIN_ALLOW_THREADS
rc = Py_ShellExecuteW((HWND)0, operation, filepath->wide,
NULL, NULL, SW_SHOWNORMAL);