Skip to content

Commit a53c01f

Browse files
committed
Minor edits per @.picnixz code review comments.
1 parent 07c01d4 commit a53c01f

File tree

3 files changed

+17
-20
lines changed

3 files changed

+17
-20
lines changed

Doc/whatsnew/3.14.rst

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -355,12 +355,11 @@ json
355355
multiprocessing
356356
---------------
357357

358-
* :mod:`multiprocessing`'s ``"forkserver"`` start method gains authentication
359-
on its control sockets so that it isn't solely reliant on filesystem
360-
permissions to control what other processes can cause the fork server to
361-
spawn workers and run code.
362-
This improves the security story behind :gh:`97514`.
363-
(Contributed by Gregory P. Smith.)
358+
* :mod:`multiprocessing`'s ``"forkserver"`` start method now authenticates
359+
its control socket to avoid solely relying on filesystem permissions
360+
to restrict what other processes could cause the forkserver to spawn workers
361+
and run code.
362+
(Contributed by Gregory P. Smith for :gh:`97514`.)
364363

365364

366365
operator

Lib/multiprocessing/forkserver.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
MAXFDS_TO_SEND = 256
2828
SIGNED_STRUCT = struct.Struct('q') # large enough for pid_t
29-
_authkey_len = 32 # <= PIPEBUF so it fits a single write to an empty pipe.
29+
_AUTHKEY_LEN = 32 # <= PIPEBUF so it fits a single write to an empty pipe.
3030

3131
#
3232
# Forkserver class
@@ -87,6 +87,7 @@ def connect_to_new_process(self, fds):
8787
process data.
8888
'''
8989
self.ensure_running()
90+
assert self._forkserver_authkey
9091
if len(fds) + 4 >= MAXFDS_TO_SEND:
9192
raise ValueError('too many fds')
9293
with socket.socket(socket.AF_UNIX) as client:
@@ -97,7 +98,6 @@ def connect_to_new_process(self, fds):
9798
resource_tracker.getfd()]
9899
allfds += fds
99100
try:
100-
assert self._forkserver_authkey
101101
client.setblocking(True)
102102
wrapped_client = connection.Connection(client.fileno())
103103
# The other side of this exchange happens in the child as
@@ -183,7 +183,7 @@ def ensure_running(self):
183183
# Authenticate our control socket to prevent access from
184184
# processes we have not shared this key with.
185185
try:
186-
self._forkserver_authkey = os.urandom(_authkey_len)
186+
self._forkserver_authkey = os.urandom(_AUTHKEY_LEN)
187187
os.write(authkey_w, self._forkserver_authkey)
188188
finally:
189189
os.close(authkey_w)
@@ -199,9 +199,11 @@ def main(listener_fd, alive_r, preload, main_path=None, sys_path=None,
199199
*, authkey_r=None):
200200
"""Run forkserver."""
201201
if authkey_r is not None:
202-
authkey = os.read(authkey_r, _authkey_len)
203-
assert len(authkey) == _authkey_len, f'{len(authkey)} < {_authkey_len}'
204-
os.close(authkey_r)
202+
try:
203+
authkey = os.read(authkey_r, _AUTHKEY_LEN)
204+
assert len(authkey) == _AUTHKEY_LEN, f'{len(authkey)} < {_AUTHKEY_LEN}'
205+
finally:
206+
os.close(authkey_r)
205207
else:
206208
authkey = b''
207209

Lib/test/_test_multiprocessing.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -895,10 +895,6 @@ def test_forkserver_sigkill(self):
895895
if os.name != 'nt':
896896
self.check_forkserver_death(signal.SIGKILL)
897897

898-
@staticmethod
899-
def _exit_process():
900-
sys.exit(0)
901-
902898
def test_forkserver_auth_is_enabled(self):
903899
if self.TYPE == "threads":
904900
self.skipTest(f"test not appropriate for {self.TYPE}")
@@ -920,7 +916,7 @@ def test_forkserver_auth_is_enabled(self):
920916
client.close()
921917

922918
# That worked, now launch a quick process.
923-
proc = self.Process(target=self._exit_process)
919+
proc = self.Process(target=sys.exit)
924920
proc.start()
925921
proc.join()
926922
self.assertEqual(proc.exitcode, 0)
@@ -939,14 +935,14 @@ def test_forkserver_without_auth_fails(self):
939935
forkserver, '_forkserver_authkey', None):
940936
# With an incorrect authkey we should get an auth rejection
941937
# rather than the above protocol error.
942-
forkserver._forkserver_authkey = b'T'*authkey_len
943-
proc = self.Process(target=self._exit_process)
938+
forkserver._forkserver_authkey = b'T' * authkey_len
939+
proc = self.Process(target=sys.exit)
944940
with self.assertRaises(multiprocessing.AuthenticationError):
945941
proc.start()
946942
del proc
947943

948944
# authkey restored, launching processes should work again.
949-
proc = self.Process(target=self._exit_process)
945+
proc = self.Process(target=sys.exit)
950946
proc.start()
951947
proc.join()
952948

0 commit comments

Comments
 (0)