[3.13] gh-132124: improve safety nets for creating AF_UNIX socket fil… · python/cpython@932221b

GitHub

@@ -34,6 +34,7 @@

3434DEBUG=10

3535INFO=20

3636SUBWARNING=25

37+WARNING=30

37383839LOGGER_NAME='multiprocessing'

3940DEFAULT_LOGGING_FORMAT='[%(levelname)s/%(processName)s] %(message)s'

@@ -53,6 +54,10 @@ def info(msg, *args):

5354if_logger:

5455_logger.log(INFO, msg, *args, stacklevel=2)

555657+def_warn(msg, *args):

58+if_logger:

59+_logger.log(WARNING, msg, *args, stacklevel=2)

60+5661defsub_warning(msg, *args):

5762if_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#

123128129+# 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+ifsys.platform=='linux':

137+_SUN_PATH_MAX=108

138+elifsys.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=Noneifos.name=='nt'else92

143+124144def_remove_temp_dir(rmtree, tempdir):

125145rmtree(tempdir)

126146@@ -130,12 +150,67 @@ def _remove_temp_dir(rmtree, tempdir):

130150ifcurrent_processisnotNone:

131151current_process._config['tempdir'] =None

132152153+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+ifos.name=='nt':

159+returnNone

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+ifsun_path_len<=_SUN_PATH_MAX:

179+returnbase_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+exceptFileNotFoundError:

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+returnbase_tempdir

202+_warn("Ignoring user-defined temporary directory: %s", base_tempdir)

203+# at most max(map(len, dirlist)) + 14 + 14 = 36 characters

204+assertlen(base_system_tempdir) +14+14<=_SUN_PATH_MAX

205+returnbase_system_tempdir

206+133207defget_temp_dir():

134208# get name of a temp directory which will be automatically cleaned up

135209tempdir=process.current_process()._config.get('tempdir')

136210iftempdirisNone:

137211importshutil, tempfile

138-tempdir=tempfile.mkdtemp(prefix='pymp-')

212+base_tempdir=_get_base_temp_dir(tempfile)

213+tempdir=tempfile.mkdtemp(prefix='pymp-', dir=base_tempdir)

139214info('created temp directory %s', tempdir)

140215# keep a strong reference to shutil.rmtree(), since the finalizer

141216# can be called late during Python shutdown