bpo-39184: Add audit events to command execution functions in os and pty modules (GH-17824)

This commit is contained in:
Saiyang Gou 2020-02-04 16:15:00 -08:00 committed by GitHub
parent 40e547dfbb
commit 95f6001021
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 56 additions and 7 deletions

View File

@ -3314,6 +3314,8 @@ to be ignored.
you can check whether or not it is available using :data:`os.supports_fd`. 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`. If it is unavailable, using it will raise a :exc:`NotImplementedError`.
.. audit-event:: os.exec path,args,env os.execl
.. availability:: Unix, Windows. .. availability:: Unix, Windows.
.. versionadded:: 3.3 .. versionadded:: 3.3
@ -3670,6 +3672,8 @@ written in Python, such as a mail server's external command delivery program.
:c:data:`POSIX_SPAWN_SETSCHEDPARAM` and :c:data:`POSIX_SPAWN_SETSCHEDULER` :c:data:`POSIX_SPAWN_SETSCHEDPARAM` and :c:data:`POSIX_SPAWN_SETSCHEDULER`
flags. flags.
.. audit-event:: os.posix_spawn path,argv,env os.posix_spawn
.. versionadded:: 3.8 .. versionadded:: 3.8
.. availability:: Unix. .. availability:: Unix.
@ -3684,6 +3688,8 @@ written in Python, such as a mail server's external command delivery program.
for the *executable* file in the list of directories specified by the for the *executable* file in the list of directories specified by the
:envvar:`PATH` environment variable (in the same way as for ``execvp(3)``). :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 .. versionadded:: 3.8
.. availability:: See :func:`posix_spawn` documentation. .. availability:: See :func:`posix_spawn` documentation.
@ -3784,6 +3790,8 @@ written in Python, such as a mail server's external command delivery program.
L = ['cp', 'index.html', '/dev/null'] L = ['cp', 'index.html', '/dev/null']
os.spawnvpe(os.P_WAIT, 'cp', L, os.environ) 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` .. availability:: Unix, Windows. :func:`spawnlp`, :func:`spawnlpe`, :func:`spawnvp`
and :func:`spawnvpe` are not available on Windows. :func:`spawnle` and 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 :func:`spawnve` are not thread-safe on Windows; we advise you to use the
@ -3853,6 +3861,8 @@ written in Python, such as a mail server's external command delivery program.
function is not resolved until this function is first called. If the function function is not resolved until this function is first called. If the function
cannot be resolved, :exc:`NotImplementedError` will be raised. cannot be resolved, :exc:`NotImplementedError` will be raised.
.. audit-event:: os.startfile path,operation os.startfile
.. availability:: Windows. .. availability:: Windows.

View File

@ -69,6 +69,7 @@ The :mod:`pty` module defines the following functions:
*select* throws an error on your platform when passed three empty lists. This *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>`_. is a bug, documented in `issue 26228 <https://bugs.python.org/issue26228>`_.
.. audit-event:: pty.spawn argv pty.spawn
.. versionchanged:: 3.4 .. versionchanged:: 3.4
:func:`spawn` now returns the status value from :func:`os.waitpid` :func:`spawn` now returns the status value from :func:`os.waitpid`

View File

@ -8,6 +8,7 @@
from select import select from select import select
import os import os
import sys
import tty import tty
__all__ = ["openpty","fork","spawn"] __all__ = ["openpty","fork","spawn"]
@ -151,6 +152,7 @@ def spawn(argv, master_read=_read, stdin_read=_read):
"""Create a spawned process.""" """Create a spawned process."""
if type(argv) == type(''): if type(argv) == type(''):
argv = (argv,) argv = (argv,)
sys.audit('pty.spawn', argv)
pid, master_fd = fork() pid, master_fd = fork()
if pid == CHILD: if pid == CHILD:
os.execlp(argv[0], *argv) os.execlp(argv[0], *argv)

View File

@ -0,0 +1 @@
Add audit events to command execution functions in os and pty modules.

View File

@ -5234,6 +5234,12 @@ os_execv_impl(PyObject *module, path_t *path, PyObject *argv)
return NULL; 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 _Py_BEGIN_SUPPRESS_IPH
#ifdef HAVE_WEXECV #ifdef HAVE_WEXECV
_wexecv(path->wide, argvlist); _wexecv(path->wide, argvlist);
@ -5277,7 +5283,7 @@ os_execve_impl(PyObject *module, path_t *path, PyObject *argv, PyObject *env)
if (!PyList_Check(argv) && !PyTuple_Check(argv)) { if (!PyList_Check(argv) && !PyTuple_Check(argv)) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"execve: argv must be a tuple or list"); "execve: argv must be a tuple or list");
goto fail; goto fail_0;
} }
argc = PySequence_Size(argv); argc = PySequence_Size(argv);
if (argc < 1) { if (argc < 1) {
@ -5288,22 +5294,27 @@ os_execve_impl(PyObject *module, path_t *path, PyObject *argv, PyObject *env)
if (!PyMapping_Check(env)) { if (!PyMapping_Check(env)) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"execve: environment must be a mapping object"); "execve: environment must be a mapping object");
goto fail; goto fail_0;
} }
argvlist = parse_arglist(argv, &argc); argvlist = parse_arglist(argv, &argc);
if (argvlist == NULL) { if (argvlist == NULL) {
goto fail; goto fail_0;
} }
if (!argvlist[0][0]) { if (!argvlist[0][0]) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"execve: argv first element cannot be empty"); "execve: argv first element cannot be empty");
goto fail; goto fail_0;
} }
envlist = parse_envlist(env, &envc); envlist = parse_envlist(env, &envc);
if (envlist == NULL) 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 _Py_BEGIN_SUPPRESS_IPH
#ifdef HAVE_FEXECVE #ifdef HAVE_FEXECVE
@ -5321,9 +5332,9 @@ os_execve_impl(PyObject *module, path_t *path, PyObject *argv, PyObject *env)
/* If we get here it's definitely an error */ /* If we get here it's definitely an error */
posix_path_error(path); posix_path_error(path);
fail_1:
free_string_array(envlist, envc); free_string_array(envlist, envc);
fail: fail_0:
if (argvlist) if (argvlist)
free_string_array(argvlist, argc); free_string_array(argvlist, argc);
return NULL; return NULL;
@ -5654,6 +5665,11 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a
} }
attrp = &attr; attrp = &attr;
if (PySys_Audit("os.posix_spawn", "OOO",
path->object ? path->object : Py_None, argv, env) < 0) {
goto exit;
}
_Py_BEGIN_SUPPRESS_IPH _Py_BEGIN_SUPPRESS_IPH
#ifdef HAVE_POSIX_SPAWNP #ifdef HAVE_POSIX_SPAWNP
if (use_posix_spawnp) { if (use_posix_spawnp) {
@ -5894,6 +5910,13 @@ os_spawnv_impl(PyObject *module, int mode, path_t *path, PyObject *argv)
mode = _P_OVERLAY; mode = _P_OVERLAY;
#endif #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_ALLOW_THREADS
_Py_BEGIN_SUPPRESS_IPH _Py_BEGIN_SUPPRESS_IPH
#ifdef HAVE_WSPAWNV #ifdef HAVE_WSPAWNV
@ -6003,6 +6026,11 @@ os_spawnve_impl(PyObject *module, int mode, path_t *path, PyObject *argv,
mode = _P_OVERLAY; mode = _P_OVERLAY;
#endif #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_ALLOW_THREADS
_Py_BEGIN_SUPPRESS_IPH _Py_BEGIN_SUPPRESS_IPH
#ifdef HAVE_WSPAWNV #ifdef HAVE_WSPAWNV
@ -6021,6 +6049,7 @@ os_spawnve_impl(PyObject *module, int mode, path_t *path, PyObject *argv,
else else
res = Py_BuildValue(_Py_PARSE_INTPTR, spawnval); res = Py_BuildValue(_Py_PARSE_INTPTR, spawnval);
fail_2:
while (--envc >= 0) while (--envc >= 0)
PyMem_DEL(envlist[envc]); PyMem_DEL(envlist[envc]);
PyMem_DEL(envlist); PyMem_DEL(envlist);
@ -11701,6 +11730,12 @@ os_startfile_impl(PyObject *module, path_t *filepath,
"startfile not available on this platform"); "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 Py_BEGIN_ALLOW_THREADS
rc = Py_ShellExecuteW((HWND)0, operation, filepath->wide, rc = Py_ShellExecuteW((HWND)0, operation, filepath->wide,
NULL, NULL, SW_SHOWNORMAL); NULL, NULL, SW_SHOWNORMAL);