Skip to content

Commit 3498ac5

Browse files
bpo-39184: Add audit events to command execution functions in os and pty modules (GH-17824)
(cherry picked from commit 95f6001) Co-authored-by: Saiyang Gou <[email protected]>
1 parent 30e7693 commit 3498ac5

File tree

5 files changed

+56
-7
lines changed

5 files changed

+56
-7
lines changed

Doc/library/os.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3313,6 +3313,8 @@ to be ignored.
33133313
you can check whether or not it is available using :data:`os.supports_fd`.
33143314
If it is unavailable, using it will raise a :exc:`NotImplementedError`.
33153315

3316+
.. audit-event:: os.exec path,args,env os.execl
3317+
33163318
.. availability:: Unix, Windows.
33173319

33183320
.. versionadded:: 3.3
@@ -3656,6 +3658,8 @@ written in Python, such as a mail server's external command delivery program.
36563658
:c:data:`POSIX_SPAWN_SETSCHEDPARAM` and :c:data:`POSIX_SPAWN_SETSCHEDULER`
36573659
flags.
36583660

3661+
.. audit-event:: os.posix_spawn path,argv,env os.posix_spawn
3662+
36593663
.. versionadded:: 3.8
36603664

36613665
.. availability:: Unix.
@@ -3670,6 +3674,8 @@ written in Python, such as a mail server's external command delivery program.
36703674
for the *executable* file in the list of directories specified by the
36713675
:envvar:`PATH` environment variable (in the same way as for ``execvp(3)``).
36723676

3677+
.. audit-event:: os.posix_spawn path,argv,env os.posix_spawnp
3678+
36733679
.. versionadded:: 3.8
36743680

36753681
.. availability:: See :func:`posix_spawn` documentation.
@@ -3770,6 +3776,8 @@ written in Python, such as a mail server's external command delivery program.
37703776
L = ['cp', 'index.html', '/dev/null']
37713777
os.spawnvpe(os.P_WAIT, 'cp', L, os.environ)
37723778

3779+
.. audit-event:: os.spawn mode,path,args,env os.spawnl
3780+
37733781
.. availability:: Unix, Windows. :func:`spawnlp`, :func:`spawnlpe`, :func:`spawnvp`
37743782
and :func:`spawnvpe` are not available on Windows. :func:`spawnle` and
37753783
:func:`spawnve` are not thread-safe on Windows; we advise you to use the
@@ -3839,6 +3847,8 @@ written in Python, such as a mail server's external command delivery program.
38393847
function is not resolved until this function is first called. If the function
38403848
cannot be resolved, :exc:`NotImplementedError` will be raised.
38413849

3850+
.. audit-event:: os.startfile path,operation os.startfile
3851+
38423852
.. availability:: Windows.
38433853

38443854

Doc/library/pty.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ The :mod:`pty` module defines the following functions:
6969
*select* throws an error on your platform when passed three empty lists. This
7070
is a bug, documented in `issue 26228 <https://bugs.python.org/issue26228>`_.
7171

72+
.. audit-event:: pty.spawn argv pty.spawn
7273

7374
.. versionchanged:: 3.4
7475
:func:`spawn` now returns the status value from :func:`os.waitpid`

Lib/pty.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from select import select
1010
import os
11+
import sys
1112
import tty
1213

1314
__all__ = ["openpty","fork","spawn"]
@@ -151,6 +152,7 @@ def spawn(argv, master_read=_read, stdin_read=_read):
151152
"""Create a spawned process."""
152153
if type(argv) == type(''):
153154
argv = (argv,)
155+
sys.audit('pty.spawn', argv)
154156
pid, master_fd = fork()
155157
if pid == CHILD:
156158
os.execlp(argv[0], *argv)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add audit events to command execution functions in os and pty modules.

Modules/posixmodule.c

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5156,6 +5156,12 @@ os_execv_impl(PyObject *module, path_t *path, PyObject *argv)
51565156
return NULL;
51575157
}
51585158

5159+
if (PySys_Audit("os.exec", "OOO", path->object ? path->object : Py_None,
5160+
argv, Py_None) < 0) {
5161+
free_string_array(argvlist, argc);
5162+
return NULL;
5163+
}
5164+
51595165
_Py_BEGIN_SUPPRESS_IPH
51605166
#ifdef HAVE_WEXECV
51615167
_wexecv(path->wide, argvlist);
@@ -5199,7 +5205,7 @@ os_execve_impl(PyObject *module, path_t *path, PyObject *argv, PyObject *env)
51995205
if (!PyList_Check(argv) && !PyTuple_Check(argv)) {
52005206
PyErr_SetString(PyExc_TypeError,
52015207
"execve: argv must be a tuple or list");
5202-
goto fail;
5208+
goto fail_0;
52035209
}
52045210
argc = PySequence_Size(argv);
52055211
if (argc < 1) {
@@ -5210,22 +5216,27 @@ os_execve_impl(PyObject *module, path_t *path, PyObject *argv, PyObject *env)
52105216
if (!PyMapping_Check(env)) {
52115217
PyErr_SetString(PyExc_TypeError,
52125218
"execve: environment must be a mapping object");
5213-
goto fail;
5219+
goto fail_0;
52145220
}
52155221

52165222
argvlist = parse_arglist(argv, &argc);
52175223
if (argvlist == NULL) {
5218-
goto fail;
5224+
goto fail_0;
52195225
}
52205226
if (!argvlist[0][0]) {
52215227
PyErr_SetString(PyExc_ValueError,
52225228
"execve: argv first element cannot be empty");
5223-
goto fail;
5229+
goto fail_0;
52245230
}
52255231

52265232
envlist = parse_envlist(env, &envc);
52275233
if (envlist == NULL)
5228-
goto fail;
5234+
goto fail_0;
5235+
5236+
if (PySys_Audit("os.exec", "OOO", path->object ? path->object : Py_None,
5237+
argv, env) < 0) {
5238+
goto fail_1;
5239+
}
52295240

52305241
_Py_BEGIN_SUPPRESS_IPH
52315242
#ifdef HAVE_FEXECVE
@@ -5243,9 +5254,9 @@ os_execve_impl(PyObject *module, path_t *path, PyObject *argv, PyObject *env)
52435254
/* If we get here it's definitely an error */
52445255

52455256
posix_path_error(path);
5246-
5257+
fail_1:
52475258
free_string_array(envlist, envc);
5248-
fail:
5259+
fail_0:
52495260
if (argvlist)
52505261
free_string_array(argvlist, argc);
52515262
return NULL;
@@ -5576,6 +5587,11 @@ py_posix_spawn(int use_posix_spawnp, PyObject *module, path_t *path, PyObject *a
55765587
}
55775588
attrp = &attr;
55785589

5590+
if (PySys_Audit("os.posix_spawn", "OOO",
5591+
path->object ? path->object : Py_None, argv, env) < 0) {
5592+
goto exit;
5593+
}
5594+
55795595
_Py_BEGIN_SUPPRESS_IPH
55805596
#ifdef HAVE_POSIX_SPAWNP
55815597
if (use_posix_spawnp) {
@@ -5816,6 +5832,13 @@ os_spawnv_impl(PyObject *module, int mode, path_t *path, PyObject *argv)
58165832
mode = _P_OVERLAY;
58175833
#endif
58185834

5835+
if (PySys_Audit("os.spawn", "iOOO", mode,
5836+
path->object ? path->object : Py_None, argv,
5837+
Py_None) < 0) {
5838+
free_string_array(argvlist, argc);
5839+
return NULL;
5840+
}
5841+
58195842
Py_BEGIN_ALLOW_THREADS
58205843
_Py_BEGIN_SUPPRESS_IPH
58215844
#ifdef HAVE_WSPAWNV
@@ -5925,6 +5948,11 @@ os_spawnve_impl(PyObject *module, int mode, path_t *path, PyObject *argv,
59255948
mode = _P_OVERLAY;
59265949
#endif
59275950

5951+
if (PySys_Audit("os.spawn", "iOOO", mode,
5952+
path->object ? path->object : Py_None, argv, env) < 0) {
5953+
goto fail_2;
5954+
}
5955+
59285956
Py_BEGIN_ALLOW_THREADS
59295957
_Py_BEGIN_SUPPRESS_IPH
59305958
#ifdef HAVE_WSPAWNV
@@ -5943,6 +5971,7 @@ os_spawnve_impl(PyObject *module, int mode, path_t *path, PyObject *argv,
59435971
else
59445972
res = Py_BuildValue(_Py_PARSE_INTPTR, spawnval);
59455973

5974+
fail_2:
59465975
while (--envc >= 0)
59475976
PyMem_DEL(envlist[envc]);
59485977
PyMem_DEL(envlist);
@@ -11608,6 +11637,12 @@ os_startfile_impl(PyObject *module, path_t *filepath,
1160811637
"startfile not available on this platform");
1160911638
}
1161011639

11640+
if (PySys_Audit("os.startfile", "Ou",
11641+
filepath->object ? filepath->object : Py_None,
11642+
operation) < 0) {
11643+
return NULL;
11644+
}
11645+
1161111646
Py_BEGIN_ALLOW_THREADS
1161211647
rc = Py_ShellExecuteW((HWND)0, operation, filepath->wide,
1161311648
NULL, NULL, SW_SHOWNORMAL);

0 commit comments

Comments
 (0)