bpo-39184: Add audit events to functions in `fcntl`, `msvcrt`, `os`, `resource`,  `shutil`, `signal`, `syslog` (GH-18407)

Co-authored-by: Saiyang Gou <gousaiyang@163.com>
diff --git a/Modules/fcntlmodule.c b/Modules/fcntlmodule.c
index 0fbf787..a7d2193 100644
--- a/Modules/fcntlmodule.c
+++ b/Modules/fcntlmodule.c
@@ -66,6 +66,10 @@
     char buf[1024];
     int async_err = 0;
 
+    if (PySys_Audit("fcntl.fcntl", "iiO", fd, code, arg ? arg : Py_None) < 0) {
+        return NULL;
+    }
+
     if (arg != NULL) {
         int parse_result;
 
@@ -171,6 +175,11 @@
     Py_ssize_t len;
     char buf[IOCTL_BUFSZ+1];  /* argument plus NUL byte */
 
+    if (PySys_Audit("fcntl.ioctl", "iIO", fd, code,
+                    ob_arg ? ob_arg : Py_None) < 0) {
+        return NULL;
+    }
+
     if (ob_arg != NULL) {
         if (PyArg_Parse(ob_arg, "w*:ioctl", &pstr)) {
             char *arg;
@@ -288,6 +297,10 @@
     int ret;
     int async_err = 0;
 
+    if (PySys_Audit("fcntl.flock", "ii", fd, code) < 0) {
+        return NULL;
+    }
+
 #ifdef HAVE_FLOCK
     do {
         Py_BEGIN_ALLOW_THREADS
@@ -372,6 +385,11 @@
     int ret;
     int async_err = 0;
 
+    if (PySys_Audit("fcntl.lockf", "iiOOi", fd, code, lenobj ? lenobj : Py_None,
+                    startobj ? startobj : Py_None, whence) < 0) {
+        return NULL;
+    }
+
 #ifndef LOCK_SH
 #define LOCK_SH         1       /* shared lock */
 #define LOCK_EX         2       /* exclusive lock */
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 88b4716..2f791d1 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -2827,6 +2827,10 @@
 {
     int result;
 
+    if (PySys_Audit("os.chdir", "(O)", path->object) < 0) {
+        return NULL;
+    }
+
     Py_BEGIN_ALLOW_THREADS
 #ifdef MS_WINDOWS
     /* on unix, success = 0, on windows, success = !0 */
@@ -2866,6 +2870,9 @@
 os_fchdir_impl(PyObject *module, int fd)
 /*[clinic end generated code: output=42e064ec4dc00ab0 input=18e816479a2fa985]*/
 {
+    if (PySys_Audit("os.chdir", "(i)", fd) < 0) {
+        return NULL;
+    }
     return posix_fildes_fd(fd, fchdir);
 }
 #endif /* HAVE_FCHDIR */
@@ -2923,6 +2930,11 @@
         return NULL;
 #endif
 
+    if (PySys_Audit("os.chmod", "Oii", path->object, mode,
+                    dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) {
+        return NULL;
+    }
+
 #ifdef MS_WINDOWS
     Py_BEGIN_ALLOW_THREADS
     attr = GetFileAttributesW(path->wide);
@@ -3019,6 +3031,10 @@
     int res;
     int async_err = 0;
 
+    if (PySys_Audit("os.chmod", "iii", fd, mode, -1) < 0) {
+        return NULL;
+    }
+
     do {
         Py_BEGIN_ALLOW_THREADS
         res = fchmod(fd, mode);
@@ -3050,6 +3066,9 @@
 /*[clinic end generated code: output=082344022b51a1d5 input=90c5663c7465d24f]*/
 {
     int res;
+    if (PySys_Audit("os.chmod", "Oii", path->object, mode, -1) < 0) {
+        return NULL;
+    }
     Py_BEGIN_ALLOW_THREADS
     res = lchmod(path->narrow, mode);
     Py_END_ALLOW_THREADS
@@ -3092,6 +3111,10 @@
         return NULL;
 #endif
 
+    if (PySys_Audit("os.chflags", "Ok", path->object, flags) < 0) {
+        return NULL;
+    }
+
     Py_BEGIN_ALLOW_THREADS
 #ifdef HAVE_LCHFLAGS
     if (!follow_symlinks)
@@ -3127,6 +3150,9 @@
 /*[clinic end generated code: output=30ae958695c07316 input=f9f82ea8b585ca9d]*/
 {
     int res;
+    if (PySys_Audit("os.chflags", "Ok", path->object, flags) < 0) {
+        return NULL;
+    }
     Py_BEGIN_ALLOW_THREADS
     res = lchflags(path->narrow, flags);
     Py_END_ALLOW_THREADS
@@ -3289,6 +3315,11 @@
     }
 #endif
 
+    if (PySys_Audit("os.chown", "OIIi", path->object, uid, gid,
+                    dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) {
+        return NULL;
+    }
+
     Py_BEGIN_ALLOW_THREADS
 #ifdef HAVE_FCHOWN
     if (path->fd != -1)
@@ -3338,6 +3369,10 @@
     int res;
     int async_err = 0;
 
+    if (PySys_Audit("os.chown", "iIIi", fd, uid, gid, -1) < 0) {
+        return NULL;
+    }
+
     do {
         Py_BEGIN_ALLOW_THREADS
         res = fchown(fd, uid, gid);
@@ -3370,6 +3405,9 @@
 /*[clinic end generated code: output=25eaf6af412fdf2f input=b1c6014d563a7161]*/
 {
     int res;
+    if (PySys_Audit("os.chown", "OIIi", path->object, uid, gid, -1) < 0) {
+        return NULL;
+    }
     Py_BEGIN_ALLOW_THREADS
     res = lchown(path->narrow, uid, gid);
     Py_END_ALLOW_THREADS
@@ -3563,6 +3601,12 @@
     }
 #endif
 
+    if (PySys_Audit("os.link", "OOii", src->object, dst->object,
+                    src_dir_fd == DEFAULT_DIR_FD ? -1 : src_dir_fd,
+                    dst_dir_fd == DEFAULT_DIR_FD ? -1 : dst_dir_fd) < 0) {
+        return NULL;
+    }
+
 #ifdef MS_WINDOWS
     Py_BEGIN_ALLOW_THREADS
     result = CreateHardLinkW(dst->wide, src->wide, NULL);
@@ -4034,6 +4078,11 @@
 {
     int result;
 
+    if (PySys_Audit("os.mkdir", "Oii", path->object, mode,
+                    dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) {
+        return NULL;
+    }
+
 #ifdef MS_WINDOWS
     Py_BEGIN_ALLOW_THREADS
     result = CreateDirectoryW(path->wide, NULL);
@@ -4179,6 +4228,12 @@
     }
 #endif
 
+    if (PySys_Audit("os.rename", "OOii", src->object, dst->object,
+                    src_dir_fd == DEFAULT_DIR_FD ? -1 : src_dir_fd,
+                    dst_dir_fd == DEFAULT_DIR_FD ? -1 : dst_dir_fd) < 0) {
+        return NULL;
+    }
+
 #ifdef MS_WINDOWS
     Py_BEGIN_ALLOW_THREADS
     result = MoveFileExW(src->wide, dst->wide, flags);
@@ -4279,6 +4334,11 @@
 {
     int result;
 
+    if (PySys_Audit("os.rmdir", "Oi", path->object,
+                    dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) {
+        return NULL;
+    }
+
     Py_BEGIN_ALLOW_THREADS
 #ifdef MS_WINDOWS
     /* Windows, success=1, UNIX, success=0 */
@@ -4437,6 +4497,11 @@
 {
     int result;
 
+    if (PySys_Audit("os.remove", "Oi", path->object,
+                    dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) {
+        return NULL;
+    }
+
     Py_BEGIN_ALLOW_THREADS
     _Py_BEGIN_SUPPRESS_IPH
 #ifdef MS_WINDOWS
@@ -4855,6 +4920,11 @@
     }
 #endif
 
+    if (PySys_Audit("os.utime", "OOOi", path->object, times, ns ? ns : Py_None,
+                    dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) {
+        return NULL;
+    }
+
 #ifdef MS_WINDOWS
     Py_BEGIN_ALLOW_THREADS
     hFile = CreateFileW(path->wide, FILE_WRITE_ATTRIBUTES, 0,
@@ -5156,8 +5226,7 @@
         return NULL;
     }
 
-    if (PySys_Audit("os.exec", "OOO", path->object ? path->object : Py_None,
-                    argv, Py_None) < 0) {
+    if (PySys_Audit("os.exec", "OOO", path->object, argv, Py_None) < 0) {
         free_string_array(argvlist, argc);
         return NULL;
     }
@@ -5233,8 +5302,7 @@
     if (envlist == NULL)
         goto fail_0;
 
-    if (PySys_Audit("os.exec", "OOO", path->object ? path->object : Py_None,
-                    argv, env) < 0) {
+    if (PySys_Audit("os.exec", "OOO", path->object, argv, env) < 0) {
         goto fail_1;
     }
 
@@ -5587,8 +5655,7 @@
     }
     attrp = &attr;
 
-    if (PySys_Audit("os.posix_spawn", "OOO",
-                    path->object ? path->object : Py_None, argv, env) < 0) {
+    if (PySys_Audit("os.posix_spawn", "OOO", path->object, argv, env) < 0) {
         goto exit;
     }
 
@@ -5832,8 +5899,7 @@
         mode = _P_OVERLAY;
 #endif
 
-    if (PySys_Audit("os.spawn", "iOOO", mode,
-                    path->object ? path->object : Py_None, argv,
+    if (PySys_Audit("os.spawn", "iOOO", mode, path->object, argv,
                     Py_None) < 0) {
         free_string_array(argvlist, argc);
         return NULL;
@@ -5948,8 +6014,7 @@
         mode = _P_OVERLAY;
 #endif
 
-    if (PySys_Audit("os.spawn", "iOOO", mode,
-                    path->object ? path->object : Py_None, argv, env) < 0) {
+    if (PySys_Audit("os.spawn", "iOOO", mode, path->object, argv, env) < 0) {
         goto fail_2;
     }
 
@@ -6104,6 +6169,9 @@
         PyErr_SetString(PyExc_RuntimeError, "fork not supported for subinterpreters");
         return NULL;
     }
+    if (PySys_Audit("os.fork", NULL) < 0) {
+        return NULL;
+    }
     PyOS_BeforeFork();
     pid = fork();
     if (pid == 0) {
@@ -6709,6 +6777,9 @@
         PyErr_SetString(PyExc_RuntimeError, "fork not supported for subinterpreters");
         return NULL;
     }
+    if (PySys_Audit("os.forkpty", NULL) < 0) {
+        return NULL;
+    }
     PyOS_BeforeFork();
     pid = forkpty(&master_fd, NULL, NULL, NULL);
     if (pid == 0) {
@@ -7230,14 +7301,15 @@
 static PyObject *
 os_kill_impl(PyObject *module, pid_t pid, Py_ssize_t signal)
 /*[clinic end generated code: output=8e346a6701c88568 input=61a36b86ca275ab9]*/
-#ifndef MS_WINDOWS
 {
+    if (PySys_Audit("os.kill", "in", pid, signal) < 0) {
+        return NULL;
+    }
+#ifndef MS_WINDOWS
     if (kill(pid, (int)signal) == -1)
         return posix_error();
     Py_RETURN_NONE;
-}
 #else /* !MS_WINDOWS */
-{
     PyObject *result;
     DWORD sig = (DWORD)signal;
     DWORD err;
@@ -7272,8 +7344,8 @@
 
     CloseHandle(handle);
     return result;
-}
 #endif /* !MS_WINDOWS */
+}
 #endif /* HAVE_KILL */
 
 
@@ -7292,6 +7364,9 @@
 os_killpg_impl(PyObject *module, pid_t pgid, int signal)
 /*[clinic end generated code: output=6dbcd2f1fdf5fdba input=38b5449eb8faec19]*/
 {
+    if (PySys_Audit("os.killpg", "ii", pgid, signal) < 0) {
+        return NULL;
+    }
     /* XXX some man pages make the `pgid` parameter an int, others
        a pid_t. Since getpgrp() returns a pid_t, we assume killpg should
        take the same type. Moreover, pid_t is always at least as wide as
@@ -8035,6 +8110,11 @@
     int result;
 #endif
 
+    if (PySys_Audit("os.symlink", "OOi", src->object, dst->object,
+                    dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd) < 0) {
+        return NULL;
+    }
+
 #ifdef MS_WINDOWS
 
     if (windows_has_symlink_unprivileged_flag) {
@@ -8638,6 +8718,10 @@
 {
     int res;
 
+    if (PySys_Audit("os.lockf", "iiL", fd, command, length) < 0) {
+        return NULL;
+    }
+
     Py_BEGIN_ALLOW_THREADS
     res = lockf(fd, command, length);
     Py_END_ALLOW_THREADS
@@ -10070,6 +10154,9 @@
         PyErr_SetString(PyExc_ValueError, "illegal environment variable name");
         return NULL;
     }
+    if (PySys_Audit("os.putenv", "OO", name, value) < 0) {
+        return NULL;
+    }
     bytes = PyBytes_FromFormat("%s=%s", name_string, value_string);
     if (bytes == NULL) {
         return NULL;
@@ -10105,6 +10192,10 @@
     int err;
 #endif
 
+    if (PySys_Audit("os.unsetenv", "(O)", name) < 0) {
+        return NULL;
+    }
+
 #ifdef HAVE_BROKEN_UNSETENV
     unsetenv(PyBytes_AS_STRING(name));
 #else
@@ -11637,9 +11728,7 @@
             "startfile not available on this platform");
     }
 
-    if (PySys_Audit("os.startfile", "Ou",
-                    filepath->object ? filepath->object : Py_None,
-                    operation) < 0) {
+    if (PySys_Audit("os.startfile", "Ou", filepath->object, operation) < 0) {
         return NULL;
     }
 
@@ -11817,6 +11906,10 @@
     if (fd_and_follow_symlinks_invalid("getxattr", path->fd, follow_symlinks))
         return NULL;
 
+    if (PySys_Audit("os.getxattr", "OO", path->object, attribute->object) < 0) {
+        return NULL;
+    }
+
     for (i = 0; ; i++) {
         void *ptr;
         ssize_t result;
@@ -11888,6 +11981,11 @@
     if (fd_and_follow_symlinks_invalid("setxattr", path->fd, follow_symlinks))
         return NULL;
 
+    if (PySys_Audit("os.setxattr", "OOy#i", path->object, attribute->object,
+                    value->buf, value->len, flags) < 0) {
+        return NULL;
+    }
+
     Py_BEGIN_ALLOW_THREADS;
     if (path->fd > -1)
         result = fsetxattr(path->fd, attribute->narrow,
@@ -11936,6 +12034,10 @@
     if (fd_and_follow_symlinks_invalid("removexattr", path->fd, follow_symlinks))
         return NULL;
 
+    if (PySys_Audit("os.removexattr", "OO", path->object, attribute->object) < 0) {
+        return NULL;
+    }
+
     Py_BEGIN_ALLOW_THREADS;
     if (path->fd > -1)
         result = fremovexattr(path->fd, attribute->narrow);
@@ -11981,6 +12083,11 @@
     if (fd_and_follow_symlinks_invalid("listxattr", path->fd, follow_symlinks))
         goto exit;
 
+    if (PySys_Audit("os.listxattr", "(O)",
+                    path->object ? path->object : Py_None) < 0) {
+        return NULL;
+    }
+
     name = path->narrow ? path->narrow : ".";
 
     for (i = 0; ; i++) {
@@ -13494,6 +13601,10 @@
     DLL_DIRECTORY_COOKIE cookie = 0;
     DWORD err = 0;
 
+    if (PySys_Audit("os.add_dll_directory", "(O)", path->object) < 0) {
+        return NULL;
+    }
+
     /* For Windows 7, we have to load this. As this will be a fairly
        infrequent operation, just do it each time. Kernel32 is always
        loaded. */
diff --git a/Modules/resource.c b/Modules/resource.c
index 87c72e7..afde03c 100644
--- a/Modules/resource.c
+++ b/Modules/resource.c
@@ -224,6 +224,11 @@
         return NULL;
     }
 
+    if (PySys_Audit("resource.setrlimit", "iO", resource,
+                    limits ? limits : Py_None) < 0) {
+        return NULL;
+    }
+
     if (py2rlimit(limits, &rl) < 0) {
         return NULL;
     }
@@ -269,6 +274,11 @@
         return NULL;
     }
 
+    if (PySys_Audit("resource.prlimit", "iiO", pid, resource,
+                    limits ? limits : Py_None) < 0) {
+        return NULL;
+    }
+
     if (group_right_1) {
         if (py2rlimit(limits, &new_limit) < 0) {
             return NULL;
diff --git a/Modules/signalmodule.c b/Modules/signalmodule.c
index 9aca705..0c9a267 100644
--- a/Modules/signalmodule.c
+++ b/Modules/signalmodule.c
@@ -1233,6 +1233,10 @@
 {
     int err;
 
+    if (PySys_Audit("signal.pthread_kill", "ki", thread_id, signalnum) < 0) {
+        return NULL;
+    }
+
     err = pthread_kill((pthread_t)thread_id, signalnum);
     if (err != 0) {
         errno = err;
diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c
index b2ea73b..66ea270 100644
--- a/Modules/syslogmodule.c
+++ b/Modules/syslogmodule.c
@@ -144,6 +144,10 @@
             return NULL;
     }
 
+    if (PySys_Audit("syslog.openlog", "sll", ident, logopt, facility) < 0) {
+        return NULL;
+    }
+
     openlog(ident, logopt, facility);
     S_log_open = 1;
 
@@ -170,6 +174,10 @@
     if (message == NULL)
         return NULL;
 
+    if (PySys_Audit("syslog.syslog", "is", priority, message) < 0) {
+        return NULL;
+    }
+
     /*  if log is not opened, open it now  */
     if (!S_log_open) {
         PyObject *openargs;
@@ -194,6 +202,9 @@
 static PyObject *
 syslog_closelog(PyObject *self, PyObject *unused)
 {
+    if (PySys_Audit("syslog.closelog", NULL) < 0) {
+        return NULL;
+    }
     if (S_log_open) {
         closelog();
         Py_CLEAR(S_ident_o);
@@ -209,6 +220,9 @@
 
     if (!PyArg_ParseTuple(args, "l;mask for priority", &maskpri))
         return NULL;
+    if (PySys_Audit("syslog.setlogmask", "(O)", args ? args : Py_None) < 0) {
+        return NULL;
+    }
     omaskpri = setlogmask(maskpri);
     return PyLong_FromLong(omaskpri);
 }