# HG changeset patch # User Brian Harring # Date 1314664090 25200 # Node ID 9dfe1d7d5d1511ec842c7bcc4c59890c24d60592 # Parent fb8d7a666bed19f5aa1d18a1288bbe08e5fbd07d Ensure child processes do not inherit the parents random seed for tempfile All tempfile functionality currently is reliant on a pseudorandom source; this source is unfortunately global, meaning that children processes inherit it, and will get the same set of random values. This introduces predictability into the parent/children tempfile creation, and a bit of contention. Suspect that in existing code that has issues this can be useful for an attack vector; primarily it's an annoying gotcha when doing a form of multiprocessing with multiple workers. diff -r fb8d7a666bed -r 9dfe1d7d5d15 Lib/tempfile.py --- a/Lib/tempfile.py Tue Aug 30 00:28:40 2011 +0200 +++ b/Lib/tempfile.py Mon Aug 29 17:28:10 2011 -0700 @@ -112,8 +112,13 @@ characters = "abcdefghijklmnopqrstuvwxyz0123456789_" - def __init__(self): - self.rng = _Random() + @property + def rng(self): + cur_pid = _os.getpid() + if cur_pid != getattr(self, '_rng_pid', None): + self._rng = _Random() + self._rng_pid = cur_pid + return self._rng def __iter__(self): return self diff -r fb8d7a666bed -r 9dfe1d7d5d15 Lib/test/test_tempfile.py --- a/Lib/test/test_tempfile.py Tue Aug 30 00:28:40 2011 +0200 +++ b/Lib/test/test_tempfile.py Mon Aug 29 17:28:10 2011 -0700 @@ -1,6 +1,7 @@ # tempfile.py unit tests. import tempfile import os +import signal import sys import re import warnings @@ -135,6 +136,34 @@ except: self.failOnException("iteration") + def test_process_awareness(self): + # ensure that the random source differs between + # child and parent. + read_fd, write_fd = os.pipe() + pid = None + try: + pid = os.fork() + if not pid: + os.close(read_fd) + os.write(write_fd, next(self.r).encode("ascii")) + os.close(write_fd) + # bypass the normal exit handlers- leave those to + # the parent. + os._exit(0) + value = os.read(read_fd, 6).decode("ascii") + finally: + if pid: + # best effort to ensure the process can't bleed out + # via any bugs above + try: + os.kill(pid, signal.SIGKILL) + except EnvironmentError: + pass + os.close(read_fd) + os.close(write_fd) + self.assertNotEqual(value, next(self.r)) + + test_classes.append(test__RandomNameSequence)