summaryrefslogtreecommitdiffstats
path: root/Doc
diff options
context:
space:
mode:
authorSteve Dower <steve.dower@microsoft.com>2019-03-29 23:37:16 (GMT)
committerGitHub <noreply@github.com>2019-03-29 23:37:16 (GMT)
commit2438cdf0e932a341c7613bf4323d06b91ae9f1f1 (patch)
tree231cdf3f22e1d5eb9f88fe7a511ab47e3cf8d225 /Doc
parent32119e10b792ad7ee4e5f951a2d89ddbaf111cc5 (diff)
downloadcpython-2438cdf0e932a341c7613bf4323d06b91ae9f1f1.zip
cpython-2438cdf0e932a341c7613bf4323d06b91ae9f1f1.tar.gz
cpython-2438cdf0e932a341c7613bf4323d06b91ae9f1f1.tar.bz2
bpo-36085: Enable better DLL resolution on Windows (GH-12302)
Diffstat (limited to 'Doc')
-rw-r--r--Doc/library/ctypes.rst17
-rw-r--r--Doc/library/os.rst30
-rw-r--r--Doc/whatsnew/3.8.rst30
3 files changed, 74 insertions, 3 deletions
diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst
index 500aad8..baab0de 100644
--- a/Doc/library/ctypes.rst
+++ b/Doc/library/ctypes.rst
@@ -1322,14 +1322,14 @@ There are several ways to load shared libraries into the Python process. One
way is to instantiate one of the following classes:
-.. class:: CDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False)
+.. class:: CDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=0)
Instances of this class represent loaded shared libraries. Functions in these
libraries use the standard C calling convention, and are assumed to return
:c:type:`int`.
-.. class:: OleDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False)
+.. class:: OleDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=0)
Windows only: Instances of this class represent loaded shared libraries,
functions in these libraries use the ``stdcall`` calling convention, and are
@@ -1342,7 +1342,7 @@ way is to instantiate one of the following classes:
:exc:`WindowsError` used to be raised.
-.. class:: WinDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False)
+.. class:: WinDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=0)
Windows only: Instances of this class represent loaded shared libraries,
functions in these libraries use the ``stdcall`` calling convention, and are
@@ -1394,6 +1394,17 @@ the Windows error code which is managed by the :func:`GetLastError` and
:func:`ctypes.set_last_error` are used to request and change the ctypes private
copy of the windows error code.
+The *winmode* parameter is used on Windows to specify how the library is loaded
+(since *mode* is ignored). It takes any value that is valid for the Win32 API
+``LoadLibraryEx`` flags parameter. When omitted, the default is to use the flags
+that result in the most secure DLL load to avoiding issues such as DLL
+hijacking. Passing the full path to the DLL is the safest way to ensure the
+correct library and dependencies are loaded.
+
+.. versionchanged:: 3.8
+ Added *winmode* parameter.
+
+
.. data:: RTLD_GLOBAL
:noindex:
diff --git a/Doc/library/os.rst b/Doc/library/os.rst
index f8803af..85e240a 100644
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -3079,6 +3079,36 @@ to be ignored.
:func:`signal.signal`.
+.. function:: add_dll_directory(path)
+
+ Add a path to the DLL search path.
+
+ This search path is used when resolving dependencies for imported
+ extension modules (the module itself is resolved through sys.path),
+ and also by :mod:`ctypes`.
+
+ Remove the directory by calling **close()** on the returned object
+ or using it in a :keyword:`with` statement.
+
+ See the `Microsoft documentation
+ <https://msdn.microsoft.com/44228cf2-6306-466c-8f16-f513cd3ba8b5>`_
+ for more information about how DLLs are loaded.
+
+ .. availability:: Windows.
+
+ .. versionadded:: 3.8
+ Previous versions of CPython would resolve DLLs using the default
+ behavior for the current process. This led to inconsistencies,
+ such as only sometimes searching :envvar:`PATH` or the current
+ working directory, and OS functions such as ``AddDllDirectory``
+ having no effect.
+
+ In 3.8, the two primary ways DLLs are loaded now explicitly
+ override the process-wide behavior to ensure consistency. See the
+ :ref:`porting notes <bpo-36085-whatsnew>` for information on
+ updating libraries.
+
+
.. function:: execl(path, arg0, arg1, ...)
execle(path, arg0, arg1, ..., env)
execlp(file, arg0, arg1, ...)
diff --git a/Doc/whatsnew/3.8.rst b/Doc/whatsnew/3.8.rst
index 0ffbcab..f0423c3 100644
--- a/Doc/whatsnew/3.8.rst
+++ b/Doc/whatsnew/3.8.rst
@@ -168,6 +168,16 @@ asyncio
On Windows, the default event loop is now :class:`~asyncio.ProactorEventLoop`.
+ctypes
+------
+
+On Windows, :class:`~ctypes.CDLL` and subclasses now accept a *winmode* parameter
+to specify flags for the underlying ``LoadLibraryEx`` call. The default flags are
+set to only load DLL dependencies from trusted locations, including the path
+where the DLL is stored (if a full or partial path is used to load the initial
+DLL) and paths added by :func:`~os.add_dll_directory`.
+
+
gettext
-------
@@ -238,6 +248,13 @@ Added new function, :func:`math.prod`, as analogous function to :func:`sum`
that returns the product of a 'start' value (default: 1) times an iterable of
numbers. (Contributed by Pablo Galindo in :issue:`35606`)
+os
+--
+
+Added new function :func:`~os.add_dll_directory` on Windows for providing
+additional search paths for native dependencies when importing extension
+modules or loading DLLs using :mod:`ctypes`.
+
os.path
-------
@@ -727,6 +744,19 @@ Changes in the Python API
environment variable and does not use :envvar:`HOME`, which is not normally
set for regular user accounts.
+.. _bpo-36085-whatsnew:
+
+* DLL dependencies for extension modules and DLLs loaded with :mod:`ctypes` on
+ Windows are now resolved more securely. Only the system paths, the directory
+ containing the DLL or PYD file, and directories added with
+ :func:`~os.add_dll_directory` are searched for load-time dependencies.
+ Specifically, :envvar:`PATH` and the current working directory are no longer
+ used, and modifications to these will no longer have any effect on normal DLL
+ resolution. If your application relies on these mechanisms, you should check
+ for :func:`~os.add_dll_directory` and if it exists, use it to add your DLLs
+ directory while loading your library.
+ (See :issue:`36085`.)
+
Changes in the C API
--------------------