Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f8ced87

Browse filesBrowse files
[3.14] gh-132124: improve safety nets for creating AF_UNIX socket files (GH-134085) (#134447)
gh-132124: improve safety nets for creating AF_UNIX socket files (GH-134085) * ensure that we can create AF_UNIX socket files * emit a warning if system-wide temporary directory is used (cherry picked from commit 1a07a01) Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
1 parent df6d9e7 commit f8ced87
Copy full SHA for f8ced87

File tree

Expand file treeCollapse file tree

4 files changed

+87
-5
lines changed
Filter options
Expand file treeCollapse file tree

4 files changed

+87
-5
lines changed

‎Lib/multiprocessing/connection.py

Copy file name to clipboardExpand all lines: Lib/multiprocessing/connection.py
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ def arbitrary_address(family):
7676
if family == 'AF_INET':
7777
return ('localhost', 0)
7878
elif family == 'AF_UNIX':
79-
return tempfile.mktemp(prefix='listener-', dir=util.get_temp_dir())
79+
return tempfile.mktemp(prefix='sock-', dir=util.get_temp_dir())
8080
elif family == 'AF_PIPE':
8181
return tempfile.mktemp(prefix=r'\\.\pipe\pyc-%d-%d-' %
8282
(os.getpid(), next(_mmap_counter)), dir="")

‎Lib/multiprocessing/util.py

Copy file name to clipboardExpand all lines: Lib/multiprocessing/util.py
+77-2Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from . import process
2020

2121
__all__ = [
22-
'sub_debug', 'debug', 'info', 'sub_warning', 'get_logger',
22+
'sub_debug', 'debug', 'info', 'sub_warning', 'warn', 'get_logger',
2323
'log_to_stderr', 'get_temp_dir', 'register_after_fork',
2424
'is_exiting', 'Finalize', 'ForkAwareThreadLock', 'ForkAwareLocal',
2525
'close_all_fds_except', 'SUBDEBUG', 'SUBWARNING',
@@ -34,6 +34,7 @@
3434
DEBUG = 10
3535
INFO = 20
3636
SUBWARNING = 25
37+
WARNING = 30
3738

3839
LOGGER_NAME = 'multiprocessing'
3940
DEFAULT_LOGGING_FORMAT = '[%(levelname)s/%(processName)s] %(message)s'
@@ -53,6 +54,10 @@ def info(msg, *args):
5354
if _logger:
5455
_logger.log(INFO, msg, *args, stacklevel=2)
5556

57+
def warn(msg, *args):
58+
if _logger:
59+
_logger.log(WARNING, msg, *args, stacklevel=2)
60+
5661
def sub_warning(msg, *args):
5762
if _logger:
5863
_logger.log(SUBWARNING, msg, *args, stacklevel=2)
@@ -121,6 +126,21 @@ def is_abstract_socket_namespace(address):
121126
# Function returning a temp directory which will be removed on exit
122127
#
123128

129+
# Maximum length of a socket file path is usually between 92 and 108 [1],
130+
# but Linux is known to use a size of 108 [2]. BSD-based systems usually
131+
# use a size of 104 or 108 and Windows does not create AF_UNIX sockets.
132+
#
133+
# [1]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_un.h.html
134+
# [2]: https://man7.org/linux/man-pages/man7/unix.7.html.
135+
136+
if sys.platform == 'linux':
137+
_SUN_PATH_MAX = 108
138+
elif sys.platform.startswith(('openbsd', 'freebsd')):
139+
_SUN_PATH_MAX = 104
140+
else:
141+
# On Windows platforms, we do not create AF_UNIX sockets.
142+
_SUN_PATH_MAX = None if os.name == 'nt' else 92
143+
124144
def _remove_temp_dir(rmtree, tempdir):
125145
rmtree(tempdir)
126146

@@ -130,12 +150,67 @@ def _remove_temp_dir(rmtree, tempdir):
130150
if current_process is not None:
131151
current_process._config['tempdir'] = None
132152

153+
def _get_base_temp_dir(tempfile):
154+
"""Get a temporary directory where socket files will be created.
155+
156+
To prevent additional imports, pass a pre-imported 'tempfile' module.
157+
"""
158+
if os.name == 'nt':
159+
return None
160+
# Most of the time, the default temporary directory is /tmp. Thus,
161+
# listener sockets files "$TMPDIR/pymp-XXXXXXXX/sock-XXXXXXXX" do
162+
# not have a path length exceeding SUN_PATH_MAX.
163+
#
164+
# If users specify their own temporary directory, we may be unable
165+
# to create those files. Therefore, we fall back to the system-wide
166+
# temporary directory /tmp, assumed to exist on POSIX systems.
167+
#
168+
# See https://github.com/python/cpython/issues/132124.
169+
base_tempdir = tempfile.gettempdir()
170+
# Files created in a temporary directory are suffixed by a string
171+
# generated by tempfile._RandomNameSequence, which, by design,
172+
# is 8 characters long.
173+
#
174+
# Thus, the length of socket filename will be:
175+
#
176+
# len(base_tempdir + '/pymp-XXXXXXXX' + '/sock-XXXXXXXX')
177+
sun_path_len = len(base_tempdir) + 14 + 14
178+
if sun_path_len <= _SUN_PATH_MAX:
179+
return base_tempdir
180+
# Fallback to the default system-wide temporary directory.
181+
# This ignores user-defined environment variables.
182+
#
183+
# On POSIX systems, /tmp MUST be writable by any application [1].
184+
# We however emit a warning if this is not the case to prevent
185+
# obscure errors later in the execution.
186+
#
187+
# On some legacy systems, /var/tmp and /usr/tmp can be present
188+
# and will be used instead.
189+
#
190+
# [1]: https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch03s18.html
191+
dirlist = ['/tmp', '/var/tmp', '/usr/tmp']
192+
try:
193+
base_system_tempdir = tempfile._get_default_tempdir(dirlist)
194+
except FileNotFoundError:
195+
warn("Process-wide temporary directory %s will not be usable for "
196+
"creating socket files and no usable system-wide temporary "
197+
"directory was found in %s", base_tempdir, dirlist)
198+
# At this point, the system-wide temporary directory is not usable
199+
# but we may assume that the user-defined one is, even if we will
200+
# not be able to write socket files out there.
201+
return base_tempdir
202+
warn("Ignoring user-defined temporary directory: %s", base_tempdir)
203+
# at most max(map(len, dirlist)) + 14 + 14 = 36 characters
204+
assert len(base_system_tempdir) + 14 + 14 <= _SUN_PATH_MAX
205+
return base_system_tempdir
206+
133207
def get_temp_dir():
134208
# get name of a temp directory which will be automatically cleaned up
135209
tempdir = process.current_process()._config.get('tempdir')
136210
if tempdir is None:
137211
import shutil, tempfile
138-
tempdir = tempfile.mkdtemp(prefix='pymp-')
212+
base_tempdir = _get_base_temp_dir(tempfile)
213+
tempdir = tempfile.mkdtemp(prefix='pymp-', dir=base_tempdir)
139214
info('created temp directory %s', tempdir)
140215
# keep a strong reference to shutil.rmtree(), since the finalizer
141216
# can be called late during Python shutdown

‎Lib/tempfile.py

Copy file name to clipboardExpand all lines: Lib/tempfile.py
+3-2Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ def _candidate_tempdir_list():
180180

181181
return dirlist
182182

183-
def _get_default_tempdir():
183+
def _get_default_tempdir(dirlist=None):
184184
"""Calculate the default directory to use for temporary files.
185185
This routine should be called exactly once.
186186
@@ -190,7 +190,8 @@ def _get_default_tempdir():
190190
service, the name of the test file must be randomized."""
191191

192192
namer = _RandomNameSequence()
193-
dirlist = _candidate_tempdir_list()
193+
if dirlist is None:
194+
dirlist = _candidate_tempdir_list()
194195

195196
for dir in dirlist:
196197
if dir != _os.curdir:
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
On POSIX-compliant systems, :func:`!multiprocessing.util.get_temp_dir` now
2+
ignores :envvar:`TMPDIR` (and similar environment variables) if the path
3+
length of ``AF_UNIX`` socket files exceeds the platform-specific maximum
4+
length when using the :ref:`forkserver
5+
<multiprocessing-start-method-forkserver>` start method. Patch by Bénédikt
6+
Tran.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.