Skip to content

Commit 80e7a0e

Browse files
committed
gh-144503: Harden init pipe I/O in forkserver
- Use buffered os.fdopen() for both writing and reading the init pipe so that preload payloads larger than PIPE_BUF are written and read fully. A bare os.write() may short-write large buffers. - Use data.get() for preparation-data keys rather than direct indexing to avoid coupling to spawn.get_preparation_data() internals.
1 parent be2e1f0 commit 80e7a0e

File tree

1 file changed

+17
-14
lines changed

1 file changed

+17
-14
lines changed

Lib/multiprocessing/forkserver.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,9 @@ def ensure_running(self):
170170
data = spawn.get_preparation_data('ignore')
171171
preload_kwargs = {
172172
"preload": self._preload_modules,
173-
"sys_path": data["sys_path"],
174-
"main_path": data.get("init_main_from_path", None),
175-
"sys_argv": data["sys_argv"],
173+
"sys_path": data.get("sys_path"),
174+
"main_path": data.get("init_main_from_path"),
175+
"sys_argv": data.get("sys_argv"),
176176
"on_error": self._preload_on_error,
177177
}
178178
else:
@@ -208,10 +208,13 @@ def ensure_running(self):
208208
# processes we have not shared this key with.
209209
try:
210210
self._forkserver_authkey = os.urandom(_AUTHKEY_LEN)
211-
os.write(init_w, self._forkserver_authkey)
212211
preload_data = json.dumps(preload_kwargs).encode()
213-
os.write(init_w, struct.pack("Q", len(preload_data)))
214-
os.write(init_w, preload_data)
212+
# Use a buffered writer so that payloads larger than
213+
# PIPE_BUF are written fully (os.write may short-write).
214+
with os.fdopen(init_w, 'wb', closefd=False) as f:
215+
f.write(self._forkserver_authkey)
216+
f.write(struct.pack("Q", len(preload_data)))
217+
f.write(preload_data)
215218
finally:
216219
os.close(init_w)
217220
self._forkserver_address = address
@@ -286,14 +289,14 @@ def _handle_preload(preload, main_path=None, sys_path=None, sys_argv=None,
286289
def main(listener_fd, alive_r, init_r):
287290
"""Run forkserver."""
288291
try:
289-
authkey = os.read(init_r, _AUTHKEY_LEN)
290-
assert len(authkey) == _AUTHKEY_LEN, f'{len(authkey)} < {_AUTHKEY_LEN}'
291-
292-
preload_data_len, = struct.unpack("Q", os.read(init_r, struct.calcsize("Q")))
293-
preload_data = b""
294-
while len(preload_data) < preload_data_len:
295-
preload_data += os.read(init_r, preload_data_len - len(preload_data))
296-
preload_kwargs = json.loads(preload_data.decode())
292+
# Buffered reader handles short reads on the length prefix and body.
293+
with os.fdopen(init_r, 'rb', closefd=False) as f:
294+
authkey = f.read(_AUTHKEY_LEN)
295+
assert len(authkey) == _AUTHKEY_LEN, (
296+
f'{len(authkey)} < {_AUTHKEY_LEN}')
297+
preload_data_len, = struct.unpack("Q",
298+
f.read(struct.calcsize("Q")))
299+
preload_kwargs = json.loads(f.read(preload_data_len))
297300
finally:
298301
os.close(init_r)
299302

0 commit comments

Comments
 (0)