From 60419a7e96577cf783b3b45bf3984f9fb0d7ddff Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Mon, 24 Jun 2019 08:42:54 -0700 Subject: [PATCH] bpo-37363: Add audit events for a range of modules (GH-14301) --- Doc/library/ctypes.rst | 2 +- Doc/library/ensurepip.rst | 2 ++ Doc/library/ftplib.rst | 6 ++++++ Doc/library/functions.rst | 14 ++++++++------ Doc/library/glob.rst | 4 ++++ Doc/library/imaplib.rst | 4 ++++ Doc/library/io.rst | 2 +- Doc/library/nntplib.rst | 11 +++++++++++ Doc/library/os.rst | 4 ++++ Doc/library/pdb.rst | 2 ++ Doc/library/poplib.rst | 12 ++++++++++++ Doc/library/shutil.rst | 6 ++++++ Doc/library/smtplib.rst | 6 ++++++ Doc/library/sqlite3.rst | 2 ++ Doc/library/subprocess.rst | 7 +++++++ Doc/library/telnetlib.rst | 4 ++++ Doc/library/tempfile.rst | 10 ++++++++++ Doc/library/urllib.request.rst | 2 +- Doc/library/webbrowser.rst | 2 ++ Doc/tools/extensions/suspicious.py | 10 +++++----- Lib/ensurepip/__init__.py | 2 ++ Lib/ftplib.py | 2 ++ Lib/glob.py | 2 ++ Lib/imaplib.py | 2 ++ Lib/nntplib.py | 4 ++++ Lib/pdb.py | 1 + Lib/poplib.py | 3 +++ Lib/shutil.py | 3 +++ Lib/smtplib.py | 2 ++ Lib/subprocess.py | 9 ++++++++- Lib/telnetlib.py | 2 ++ Lib/tempfile.py | 5 ++++- Lib/webbrowser.py | 11 +++++++++-- .../2019-06-21-15-58-59.bpo-37363.diouyl.rst | 5 +++++ Modules/_sqlite/module.c | 4 ++++ Modules/posixmodule.c | 9 +++++++++ Python/bltinmodule.c | 5 +++++ 37 files changed, 165 insertions(+), 18 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2019-06-21-15-58-59.bpo-37363.diouyl.rst diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst index 97172c588a..c1218ad32e 100644 --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -2046,7 +2046,7 @@ Data types .. audit-event:: ctypes.cdata address This method, and others that indirectly call this method, raises an - :func:`auditing event ` ``ctypes.cdata`` with argument + :ref:`auditing event ` ``ctypes.cdata`` with argument ``address``. .. method:: from_param(obj) diff --git a/Doc/library/ensurepip.rst b/Doc/library/ensurepip.rst index c797f63326..3b6b01fb45 100644 --- a/Doc/library/ensurepip.rst +++ b/Doc/library/ensurepip.rst @@ -119,6 +119,8 @@ Module API *verbosity* controls the level of output to :data:`sys.stdout` from the bootstrapping operation. + .. audit-event:: ensurepip.bootstrap root + .. note:: The bootstrapping process has side effects on both ``sys.path`` and diff --git a/Doc/library/ftplib.rst b/Doc/library/ftplib.rst index 6c39f9a59f..36abfbde3e 100644 --- a/Doc/library/ftplib.rst +++ b/Doc/library/ftplib.rst @@ -190,6 +190,8 @@ followed by ``lines`` for the text version or ``binary`` for the binary version. *source_address* is a 2-tuple ``(host, port)`` for the socket to bind to as its source address before connecting. + .. audit-event:: ftplib.FTP.connect "self host port" + .. versionchanged:: 3.3 *source_address* parameter was added. @@ -223,6 +225,8 @@ followed by ``lines`` for the text version or ``binary`` for the binary version. Send a simple command string to the server and return the response string. + .. audit-event:: ftplib.FTP.sendcmd "self cmd" + .. method:: FTP.voidcmd(cmd) @@ -230,6 +234,8 @@ followed by ``lines`` for the text version or ``binary`` for the binary version. nothing if a response code corresponding to success (codes in the range 200--299) is received. Raise :exc:`error_reply` otherwise. + .. audit-event:: ftplib.FTP.sendcmd "self cmd" + .. method:: FTP.retrbinary(cmd, callback, blocksize=8192, rest=None) diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index 8897705672..637c82b670 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -128,6 +128,8 @@ are always available. They are listed here in alphabetical order. :func:`breakpoint` will automatically call that, allowing you to drop into the debugger of choice. + .. audit-event:: builtins.breakpoint "sys.breakpointhook" + .. versionadded:: 3.7 .. _func-bytearray: @@ -277,7 +279,7 @@ are always available. They are listed here in alphabetical order. .. audit-event:: compile "source filename" - Raises an :func:`auditing event ` ``compile`` with arguments + Raises an :ref:`auditing event ` ``compile`` with arguments ``source`` and ``filename``. This event may also be raised by implicit compilation. @@ -490,8 +492,8 @@ are always available. They are listed here in alphabetical order. .. audit-event:: exec code_object - Raises an :func:`auditing event ` ``exec`` with the code object as - the argument. Code compilation events may also be raised. + Raises an :ref:`auditing event ` ``exec`` with the code object + as the argument. Code compilation events may also be raised. .. index:: builtin: exec @@ -525,8 +527,8 @@ are always available. They are listed here in alphabetical order. .. audit-event:: exec code_object - Raises an :func:`auditing event ` ``exec`` with the code object as - the argument. Code compilation events may also be raised. + Raises an :ref:`auditing event ` ``exec`` with the code object + as the argument. Code compilation events may also be raised. .. note:: @@ -779,7 +781,7 @@ are always available. They are listed here in alphabetical order. .. audit-event:: builtins.input prompt - Raises an :func:`auditing event ` ``builtins.input`` with + Raises an :ref:`auditing event ` ``builtins.input`` with argument ``prompt`` before reading input .. audit-event:: builtins.input/result result diff --git a/Doc/library/glob.rst b/Doc/library/glob.rst index 2a5f0ddc4e..1f29fc562d 100644 --- a/Doc/library/glob.rst +++ b/Doc/library/glob.rst @@ -52,6 +52,8 @@ For example, ``'[?]'`` matches the character ``'?'``. more directories and subdirectories. If the pattern is followed by an ``os.sep``, only directories and subdirectories match. + .. audit-event:: glob.glob "pathname recursive" + .. note:: Using the "``**``" pattern in large directory trees may consume an inordinate amount of time. @@ -65,6 +67,8 @@ For example, ``'[?]'`` matches the character ``'?'``. Return an :term:`iterator` which yields the same values as :func:`glob` without actually storing them all simultaneously. + .. audit-event:: glob.glob "pathname recursive" + .. function:: escape(pathname) diff --git a/Doc/library/imaplib.rst b/Doc/library/imaplib.rst index f027f82dde..c08c0a5591 100644 --- a/Doc/library/imaplib.rst +++ b/Doc/library/imaplib.rst @@ -361,6 +361,8 @@ An :class:`IMAP4` instance has the following methods: :meth:`IMAP4.send`, and :meth:`IMAP4.shutdown` methods. You may override this method. + .. audit-event:: imaplib.IMAP4.open "self host port" + .. method:: IMAP4.partial(message_num, message_part, start, length) @@ -430,6 +432,8 @@ An :class:`IMAP4` instance has the following methods: Sends ``data`` to the remote server. You may override this method. + .. audit-event:: imaplib.IMAP4.send "self data" + .. method:: IMAP4.setacl(mailbox, who, what) diff --git a/Doc/library/io.rst b/Doc/library/io.rst index 5ae30a3b58..28c5da96d9 100644 --- a/Doc/library/io.rst +++ b/Doc/library/io.rst @@ -122,7 +122,7 @@ High-level Module Interface .. audit-event:: open "path mode flags" - This function raises an :func:`auditing event ` ``open`` with + This function raises an :ref:`auditing event ` ``open`` with arguments ``path``, ``mode`` and ``flags``. The ``mode`` and ``flags`` arguments may have been modified or inferred from the original call. diff --git a/Doc/library/nntplib.rst b/Doc/library/nntplib.rst index 56188c7ef5..297bbedc86 100644 --- a/Doc/library/nntplib.rst +++ b/Doc/library/nntplib.rst @@ -79,6 +79,11 @@ The module itself defines the following classes: ('211 1755 1 1755 gmane.comp.python.committers', 1755, 1, 1755, 'gmane.comp.python.committers') >>> + .. audit-event:: nntplib.NNTP "self host port" + + All commands will raise an :ref:`auditing event ` + ``nntplib.NNTP.putline`` with arguments ``self`` and ``line``, + where ``line`` is the bytes about to be sent to the remote host. .. versionchanged:: 3.2 *usenetrc* is now ``False`` by default. @@ -100,6 +105,12 @@ The module itself defines the following classes: STARTTLS as described below. However, some servers only support the former. + .. audit-event:: nntplib.NNTP "self host port" + + All commands will raise an :ref:`auditing event ` + ``nntplib.NNTP.putline`` with arguments ``self`` and ``line``, + where ``line`` is the bytes about to be sent to the remote host. + .. versionadded:: 3.2 .. versionchanged:: 3.4 diff --git a/Doc/library/os.rst b/Doc/library/os.rst index f0df35e9dd..e7acb356d3 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1801,6 +1801,8 @@ features: This function can also support :ref:`specifying a file descriptor `; the file descriptor must refer to a directory. + .. audit-event:: os.listdir path + .. note:: To encode ``str`` filenames to ``bytes``, use :func:`~os.fsencode`. @@ -2178,6 +2180,8 @@ features: This function can also support :ref:`specifying a file descriptor `; the file descriptor must refer to a directory. + .. audit-event:: os.scandir path + The :func:`scandir` iterator supports the :term:`context manager` protocol and has the following method: diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst index c7864e9e3f..7ebad79130 100644 --- a/Doc/library/pdb.rst +++ b/Doc/library/pdb.rst @@ -181,6 +181,8 @@ access further features, you have to do this yourself: import pdb; pdb.Pdb(skip=['django.*']).set_trace() + .. audit-event:: pdb.Pdb + .. versionadded:: 3.1 The *skip* argument. diff --git a/Doc/library/poplib.rst b/Doc/library/poplib.rst index d72b660d6e..d227b53ff9 100644 --- a/Doc/library/poplib.rst +++ b/Doc/library/poplib.rst @@ -39,6 +39,12 @@ The :mod:`poplib` module provides two classes: connection attempt (if not specified, the global default timeout setting will be used). + .. audit-event:: poplib.POP3 "self host port" + + All commands will raise an :ref:`auditing event ` + ``poplib.POP3.putline`` with arguments ``self`` and ``line``, + where ``line`` is the bytes about to be sent to the remote host. + .. class:: POP3_SSL(host, port=POP3_SSL_PORT, keyfile=None, certfile=None, timeout=None, context=None) @@ -54,6 +60,12 @@ The :mod:`poplib` module provides two classes: point to PEM-formatted private key and certificate chain files, respectively, for the SSL connection. + .. audit-event:: poplib.POP3 "self host port" + + All commands will raise an :ref:`auditing event ` + ``poplib.POP3.putline`` with arguments ``self`` and ``line``, + where ``line`` is the bytes about to be sent to the remote host. + .. versionchanged:: 3.2 *context* parameter added. diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst index dcb2a16cff..3cca9c84a2 100644 --- a/Doc/library/shutil.rst +++ b/Doc/library/shutil.rst @@ -249,6 +249,8 @@ Directory and files operations   as arguments. By default, :func:`~shutil.copy2` is used, but any function   that supports the same signature (like :func:`~shutil.copy`) can be used. + .. audit-event:: shutil.copytree "src dst" + .. versionchanged:: 3.3 Copy metadata when *symlinks* is false. Now returns *dst*. @@ -296,6 +298,8 @@ Directory and files operations *excinfo*, will be the exception information returned by :func:`sys.exc_info`. Exceptions raised by *onerror* will not be caught. + .. audit-event:: shutil.rmtree path + .. versionchanged:: 3.3 Added a symlink attack resistant version that is used automatically if platform supports fd-based functions. @@ -558,6 +562,8 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules. The *verbose* argument is unused and deprecated. + .. audit-event:: shutil.make_archive "base_name format root_dir base_dir" + .. versionchanged:: 3.8 The modern pax (POSIX.1-2001) format is now used instead of the legacy GNU format for archives created with ``format="tar"``. diff --git a/Doc/library/smtplib.rst b/Doc/library/smtplib.rst index 2c3a5f0c6f..8771f10938 100644 --- a/Doc/library/smtplib.rst +++ b/Doc/library/smtplib.rst @@ -55,6 +55,10 @@ Protocol) and :rfc:`1869` (SMTP Service Extensions). (250, b'Ok') >>> + All commands will raise an :ref:`auditing event ` + ``smtplib.SMTP.send`` with arguments ``self`` and ``data``, + where ``data`` is the bytes about to be sent to the remote host. + .. versionchanged:: 3.3 Support for the :keyword:`with` statement was added. @@ -242,6 +246,8 @@ An :class:`SMTP` instance has the following methods: 2-tuple of the response code and message sent by the server in its connection response. + .. audit-event:: smtplib.SMTP.connect "self host port" + .. method:: SMTP.helo(name='') diff --git a/Doc/library/sqlite3.rst b/Doc/library/sqlite3.rst index 20fca54aab..e0411fed2f 100644 --- a/Doc/library/sqlite3.rst +++ b/Doc/library/sqlite3.rst @@ -224,6 +224,8 @@ Module functions and constants More information about this feature, including a list of recognized options, can be found in the `SQLite URI documentation `_. + .. audit-event:: sqlite3.connect "database" + .. versionchanged:: 3.4 Added the *uri* parameter. diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index ede5c3c5a3..ad49d7f201 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -585,6 +585,13 @@ functions. with Popen(["ifconfig"], stdout=PIPE) as proc: log.write(proc.stdout.read()) + .. audit-event:: subprocess.Popen "executable args cwd env" + + Popen and the other functions in this module that use it raise an + :ref:`auditing event ` ``subprocess.Popen`` with arguments + ``executable``, ``args``, ``cwd``, ``env``. The value for ``args`` + may be a single string or a list of strings, depending on platform. + .. versionchanged:: 3.2 Added context manager support. diff --git a/Doc/library/telnetlib.rst b/Doc/library/telnetlib.rst index 4ba4264252..d238136567 100644 --- a/Doc/library/telnetlib.rst +++ b/Doc/library/telnetlib.rst @@ -141,6 +141,8 @@ Telnet Objects Do not try to reopen an already connected instance. + .. audit-event:: telnetlib.Telnet.open "self host port" + .. method:: Telnet.msg(msg, *args) @@ -176,6 +178,8 @@ Telnet Objects block if the connection is blocked. May raise :exc:`OSError` if the connection is closed. + .. audit-event:: telnetlib.Telnet.write "self buffer" + .. versionchanged:: 3.3 This method used to raise :exc:`socket.error`, which is now an alias of :exc:`OSError`. diff --git a/Doc/library/tempfile.rst b/Doc/library/tempfile.rst index daa6f621f1..98069f2442 100644 --- a/Doc/library/tempfile.rst +++ b/Doc/library/tempfile.rst @@ -62,6 +62,8 @@ The module defines the following user-callable items: The :py:data:`os.O_TMPFILE` flag is used if it is available and works (Linux-specific, requires Linux kernel 3.11 or later). + .. audit-event:: tempfile.mkstemp "full-path" + .. versionchanged:: 3.5 The :py:data:`os.O_TMPFILE` flag is now used if available. @@ -85,6 +87,8 @@ The module defines the following user-callable items: attribute is the underlying true file object. This file-like object can be used in a :keyword:`with` statement, just like a normal file. + .. audit-event:: tempfile.mkstemp "full-path" + .. versionchanged:: 3.8 Added *errors* parameter. @@ -130,6 +134,8 @@ The module defines the following user-callable items: The directory can be explicitly cleaned up by calling the :func:`cleanup` method. + .. audit-event:: tempfile.mkdtemp "full-path" + .. versionadded:: 3.2 @@ -177,6 +183,8 @@ The module defines the following user-callable items: file (as would be returned by :func:`os.open`) and the absolute pathname of that file, in that order. + .. audit-event:: tempfile.mkstemp "full-path" + .. versionchanged:: 3.5 *suffix*, *prefix*, and *dir* may now be supplied in bytes in order to obtain a bytes return value. Prior to this, only str was allowed. @@ -198,6 +206,8 @@ The module defines the following user-callable items: :func:`mkdtemp` returns the absolute pathname of the new directory. + .. audit-event:: tempfile.mkdtemp "full-path" + .. versionchanged:: 3.5 *suffix*, *prefix*, and *dir* may now be supplied in bytes in order to obtain a bytes return value. Prior to this, only str was allowed. diff --git a/Doc/library/urllib.request.rst b/Doc/library/urllib.request.rst index a53c969ec6..9f8869c87f 100644 --- a/Doc/library/urllib.request.rst +++ b/Doc/library/urllib.request.rst @@ -97,7 +97,7 @@ The :mod:`urllib.request` module defines the following functions: .. audit-event:: urllib.Request "fullurl data headers method" - The default opener raises an :func:`auditing event ` + The default opener raises an :ref:`auditing event ` ``urllib.Request`` with arguments ``fullurl``, ``data``, ``headers``, ``method`` taken from the request object. diff --git a/Doc/library/webbrowser.rst b/Doc/library/webbrowser.rst index 9dc5551398..85e932d5a2 100644 --- a/Doc/library/webbrowser.rst +++ b/Doc/library/webbrowser.rst @@ -64,6 +64,8 @@ The following functions are defined: may work and start the operating system's associated program. However, this is neither supported nor portable. + .. audit-event:: webbrowser.open "url" + .. function:: open_new(url) diff --git a/Doc/tools/extensions/suspicious.py b/Doc/tools/extensions/suspicious.py index 494efabc46..34a0112f5a 100644 --- a/Doc/tools/extensions/suspicious.py +++ b/Doc/tools/extensions/suspicious.py @@ -115,8 +115,8 @@ class CheckSuspiciousMarkupBuilder(Builder): def finish(self): unused_rules = [rule for rule in self.rules if not rule.used] if unused_rules: - self.warn('Found %s/%s unused rules:' % - (len(unused_rules), len(self.rules))) + self.logger.warn('Found %s/%s unused rules:' % + (len(unused_rules), len(self.rules))) for rule in unused_rules: self.logger.info(repr(rule)) return @@ -151,10 +151,10 @@ class CheckSuspiciousMarkupBuilder(Builder): self.any_issue = True self.write_log_entry(lineno, issue, text) if py3: - self.warn('[%s:%d] "%s" found in "%-.120s"' % - (self.docname, lineno, issue, text)) + self.logger.warn('[%s:%d] "%s" found in "%-.120s"' % + (self.docname, lineno, issue, text)) else: - self.warn('[%s:%d] "%s" found in "%-.120s"' % ( + self.logger.warn('[%s:%d] "%s" found in "%-.120s"' % ( self.docname.encode(sys.getdefaultencoding(),'replace'), lineno, issue.encode(sys.getdefaultencoding(),'replace'), diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index 526dfd004a..6f2569da81 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -73,6 +73,8 @@ def _bootstrap(*, root=None, upgrade=False, user=False, if altinstall and default_pip: raise ValueError("Cannot use altinstall and default_pip together") + sys.audit("ensurepip.bootstrap", root) + _disable_pip_configuration_settings() # By default, installing pip and setuptools installs all of the diff --git a/Lib/ftplib.py b/Lib/ftplib.py index a9b1aee39e..27bf6daea6 100644 --- a/Lib/ftplib.py +++ b/Lib/ftplib.py @@ -148,6 +148,7 @@ class FTP: self.timeout = timeout if source_address is not None: self.source_address = source_address + sys.audit("ftplib.FTP.connect", self, self.host, self.port) self.sock = socket.create_connection((self.host, self.port), self.timeout, source_address=self.source_address) self.af = self.sock.family @@ -188,6 +189,7 @@ class FTP: def putline(self, line): if '\r' in line or '\n' in line: raise ValueError('an illegal newline character should not be contained') + sys.audit("ftplib.FTP.sendcmd", self, line) line = line + CRLF if self.debugging > 1: print('*put*', self.sanitize(line)) diff --git a/Lib/glob.py b/Lib/glob.py index 002cd92019..0b3fcc6bbb 100644 --- a/Lib/glob.py +++ b/Lib/glob.py @@ -3,6 +3,7 @@ import os import re import fnmatch +import sys __all__ = ["glob", "iglob", "escape"] @@ -37,6 +38,7 @@ def iglob(pathname, *, recursive=False): return it def _iglob(pathname, recursive, dironly): + sys.audit("glob.glob", pathname, recursive) dirname, basename = os.path.split(pathname) if not has_magic(pathname): assert not dironly diff --git a/Lib/imaplib.py b/Lib/imaplib.py index 341ee25ae9..face45ba5f 100644 --- a/Lib/imaplib.py +++ b/Lib/imaplib.py @@ -289,6 +289,7 @@ class IMAP4: # (which is used by socket.create_connection()) expects None # as a default value for host. host = None if not self.host else self.host + sys.audit("imaplib.IMAP4.open", self, self.host, self.port) return socket.create_connection((host, self.port)) def open(self, host = '', port = IMAP4_PORT): @@ -318,6 +319,7 @@ class IMAP4: def send(self, data): """Send data to remote.""" + sys.audit("imaplib.IMAP4.send", self, data) self.sock.sendall(data) diff --git a/Lib/nntplib.py b/Lib/nntplib.py index 5961a28ab7..e7bbc853c0 100644 --- a/Lib/nntplib.py +++ b/Lib/nntplib.py @@ -68,6 +68,7 @@ import socket import collections import datetime import warnings +import sys try: import ssl @@ -413,6 +414,7 @@ class _NNTPBase: def _putline(self, line): """Internal: send one line to the server, appending CRLF. The `line` must be a bytes-like object.""" + sys.audit("nntplib.NNTP.putline", self, line) line = line + _CRLF if self.debugging > 1: print('*put*', repr(line)) self.file.write(line) @@ -1040,6 +1042,7 @@ class NNTP(_NNTPBase): """ self.host = host self.port = port + sys.audit("nntplib.NNTP", self, host, port) self.sock = socket.create_connection((host, port), timeout) file = None try: @@ -1071,6 +1074,7 @@ if _have_ssl: """This works identically to NNTP.__init__, except for the change in default port and the `ssl_context` argument for SSL connections. """ + sys.audit("nntplib.NNTP", self, host, port) self.sock = socket.create_connection((host, port), timeout) file = None try: diff --git a/Lib/pdb.py b/Lib/pdb.py index 0e7609e43d..5e62f392d9 100755 --- a/Lib/pdb.py +++ b/Lib/pdb.py @@ -141,6 +141,7 @@ class Pdb(bdb.Bdb, cmd.Cmd): nosigint=False, readrc=True): bdb.Bdb.__init__(self, skip=skip) cmd.Cmd.__init__(self, completekey, stdin, stdout) + sys.audit("pdb.Pdb") if stdout: self.use_rawinput = 0 self.prompt = '(Pdb) ' diff --git a/Lib/poplib.py b/Lib/poplib.py index 9796f0d2f9..ced0a2d53c 100644 --- a/Lib/poplib.py +++ b/Lib/poplib.py @@ -16,6 +16,7 @@ Based on the J. Myers POP3 draft, Jan. 96 import errno import re import socket +import sys try: import ssl @@ -99,6 +100,7 @@ class POP3: self.host = host self.port = port self._tls_established = False + sys.audit("poplib.POP3", self, host, port) self.sock = self._create_socket(timeout) self.file = self.sock.makefile('rb') self._debugging = 0 @@ -109,6 +111,7 @@ class POP3: def _putline(self, line): if self._debugging > 1: print('*put*', repr(line)) + sys.audit("poplib.POP3.putline", self, line) self.sock.sendall(line + CRLF) diff --git a/Lib/shutil.py b/Lib/shutil.py index 6486cd6e5d..ab1a7d6189 100644 --- a/Lib/shutil.py +++ b/Lib/shutil.py @@ -530,6 +530,7 @@ def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, function that supports the same signature (like copy()) can be used. """ + sys.audit("shutil.copytree", src, dst) with os.scandir(src) as entries: return _copytree(entries=entries, src=src, dst=dst, symlinks=symlinks, ignore=ignore, copy_function=copy_function, @@ -640,6 +641,7 @@ def rmtree(path, ignore_errors=False, onerror=None): is false and onerror is None, an exception is raised. """ + sys.audit("shutil.rmtree", path) if ignore_errors: def onerror(*args): pass @@ -965,6 +967,7 @@ def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0, 'owner' and 'group' are used when creating a tar archive. By default, uses the current owner and group. """ + sys.audit("shutil.make_archive", base_name, format, root_dir, base_dir) save_cwd = os.getcwd() if root_dir is not None: if logger is not None: diff --git a/Lib/smtplib.py b/Lib/smtplib.py index 3c5ac75ab8..01f3d4386f 100755 --- a/Lib/smtplib.py +++ b/Lib/smtplib.py @@ -335,6 +335,7 @@ class SMTP: port = self.default_port if self.debuglevel > 0: self._print_debug('connect:', (host, port)) + sys.audit("smtplib.SMTP.connect", self, host, port) self.sock = self._get_socket(host, port, self.timeout) self.file = None (code, msg) = self.getreply() @@ -352,6 +353,7 @@ class SMTP: # should not be used, but 'data' needs to convert the string to # binary itself anyway, so that's not a problem. s = s.encode(self.command_encoding) + sys.audit("smtplib.SMTP.send", self, s) try: self.sock.sendall(s) except OSError: diff --git a/Lib/subprocess.py b/Lib/subprocess.py index d34c57828b..c0bda96cbc 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -1268,6 +1268,11 @@ class Popen(object): comspec = os.environ.get("COMSPEC", "cmd.exe") args = '{} /c "{}"'.format (comspec, args) + if cwd is not None: + cwd = os.fsdecode(cwd) + + sys.audit("subprocess.Popen", executable, args, cwd, env) + # Start the process try: hp, ht, pid, tid = _winapi.CreateProcess(executable, args, @@ -1276,7 +1281,7 @@ class Popen(object): int(not close_fds), creationflags, env, - os.fsdecode(cwd) if cwd is not None else None, + cwd, startupinfo) finally: # Child is launched. Close the parent's copy of those pipe @@ -1543,6 +1548,8 @@ class Popen(object): if executable is None: executable = args[0] + sys.audit("subprocess.Popen", executable, args, cwd, env) + if (_USE_POSIX_SPAWN and os.path.dirname(executable) and preexec_fn is None diff --git a/Lib/telnetlib.py b/Lib/telnetlib.py index b9d45b48e7..8ce053e881 100644 --- a/Lib/telnetlib.py +++ b/Lib/telnetlib.py @@ -231,6 +231,7 @@ class Telnet: self.host = host self.port = port self.timeout = timeout + sys.audit("telnetlib.Telnet.open", self, host, port) self.sock = socket.create_connection((host, port), timeout) def __del__(self): @@ -286,6 +287,7 @@ class Telnet: """ if IAC in buffer: buffer = buffer.replace(IAC, IAC+IAC) + sys.audit("telnetlib.Telnet.write", self, buffer) self.msg("send %r", buffer) self.sock.sendall(buffer) diff --git a/Lib/tempfile.py b/Lib/tempfile.py index e8b111eae2..45709cb06c 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -43,6 +43,7 @@ import os as _os import shutil as _shutil import errno as _errno from random import Random as _Random +import sys as _sys import weakref as _weakref import _thread _allocate_lock = _thread.allocate_lock @@ -244,6 +245,7 @@ def _mkstemp_inner(dir, pre, suf, flags, output_type): for seq in range(TMP_MAX): name = next(names) file = _os.path.join(dir, pre + name + suf) + _sys.audit("tempfile.mkstemp", file) try: fd = _os.open(file, flags, 0o600) except FileExistsError: @@ -352,6 +354,7 @@ def mkdtemp(suffix=None, prefix=None, dir=None): for seq in range(TMP_MAX): name = next(names) file = _os.path.join(dir, prefix + name + suffix) + _sys.audit("tempfile.mkdtemp", file) try: _os.mkdir(file, 0o700) except FileExistsError: @@ -546,7 +549,7 @@ def NamedTemporaryFile(mode='w+b', buffering=-1, encoding=None, _os.close(fd) raise -if _os.name != 'posix' or _os.sys.platform == 'cygwin': +if _os.name != 'posix' or _sys.platform == 'cygwin': # On non-POSIX and Cygwin systems, assume that we cannot unlink a file # while it is open. TemporaryFile = NamedTemporaryFile diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py index 82bff835fd..0af36c4301 100755 --- a/Lib/webbrowser.py +++ b/Lib/webbrowser.py @@ -154,6 +154,7 @@ class GenericBrowser(BaseBrowser): self.basename = os.path.basename(self.name) def open(self, url, new=0, autoraise=True): + sys.audit("webbrowser.open", url) cmdline = [self.name] + [arg.replace("%s", url) for arg in self.args] try: @@ -173,6 +174,7 @@ class BackgroundBrowser(GenericBrowser): def open(self, url, new=0, autoraise=True): cmdline = [self.name] + [arg.replace("%s", url) for arg in self.args] + sys.audit("webbrowser.open", url) try: if sys.platform[:3] == 'win': p = subprocess.Popen(cmdline) @@ -201,7 +203,7 @@ class UnixBrowser(BaseBrowser): remote_action_newwin = None remote_action_newtab = None - def _invoke(self, args, remote, autoraise): + def _invoke(self, args, remote, autoraise, url=None): raise_opt = [] if remote and self.raise_opts: # use autoraise argument only for remote invocation @@ -237,6 +239,7 @@ class UnixBrowser(BaseBrowser): return not p.wait() def open(self, url, new=0, autoraise=True): + sys.audit("webbrowser.open", url) if new == 0: action = self.remote_action elif new == 1: @@ -253,7 +256,7 @@ class UnixBrowser(BaseBrowser): args = [arg.replace("%s", url).replace("%action", action) for arg in self.remote_args] args = [arg for arg in args if arg] - success = self._invoke(args, True, autoraise) + success = self._invoke(args, True, autoraise, url) if not success: # remote invocation failed, try straight way args = [arg.replace("%s", url) for arg in self.args] @@ -337,6 +340,7 @@ class Konqueror(BaseBrowser): """ def open(self, url, new=0, autoraise=True): + sys.audit("webbrowser.open", url) # XXX Currently I know no way to prevent KFM from opening a new win. if new == 2: action = "newTab" @@ -420,6 +424,7 @@ class Grail(BaseBrowser): return 1 def open(self, url, new=0, autoraise=True): + sys.audit("webbrowser.open", url) if new: ok = self._remote("LOADNEW " + url) else: @@ -577,6 +582,7 @@ def register_standard_browsers(): if sys.platform[:3] == "win": class WindowsDefault(BaseBrowser): def open(self, url, new=0, autoraise=True): + sys.audit("webbrowser.open", url) try: os.startfile(url) except OSError: @@ -606,6 +612,7 @@ if sys.platform == 'darwin': self.name = name def open(self, url, new=0, autoraise=True): + sys.audit("webbrowser.open", url) assert "'" not in url # hack for local urls if not ':' in url: diff --git a/Misc/NEWS.d/next/Security/2019-06-21-15-58-59.bpo-37363.diouyl.rst b/Misc/NEWS.d/next/Security/2019-06-21-15-58-59.bpo-37363.diouyl.rst new file mode 100644 index 0000000000..1b724ff559 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2019-06-21-15-58-59.bpo-37363.diouyl.rst @@ -0,0 +1,5 @@ +Adds audit events for :mod:`ensurepip`, :mod:`ftplib`, :mod:`glob`, +:mod:`imaplib`, :mod:`nntplib`, :mod:`pdb`, :mod:`poplib`, :mod:`shutil`, +:mod:`smtplib`, :mod:`sqlite3`, :mod:`subprocess`, :mod:`telnetlib`, +:mod:`tempfile` and :mod:`webbrowser`, as well as :func:`os.listdir`, +:func:`os.scandir` and :func:`breakpoint`. diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c index c487ba9890..9fe0dc952f 100644 --- a/Modules/_sqlite/module.c +++ b/Modules/_sqlite/module.c @@ -85,6 +85,10 @@ static PyObject* module_connect(PyObject* self, PyObject* args, PyObject* factory = (PyObject*)&pysqlite_ConnectionType; } + if (PySys_Audit("sqlite3.connect", "O", database) < 0) { + return NULL; + } + result = PyObject_Call(factory, args, kwargs); return result; diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index dff6309ac6..b2fd45b901 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -3759,6 +3759,10 @@ static PyObject * os_listdir_impl(PyObject *module, path_t *path) /*[clinic end generated code: output=293045673fcd1a75 input=e3f58030f538295d]*/ { + if (PySys_Audit("os.listdir", "O", + path->object ? path->object : Py_None) < 0) { + return NULL; + } #if defined(MS_WINDOWS) && !defined(HAVE_OPENDIR) return _listdir_windows_no_opendir(path, NULL); #else @@ -13164,6 +13168,11 @@ os_scandir_impl(PyObject *module, path_t *path) #endif #endif + if (PySys_Audit("os.scandir", "O", + path->object ? path->object : Py_None) < 0) { + return NULL; + } + iterator = PyObject_New(ScandirIterator, &ScandirIteratorType); if (!iterator) return NULL; diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index ae2a5187d9..90fbb44882 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -482,6 +482,11 @@ builtin_breakpoint(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyOb PyErr_SetString(PyExc_RuntimeError, "lost sys.breakpointhook"); return NULL; } + + if (PySys_Audit("builtins.breakpoint", "O", hook) < 0) { + return NULL; + } + Py_INCREF(hook); PyObject *retval = _PyObject_Vectorcall(hook, args, nargs, keywords); Py_DECREF(hook); -- 2.40.0