mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	Merge 3.2: Issue #13703 plus some related test suite fixes.
This commit is contained in:
		
						commit
						2fb477c0f0
					
				
					 38 changed files with 706 additions and 174 deletions
				
			
		|  | @ -73,6 +73,7 @@ extern int _PyLong_Init(void); | |||
| extern void PyLong_Fini(void); | ||||
| extern int _PyFaulthandler_Init(void); | ||||
| extern void _PyFaulthandler_Fini(void); | ||||
| extern void _PyRandom_Init(void); | ||||
| 
 | ||||
| #ifdef WITH_THREAD | ||||
| extern void _PyGILState_Init(PyInterpreterState *, PyThreadState *); | ||||
|  | @ -92,6 +93,7 @@ int Py_FrozenFlag; /* Needed by getpath.c */ | |||
| int Py_IgnoreEnvironmentFlag; /* e.g. PYTHONPATH, PYTHONHOME */ | ||||
| int Py_NoUserSiteDirectory = 0; /* for -s and site.py */ | ||||
| int Py_UnbufferedStdioFlag = 0; /* Unbuffered binary std{in,out,err} */ | ||||
| int Py_HashRandomizationFlag = 0; /* for -R and PYTHONHASHSEED */ | ||||
| 
 | ||||
| PyThreadState *_Py_Finalizing = NULL; | ||||
| 
 | ||||
|  | @ -218,6 +220,12 @@ Py_InitializeEx(int install_sigs) | |||
|         Py_OptimizeFlag = add_flag(Py_OptimizeFlag, p); | ||||
|     if ((p = Py_GETENV("PYTHONDONTWRITEBYTECODE")) && *p != '\0') | ||||
|         Py_DontWriteBytecodeFlag = add_flag(Py_DontWriteBytecodeFlag, p); | ||||
|     /* The variable is only tested for existence here; _PyRandom_Init will
 | ||||
|        check its value further. */ | ||||
|     if ((p = Py_GETENV("PYTHONHASHSEED")) && *p != '\0') | ||||
|         Py_HashRandomizationFlag = add_flag(Py_HashRandomizationFlag, p); | ||||
| 
 | ||||
|     _PyRandom_Init(); | ||||
| 
 | ||||
|     interp = PyInterpreterState_New(); | ||||
|     if (interp == NULL) | ||||
|  |  | |||
							
								
								
									
										302
									
								
								Python/random.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										302
									
								
								Python/random.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,302 @@ | |||
| #include "Python.h" | ||||
| #ifdef MS_WINDOWS | ||||
| #include <windows.h> | ||||
| #else | ||||
| #include <fcntl.h> | ||||
| #endif | ||||
| 
 | ||||
| static int random_initialized = 0; | ||||
| 
 | ||||
| #ifdef MS_WINDOWS | ||||
| typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv,\ | ||||
|               LPCSTR pszContainer, LPCSTR pszProvider, DWORD dwProvType,\ | ||||
|               DWORD dwFlags ); | ||||
| typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen,\ | ||||
|               BYTE *pbBuffer ); | ||||
| 
 | ||||
| static CRYPTGENRANDOM pCryptGenRandom = NULL; | ||||
| /* This handle is never explicitly released. Instead, the operating
 | ||||
|    system will release it when the process terminates. */ | ||||
| static HCRYPTPROV hCryptProv = 0; | ||||
| 
 | ||||
| static int | ||||
| win32_urandom_init(int raise) | ||||
| { | ||||
|     HINSTANCE hAdvAPI32 = NULL; | ||||
|     CRYPTACQUIRECONTEXTA pCryptAcquireContext = NULL; | ||||
| 
 | ||||
|     /* Obtain handle to the DLL containing CryptoAPI. This should not fail. */ | ||||
|     hAdvAPI32 = GetModuleHandle("advapi32.dll"); | ||||
|     if(hAdvAPI32 == NULL) | ||||
|         goto error; | ||||
| 
 | ||||
|     /* Obtain pointers to the CryptoAPI functions. This will fail on some early
 | ||||
|        versions of Win95. */ | ||||
|     pCryptAcquireContext = (CRYPTACQUIRECONTEXTA)GetProcAddress( | ||||
|                                hAdvAPI32, "CryptAcquireContextA"); | ||||
|     if (pCryptAcquireContext == NULL) | ||||
|         goto error; | ||||
| 
 | ||||
|     pCryptGenRandom = (CRYPTGENRANDOM)GetProcAddress(hAdvAPI32, | ||||
|                                                      "CryptGenRandom"); | ||||
|     if (pCryptGenRandom == NULL) | ||||
|         goto error; | ||||
| 
 | ||||
|     /* Acquire context */ | ||||
|     if (! pCryptAcquireContext(&hCryptProv, NULL, NULL, | ||||
|                                PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) | ||||
|         goto error; | ||||
| 
 | ||||
|     return 0; | ||||
| 
 | ||||
| error: | ||||
|     if (raise) | ||||
|         PyErr_SetFromWindowsErr(0); | ||||
|     else | ||||
|         Py_FatalError("Failed to initialize Windows random API (CryptoGen)"); | ||||
|     return -1; | ||||
| } | ||||
| 
 | ||||
| /* Fill buffer with size pseudo-random bytes generated by the Windows CryptoGen
 | ||||
|    API. Return 0 on success, or -1 on error. */ | ||||
| static int | ||||
| win32_urandom(unsigned char *buffer, Py_ssize_t size, int raise) | ||||
| { | ||||
|     Py_ssize_t chunk; | ||||
| 
 | ||||
|     if (hCryptProv == 0) | ||||
|     { | ||||
|         if (win32_urandom_init(raise) == -1) | ||||
|             return -1; | ||||
|     } | ||||
| 
 | ||||
|     while (size > 0) | ||||
|     { | ||||
|         chunk = size > INT_MAX ? INT_MAX : size; | ||||
|         if (!pCryptGenRandom(hCryptProv, chunk, buffer)) | ||||
|         { | ||||
|             /* CryptGenRandom() failed */ | ||||
|             if (raise) | ||||
|                 PyErr_SetFromWindowsErr(0); | ||||
|             else | ||||
|                 Py_FatalError("Failed to initialized the randomized hash " | ||||
|                         "secret using CryptoGen)"); | ||||
|             return -1; | ||||
|         } | ||||
|         buffer += chunk; | ||||
|         size -= chunk; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| #endif /* MS_WINDOWS */ | ||||
| 
 | ||||
| 
 | ||||
| #ifdef __VMS | ||||
| /* Use openssl random routine */ | ||||
| #include <openssl/rand.h> | ||||
| static int | ||||
| vms_urandom(unsigned char *buffer, Py_ssize_t size, int raise) | ||||
| { | ||||
|     if (RAND_pseudo_bytes(buffer, size) < 0) { | ||||
|         if (raise) { | ||||
|             PyErr_Format(PyExc_ValueError, | ||||
|                          "RAND_pseudo_bytes"); | ||||
|         } else { | ||||
|             Py_FatalError("Failed to initialize the randomized hash " | ||||
|                           "secret using RAND_pseudo_bytes"); | ||||
|         } | ||||
|         return -1; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| #endif /* __VMS */ | ||||
| 
 | ||||
| 
 | ||||
| #if !defined(MS_WINDOWS) && !defined(__VMS) | ||||
| 
 | ||||
| /* Read size bytes from /dev/urandom into buffer.
 | ||||
|    Call Py_FatalError() on error. */ | ||||
| static void | ||||
| dev_urandom_noraise(char *buffer, Py_ssize_t size) | ||||
| { | ||||
|     int fd; | ||||
|     Py_ssize_t n; | ||||
| 
 | ||||
|     assert (0 < size); | ||||
| 
 | ||||
|     fd = open("/dev/urandom", O_RDONLY); | ||||
|     if (fd < 0) | ||||
|         Py_FatalError("Failed to open /dev/urandom"); | ||||
| 
 | ||||
|     while (0 < size) | ||||
|     { | ||||
|         do { | ||||
|             n = read(fd, buffer, (size_t)size); | ||||
|         } while (n < 0 && errno == EINTR); | ||||
|         if (n <= 0) | ||||
|         { | ||||
|             /* stop on error or if read(size) returned 0 */ | ||||
|             Py_FatalError("Failed to read bytes from /dev/urandom"); | ||||
|             break; | ||||
|         } | ||||
|         buffer += n; | ||||
|         size -= (Py_ssize_t)n; | ||||
|     } | ||||
|     close(fd); | ||||
| } | ||||
| 
 | ||||
| /* Read size bytes from /dev/urandom into buffer.
 | ||||
|    Return 0 on success, raise an exception and return -1 on error. */ | ||||
| static int | ||||
| dev_urandom_python(char *buffer, Py_ssize_t size) | ||||
| { | ||||
|     int fd; | ||||
|     Py_ssize_t n; | ||||
| 
 | ||||
|     if (size <= 0) | ||||
|         return 0; | ||||
| 
 | ||||
|     Py_BEGIN_ALLOW_THREADS | ||||
|     fd = open("/dev/urandom", O_RDONLY); | ||||
|     Py_END_ALLOW_THREADS | ||||
|     if (fd < 0) | ||||
|     { | ||||
|         PyErr_SetFromErrnoWithFilename(PyExc_OSError, "/dev/urandom"); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     Py_BEGIN_ALLOW_THREADS | ||||
|     do { | ||||
|         do { | ||||
|             n = read(fd, buffer, (size_t)size); | ||||
|         } while (n < 0 && errno == EINTR); | ||||
|         if (n <= 0) | ||||
|             break; | ||||
|         buffer += n; | ||||
|         size -= (Py_ssize_t)n; | ||||
|     } while (0 < size); | ||||
|     Py_END_ALLOW_THREADS | ||||
| 
 | ||||
|     if (n <= 0) | ||||
|     { | ||||
|         /* stop on error or if read(size) returned 0 */ | ||||
|         if (n < 0) | ||||
|             PyErr_SetFromErrno(PyExc_OSError); | ||||
|         else | ||||
|             PyErr_Format(PyExc_RuntimeError, | ||||
|                          "Failed to read %zi bytes from /dev/urandom", | ||||
|                          size); | ||||
|         close(fd); | ||||
|         return -1; | ||||
|     } | ||||
|     close(fd); | ||||
|     return 0; | ||||
| } | ||||
| #endif /* !defined(MS_WINDOWS) && !defined(__VMS) */ | ||||
| 
 | ||||
| /* Fill buffer with pseudo-random bytes generated by a linear congruent
 | ||||
|    generator (LCG): | ||||
| 
 | ||||
|        x(n+1) = (x(n) * 214013 + 2531011) % 2^32 | ||||
| 
 | ||||
|    Use bits 23..16 of x(n) to generate a byte. */ | ||||
| static void | ||||
| lcg_urandom(unsigned int x0, unsigned char *buffer, size_t size) | ||||
| { | ||||
|     size_t index; | ||||
|     unsigned int x; | ||||
| 
 | ||||
|     x = x0; | ||||
|     for (index=0; index < size; index++) { | ||||
|         x *= 214013; | ||||
|         x += 2531011; | ||||
|         /* modulo 2 ^ (8 * sizeof(int)) */ | ||||
|         buffer[index] = (x >> 16) & 0xff; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* Fill buffer with size pseudo-random bytes, not suitable for cryptographic
 | ||||
|    use, from the operating random number generator (RNG). | ||||
| 
 | ||||
|    Return 0 on success, raise an exception and return -1 on error. */ | ||||
| int | ||||
| _PyOS_URandom(void *buffer, Py_ssize_t size) | ||||
| { | ||||
|     if (size < 0) { | ||||
|         PyErr_Format(PyExc_ValueError, | ||||
|                      "negative argument not allowed"); | ||||
|         return -1; | ||||
|     } | ||||
|     if (size == 0) | ||||
|         return 0; | ||||
| 
 | ||||
| #ifdef MS_WINDOWS | ||||
|     return win32_urandom((unsigned char *)buffer, size, 1); | ||||
| #else | ||||
| # ifdef __VMS | ||||
|     return vms_urandom((unsigned char *)buffer, size, 1); | ||||
| # else | ||||
|     return dev_urandom_python((char*)buffer, size); | ||||
| # endif | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void | ||||
| _PyRandom_Init(void) | ||||
| { | ||||
|     char *env; | ||||
|     void *secret = &_Py_HashSecret; | ||||
|     Py_ssize_t secret_size = sizeof(_Py_HashSecret); | ||||
| 
 | ||||
|     if (random_initialized) | ||||
|         return; | ||||
|     random_initialized = 1; | ||||
| 
 | ||||
|     /*
 | ||||
|       By default, hash randomization is disabled, and only | ||||
|       enabled if PYTHONHASHSEED is set to non-empty or if | ||||
|       "-R" is provided at the command line: | ||||
|     */ | ||||
|     if (!Py_HashRandomizationFlag) { | ||||
|         /* Disable the randomized hash: */ | ||||
|         memset(secret, 0, secret_size); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     /*
 | ||||
|       Hash randomization is enabled.  Generate a per-process secret, | ||||
|       using PYTHONHASHSEED if provided. | ||||
|     */ | ||||
| 
 | ||||
|     env = Py_GETENV("PYTHONHASHSEED"); | ||||
|     if (env && *env != '\0' && strcmp(env, "random") != 0) { | ||||
|         char *endptr = env; | ||||
|         unsigned long seed; | ||||
|         seed = strtoul(env, &endptr, 10); | ||||
|         if (*endptr != '\0' | ||||
|             || seed > 4294967295UL | ||||
|             || (errno == ERANGE && seed == ULONG_MAX)) | ||||
|         { | ||||
|             Py_FatalError("PYTHONHASHSEED must be \"random\" or an integer " | ||||
|                           "in range [0; 4294967295]"); | ||||
|         } | ||||
|         if (seed == 0) { | ||||
|             /* disable the randomized hash */ | ||||
|             memset(secret, 0, secret_size); | ||||
|         } | ||||
|         else { | ||||
|             lcg_urandom(seed, (unsigned char*)secret, secret_size); | ||||
|         } | ||||
|     } | ||||
|     else { | ||||
| #ifdef MS_WINDOWS | ||||
|         (void)win32_urandom((unsigned char *)secret, secret_size, 0); | ||||
| #else /* #ifdef MS_WINDOWS */ | ||||
| # ifdef __VMS | ||||
|         vms_urandom((unsigned char *)secret, secret_size, 0); | ||||
| # else | ||||
|         dev_urandom_noraise((char*)secret, secret_size); | ||||
| # endif | ||||
| #endif | ||||
|     } | ||||
| } | ||||
|  | @ -1332,6 +1332,7 @@ static PyStructSequence_Field flags_fields[] = { | |||
|     /* {"skip_first",                   "-x"}, */ | ||||
|     {"bytes_warning",           "-b"}, | ||||
|     {"quiet",                   "-q"}, | ||||
|     {"hash_randomization",      "-R"}, | ||||
|     {0} | ||||
| }; | ||||
| 
 | ||||
|  | @ -1340,9 +1341,9 @@ static PyStructSequence_Desc flags_desc = { | |||
|     flags__doc__,       /* doc */ | ||||
|     flags_fields,       /* fields */ | ||||
| #ifdef RISCOS | ||||
|     12 | ||||
|     13 | ||||
| #else | ||||
|     11 | ||||
|     12 | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
|  | @ -1375,6 +1376,7 @@ make_flags(void) | |||
|     /* SetFlag(skipfirstline); */ | ||||
|     SetFlag(Py_BytesWarningFlag); | ||||
|     SetFlag(Py_QuietFlag); | ||||
|     SetFlag(Py_HashRandomizationFlag); | ||||
| #undef SetFlag | ||||
| 
 | ||||
|     if (PyErr_Occurred()) { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Georg Brandl
						Georg Brandl