Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 5, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
10 changes: 10 additions & 0 deletions Doc/library/os.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3316,6 +3316,8 @@ to be ignored.
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
Expand Down Expand Up @@ -3672,6 +3674,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`
flags.

.. audit-event:: os.posix_spawn path,argv,env os.posix_spawn

.. versionadded:: 3.8

.. availability:: Unix.
Expand All @@ -3686,6 +3690,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
: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.
Expand Down Expand Up @@ -3786,6 +3792,8 @@ written in Python, such as a mail server's external command delivery program.
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
Expand Down Expand Up @@ -3855,6 +3863,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
cannot be resolved, :exc:`NotImplementedError` will be raised.

.. audit-event:: os.startfile path,operation os.startfile

.. availability:: Windows.


Expand Down
1 change: 1 addition & 0 deletions Doc/library/pty.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
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`
Expand Down
2 changes: 2 additions & 0 deletions Lib/pty.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from select import select
import os
import sys
import tty

__all__ = ["openpty","fork","spawn"]
Expand Down Expand Up @@ -151,6 +152,7 @@ def spawn(argv, master_read=_read, stdin_read=_read):
"""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)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add audit events to command execution functions in os and pty modules.
49 changes: 42 additions & 7 deletions Modules/posixmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -5237,6 +5237,12 @@ os_execv_impl(PyObject *module, path_t *path, PyObject *argv)
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);
Expand Down Expand Up @@ -5280,7 +5286,7 @@ os_execve_impl(PyObject *module, path_t *path, PyObject *argv, PyObject *env)
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) {
Expand All @@ -5291,22 +5297,27 @@ os_execve_impl(PyObject *module, path_t *path, PyObject *argv, PyObject *env)
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
Expand All @@ -5324,9 +5335,9 @@ os_execve_impl(PyObject *module, path_t *path, PyObject *argv, PyObject *env)
/* 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;
Expand Down Expand Up @@ -5657,6 +5668,11 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a
}
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) {
Expand Down Expand Up @@ -5897,6 +5913,13 @@ os_spawnv_impl(PyObject *module, int mode, path_t *path, PyObject *argv)
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
Expand Down Expand Up @@ -6006,6 +6029,11 @@ os_spawnve_impl(PyObject *module, int mode, path_t *path, PyObject *argv,
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
Expand All @@ -6024,6 +6052,7 @@ os_spawnve_impl(PyObject *module, int mode, path_t *path, PyObject *argv,
else
res = Py_BuildValue(_Py_PARSE_INTPTR, spawnval);

fail_2:
while (--envc >= 0)
PyMem_DEL(envlist[envc]);
PyMem_DEL(envlist);
Expand Down Expand Up @@ -11713,6 +11742,12 @@ os_startfile_impl(PyObject *module, path_t *filepath,
"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);
Expand Down