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

(cherry picked from commit 95f60010219e142a436fae18e1695cbc45407afe)

Co-authored-by: Saiyang Gou <gousaiyang@163.com>
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 850769f..88b4716 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -5156,6 +5156,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);
@@ -5199,7 +5205,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) {
@@ -5210,22 +5216,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
@@ -5243,9 +5254,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;
@@ -5576,6 +5587,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) {
@@ -5816,6 +5832,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
@@ -5925,6 +5948,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
@@ -5943,6 +5971,7 @@
     else
         res = Py_BuildValue(_Py_PARSE_INTPTR, spawnval);
 
+  fail_2:
     while (--envc >= 0)
         PyMem_DEL(envlist[envc]);
     PyMem_DEL(envlist);
@@ -11608,6 +11637,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);