mirror of
https://github.com/python/cpython.git
synced 2025-08-15 14:20:55 +00:00
merge 2.6 with hash randomization fix
This commit is contained in:
commit
aee9dfba4a
26 changed files with 2503 additions and 140 deletions
|
@ -67,6 +67,7 @@ static void call_sys_exitfunc(void);
|
|||
static void call_ll_exitfuncs(void);
|
||||
extern void _PyUnicode_Init(void);
|
||||
extern void _PyUnicode_Fini(void);
|
||||
extern void _PyRandom_Init(void);
|
||||
|
||||
#ifdef WITH_THREAD
|
||||
extern void _PyGILState_Init(PyInterpreterState *, PyThreadState *);
|
||||
|
@ -89,6 +90,7 @@ int Py_IgnoreEnvironmentFlag; /* e.g. PYTHONPATH, PYTHONHOME */
|
|||
true divisions (which they will be in 2.3). */
|
||||
int _Py_QnewFlag = 0;
|
||||
int Py_NoUserSiteDirectory = 0; /* for -s and site.py */
|
||||
int Py_HashRandomizationFlag = 0; /* for -R and PYTHONHASHSEED */
|
||||
|
||||
/* PyModule_GetWarningsModule is no longer necessary as of 2.6
|
||||
since _warnings is builtin. This API should not be used. */
|
||||
|
@ -166,6 +168,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
|
||||
}
|
||||
}
|
|
@ -1209,6 +1209,7 @@ static PyStructSequence_Field flags_fields[] = {
|
|||
{"unicode", "-U"},
|
||||
/* {"skip_first", "-x"}, */
|
||||
{"bytes_warning", "-b"},
|
||||
{"hash_randomization", "-R"},
|
||||
{0}
|
||||
};
|
||||
|
||||
|
@ -1217,9 +1218,9 @@ static PyStructSequence_Desc flags_desc = {
|
|||
flags__doc__, /* doc */
|
||||
flags_fields, /* fields */
|
||||
#ifdef RISCOS
|
||||
16
|
||||
17
|
||||
#else
|
||||
15
|
||||
16
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -1256,6 +1257,7 @@ make_flags(void)
|
|||
SetFlag(Py_UnicodeFlag);
|
||||
/* SetFlag(skipfirstline); */
|
||||
SetFlag(Py_BytesWarningFlag);
|
||||
SetFlag(Py_HashRandomizationFlag);
|
||||
#undef SetFlag
|
||||
|
||||
if (PyErr_Occurred()) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue