An interpreted, interactive, object-oriented programming language
CentOS Sources
2017-08-01 71084d584ff953f5463757ec6536406320560b4d
commit | author | age
f63228 1
CS 2 # HG changeset patch
3 # User Benjamin Peterson <benjamin@python.org>
4 # Date 1409243400 14400
5 # Node ID 3e7f8855078855a9409bc2c1372de89cb021d6c8
6 # Parent  3f73c44b1fd1d442d6841493328e9756fb5e7ef5
7 PEP 466: backport persistent urandom fd (closes #21305)
8
9 Patch from Alex Gaynor.
10
11 diff --git a/Python/pythonrun.c b/Python/pythonrun.c
12 --- a/Python/pythonrun.c
13 +++ b/Python/pythonrun.c
14 @@ -536,6 +536,7 @@ Py_Finalize(void)
15      PyInt_Fini();
16      PyFloat_Fini();
17      PyDict_Fini();
18 +    _PyRandom_Fini();
19  
20  #ifdef Py_USING_UNICODE
21      /* Cleanup Unicode implementation */
22 diff -up Python-2.7.5/Include/pythonrun.h.urandom Python-2.7.5/Include/pythonrun.h
23 --- Python-2.7.5/Include/pythonrun.h.urandom    2015-03-06 08:16:47.638584015 +0100
24 +++ Python-2.7.5/Include/pythonrun.h    2015-03-06 08:21:48.009485462 +0100
25 @@ -145,6 +145,7 @@ PyAPI_FUNC(void) PyInt_Fini(void);
26  PyAPI_FUNC(void) PyFloat_Fini(void);
27  PyAPI_FUNC(void) PyOS_FiniInterrupts(void);
28  PyAPI_FUNC(void) PyByteArray_Fini(void);
29 +PyAPI_FUNC(void) _PyRandom_Fini(void);
30  
31  /* Stuff with no proper home (yet) */
32  PyAPI_FUNC(char *) PyOS_Readline(FILE *, FILE *, char *);
33 diff -up Python-2.7.5/Python/random.c.urandom Python-2.7.5/Python/random.c
34 --- Python-2.7.5/Python/random.c.urandom    2015-03-06 08:22:10.244699950 +0100
35 +++ Python-2.7.5/Python/random.c    2015-03-06 08:24:57.907317272 +0100
36 @@ -118,10 +118,16 @@ vms_urandom(unsigned char *buffer, Py_ss
37  
38  #if !defined(MS_WINDOWS) && !defined(__VMS)
39  
40 +static struct {
41 +    int fd;
42 +    dev_t st_dev;
43 +    ino_t st_ino;
44 +} urandom_cache = { -1 };
45 +
46  /* Read size bytes from /dev/urandom into buffer.
47     Call Py_FatalError() on error. */
48  static void
49 -dev_urandom_noraise(char *buffer, Py_ssize_t size)
50 +dev_urandom_noraise(unsigned char *buffer, Py_ssize_t size)
51  {
52      int fd;
53      Py_ssize_t n;
54 @@ -156,18 +162,56 @@ dev_urandom_python(char *buffer, Py_ssiz
55  {
56      int fd;
57      Py_ssize_t n;
58 +    struct stat st;
59  
60      if (size <= 0)
61          return 0;
62  
63 -    Py_BEGIN_ALLOW_THREADS
64 -    fd = open("/dev/urandom", O_RDONLY);
65 -    Py_END_ALLOW_THREADS
66 -    if (fd < 0)
67 -    {
68 -        PyErr_SetString(PyExc_NotImplementedError,
69 -                        "/dev/urandom (or equivalent) not found");
70 -        return -1;
71 +    if (urandom_cache.fd >= 0) {
72 +        /* Does the fd point to the same thing as before? (issue #21207) */
73 +        if (fstat(urandom_cache.fd, &st)
74 +            || st.st_dev != urandom_cache.st_dev
75 +            || st.st_ino != urandom_cache.st_ino) {
76 +            /* Something changed: forget the cached fd (but don't close it,
77 +               since it probably points to something important for some
78 +               third-party code). */
79 +            urandom_cache.fd = -1;
80 +        }
81 +    }
82 +    if (urandom_cache.fd >= 0)
83 +        fd = urandom_cache.fd;
84 +    else {
85 +        Py_BEGIN_ALLOW_THREADS
86 +        fd = open("/dev/urandom", O_RDONLY);
87 +        Py_END_ALLOW_THREADS
88 +        if (fd < 0)
89 +        {
90 +            if (errno == ENOENT || errno == ENXIO ||
91 +                errno == ENODEV || errno == EACCES)
92 +                PyErr_SetString(PyExc_NotImplementedError,
93 +                                "/dev/urandom (or equivalent) not found");
94 +            else
95 +                PyErr_SetFromErrno(PyExc_OSError);
96 +            return -1;
97 +        }
98 +        if (urandom_cache.fd >= 0) {
99 +            /* urandom_fd was initialized by another thread while we were
100 +               not holding the GIL, keep it. */
101 +            close(fd);
102 +            fd = urandom_cache.fd;
103 +        }
104 +        else {
105 +            if (fstat(fd, &st)) {
106 +                PyErr_SetFromErrno(PyExc_OSError);
107 +                close(fd);
108 +                return -1;
109 +            }
110 +            else {
111 +                urandom_cache.fd = fd;
112 +                urandom_cache.st_dev = st.st_dev;
113 +                urandom_cache.st_ino = st.st_ino;
114 +            }
115 +        }
116      }
117  
118      Py_BEGIN_ALLOW_THREADS
119 @@ -191,12 +235,21 @@ dev_urandom_python(char *buffer, Py_ssiz
120              PyErr_Format(PyExc_RuntimeError,
121                           "Failed to read %zi bytes from /dev/urandom",
122                           size);
123 -        close(fd);
124          return -1;
125      }
126 -    close(fd);
127      return 0;
128  }
129 +
130 +static void
131 +dev_urandom_close(void)
132 +{
133 +    if (urandom_cache.fd >= 0) {
134 +        close(urandom_cache.fd);
135 +        urandom_cache.fd = -1;
136 +    }
137 +}
138 +
139 +
140  #endif /* !defined(MS_WINDOWS) && !defined(__VMS) */
141  
142  /* Fill buffer with pseudo-random bytes generated by a linear congruent
143 @@ -300,8 +353,21 @@ _PyRandom_Init(void)
144  # ifdef __VMS
145          vms_urandom((unsigned char *)secret, secret_size, 0);
146  # else
147 -        dev_urandom_noraise((char*)secret, secret_size);
148 +        dev_urandom_noraise((unsigned char*)secret, secret_size);
149  # endif
150  #endif
151      }
152  }
153 +
154 +void
155 +_PyRandom_Fini(void)
156 +{
157 +#ifdef MS_WINDOWS
158 +    if (hCryptProv) {
159 +        CryptReleaseContext(hCryptProv, 0);
160 +        hCryptProv = 0;
161 +    }
162 +#else
163 +    dev_urandom_close();
164 +#endif
165 +}