From: Christian Heimes Date: Wed, 21 Aug 2013 11:26:34 +0000 (+0200) Subject: Issue #18747: Re-seed OpenSSL's pseudo-random number generator after fork. X-Git-Tag: v3.4.0a2~169 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6acbe2aaa385ada342ac9421333fce083041f06f;p=python Issue #18747: Re-seed OpenSSL's pseudo-random number generator after fork. A pthread_atfork() child handler is used to seeded the PRNG with pid, time and some stack data. --- 6acbe2aaa385ada342ac9421333fce083041f06f diff --cc Misc/NEWS index 5961ae590c,f02c18ea43..b95ce2d8d2 --- a/Misc/NEWS +++ b/Misc/NEWS @@@ -10,104 -12,10 +10,108 @@@ Projected Release date: 2013-09-0 Core and Builtins ----------------- +- Issue #18774: Remove last bits of GNU PTH thread code and thread_pth.h. + +- Issue #18771: Add optimization to set object lookups to reduce the cost + of hash collisions. The core idea is to inspect a second key/hash pair + for each cache line retrieved. + +- Issue #16105: When a signal handler fails to write to the file descriptor + registered with ``signal.set_wakeup_fd()``, report an exception instead + of ignoring the error. + +- Issue #18722: Remove uses of the "register" keyword in C code. + - Issue #18667: Add missing "HAVE_FCHOWNAT" symbol to posix._have_functions. +- Issue #16499: Add command line option for isolated mode. + +- Issue #15301: Parsing fd, uid, and gid parameters for builtins + in Modules/posixmodule.c is now far more robust. + - Issue #18368: PyOS_StdioReadline() no longer leaks memory when realloc() - fails. + fail. + +- Issue #17934: Add a clear() method to frame objects, to help clean up + expensive details (local variables) and break reference cycles. + +Library +------- + ++- Issue #18747: Re-seed OpenSSL's pseudo-random number generator after fork. ++ A pthread_atfork() child handler is used to seeded the PRNG with pid, time ++ and some stack data. ++ +- Issue #8865: Concurrent invocation of select.poll.poll() now raises a + RuntimeError exception. Patch by Christian Schubert. + +- Issue #18777: The ssl module now uses the new CRYPTO_THREADID API of + OpenSSL 1.0.0+ instead of the deprecated CRYPTO id callback function. + +- Issue #18768: Correct doc string of RAND_edg(). Patch by Vajrasky Kok. + +- Issue #18178: Fix ctypes on BSD. dlmalloc.c was compiled twice which broke + malloc weak symbols. + +- Issue #18709: Fix CVE-2013-4238. The SSL module now handles NULL bytes + inside subjectAltName correctly. Formerly the module has used OpenSSL's + GENERAL_NAME_print() function to get the string represention of ASN.1 + strings for ``rfc822Name`` (email), ``dNSName`` (DNS) and + ``uniformResourceIdentifier`` (URI). + +- Issue #18701: Remove support of old CPython versions (<3.0) from C code. + +- Issue #18756: Improve error reporting in os.urandom() when the failure + is due to something else than /dev/urandom not existing (for example, + exhausting the file descriptor limit). + +- Issue #18673: Add O_TMPFILE to os module. O_TMPFILE requires Linux kernel + 3.11 or newer. It's only defined on system with 3.11 uapi headers, too. + +- Issue #18532: Change the builtin hash algorithms' names to lower case names + as promised by hashlib's documentation. + +- Issue #18405: Improve the entropy of crypt.mksalt(). + +- Issue #12015: The tempfile module now uses a suffix of 8 random characters + instead of 6, to reduce the risk of filename collision. The entropy was + reduced when uppercase letters were removed from the charset used to generate + random characters. + +- Issue #18585: Add :func:`textwrap.shorten` to collapse and truncate a + piece of text to a given length. + +- Issue #18598: Tweak exception message for importlib.import_module() to + include the module name when a key argument is missing. + +- Issue #18676: Change 'positive' to 'non-negative' in queue.py put and get + docstrings and ValueError messages. Patch by Zhongyue Luo + +- Fix refcounting issue with extension types in tkinter. + +- Issue #8112: xlmrpc.server's DocXMLRPCServer server no longer raises an error + if methods have annotations; it now correctly displays the annotations. + +- Issue #18600: Added policy argument to email.message.Message.as_string, + and as_bytes and __bytes__ methods to Message. + +- Issue #18671: Output more information when logging exceptions occur. + +- Issue #18621: Prevent the site module's patched builtins from keeping + too many references alive for too long. + +- Issue #4885: Add weakref support to mmap objects. Patch by Valerie Lambert. + +- Issue #8860: Fixed rounding in timedelta constructor. + + +What's New in Python 3.4.0 Alpha 1? +=================================== + +Release date: 2013-08-03 + +Core and Builtins +----------------- - Issue #16741: Fix an error reporting in int(). diff --cc Modules/_ssl.c index dda266eda2,cd6640f499..3eb03a7478 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@@ -2936,171 -2583,71 +2941,233 @@@ Queries the entropy gather daemon (EGD Returns number of bytes read. Raises SSLError if connection to EGD\n\ fails or if it does not provide enough data to seed PRNG."); + /* Seed OpenSSL's PRNG at fork(), http://bugs.python.org/issue18747 + * + * The child handler seeds the PRNG from pseudo-random data like pid, the + * current time (nanoseconds, miliseconds or seconds) and an uninitialized + * array. The array contains stack variables that are impossible to predict + * on most systems, e.g. function return address (subject to ASLR), the + * stack protection canary and automatic variables. + * The code is inspired by Apache's ssl_rand_seed() function. + * + * Note: + * The code uses pthread_atfork() until Python has a proper atfork API. The + * handlers are not removed from the child process. + */ + + #if defined(HAVE_PTHREAD_ATFORK) && defined(WITH_THREAD) + #define PYSSL_RAND_ATFORK 1 + + static void + PySSL_RAND_atfork_child(void) + { + struct { + char stack[128]; /* uninitialized (!) stack data, 128 is an + arbitrary number. */ + pid_t pid; /* current pid */ + _PyTime_timeval tp; /* current time */ + } seed; + + #ifdef WITH_VALGRIND + VALGRIND_MAKE_MEM_DEFINED(seed.stack, sizeof(seed.stack)); + #endif + seed.pid = getpid(); + _PyTime_gettimeofday(&(seed.tp)); + + #if 0 + fprintf(stderr, "PySSL_RAND_atfork_child() seeds %i bytes in pid %i\n", + (int)sizeof(seed), seed.pid); #endif + RAND_add((unsigned char *)&seed, sizeof(seed), 0.0); + } + + static int + PySSL_RAND_atfork(void) + { + static int registered = 0; + int retval; + + if (registered) + return 0; + + retval = pthread_atfork(NULL, /* prepare */ + NULL, /* parent */ + PySSL_RAND_atfork_child); /* child */ + if (retval != 0) { + PyErr_SetFromErrno(PyExc_OSError); + return -1; + } + registered = 1; + return 0; + } + #endif /* HAVE_PTHREAD_ATFORK */ + + #endif /* HAVE_OPENSSL_RAND */ + +PyDoc_STRVAR(PySSL_get_default_verify_paths_doc, +"get_default_verify_paths() -> tuple\n\ +\n\ +Return search paths and environment vars that are used by SSLContext's\n\ +set_default_verify_paths() to load default CAs. The values are\n\ +'cert_file_env', 'cert_file', 'cert_dir_env', 'cert_dir'."); + +static PyObject * +PySSL_get_default_verify_paths(PyObject *self) +{ + PyObject *ofile_env = NULL; + PyObject *ofile = NULL; + PyObject *odir_env = NULL; + PyObject *odir = NULL; + +#define convert(info, target) { \ + const char *tmp = (info); \ + target = NULL; \ + if (!tmp) { Py_INCREF(Py_None); target = Py_None; } \ + else if ((target = PyUnicode_DecodeFSDefault(tmp)) == NULL) { \ + target = PyBytes_FromString(tmp); } \ + if (!target) goto error; \ + } while(0) + + convert(X509_get_default_cert_file_env(), ofile_env); + convert(X509_get_default_cert_file(), ofile); + convert(X509_get_default_cert_dir_env(), odir_env); + convert(X509_get_default_cert_dir(), odir); +#undef convert + + return Py_BuildValue("NNNN", ofile_env, ofile, odir_env, odir); + + error: + Py_XDECREF(ofile_env); + Py_XDECREF(ofile); + Py_XDECREF(odir_env); + Py_XDECREF(odir); + return NULL; +} +#ifdef _MSC_VER +PyDoc_STRVAR(PySSL_enum_cert_store_doc, +"enum_cert_store(store_name, cert_type='certificate') -> []\n\ +\n\ +Retrieve certificates from Windows' cert store. store_name may be one of\n\ +'CA', 'ROOT' or 'MY'. The system may provide more cert storages, too.\n\ +cert_type must be either 'certificate' or 'crl'.\n\ +The function returns a list of (bytes, encoding_type) tuples. The\n\ +encoding_type flag can be interpreted with X509_ASN_ENCODING or\n\ +PKCS_7_ASN_ENCODING."); + +static PyObject * +PySSL_enum_cert_store(PyObject *self, PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"store_name", "cert_type", NULL}; + char *store_name; + char *cert_type = "certificate"; + HCERTSTORE hStore = NULL; + PyObject *result = NULL; + PyObject *tup = NULL, *cert = NULL, *enc = NULL; + int ok = 1; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|s:enum_cert_store", + kwlist, &store_name, &cert_type)) { + return NULL; + } + + if ((strcmp(cert_type, "certificate") != 0) && + (strcmp(cert_type, "crl") != 0)) { + return PyErr_Format(PyExc_ValueError, + "cert_type must be 'certificate' or 'crl', " + "not %.100s", cert_type); + } + + if ((result = PyList_New(0)) == NULL) { + return NULL; + } + + if ((hStore = CertOpenSystemStore(NULL, store_name)) == NULL) { + Py_DECREF(result); + return PyErr_SetFromWindowsErr(GetLastError()); + } + + if (strcmp(cert_type, "certificate") == 0) { + PCCERT_CONTEXT pCertCtx = NULL; + while (pCertCtx = CertEnumCertificatesInStore(hStore, pCertCtx)) { + cert = PyBytes_FromStringAndSize((const char*)pCertCtx->pbCertEncoded, + pCertCtx->cbCertEncoded); + if (!cert) { + ok = 0; + break; + } + if ((enc = PyLong_FromLong(pCertCtx->dwCertEncodingType)) == NULL) { + ok = 0; + break; + } + if ((tup = PyTuple_New(2)) == NULL) { + ok = 0; + break; + } + PyTuple_SET_ITEM(tup, 0, cert); cert = NULL; + PyTuple_SET_ITEM(tup, 1, enc); enc = NULL; + + if (PyList_Append(result, tup) < 0) { + ok = 0; + break; + } + Py_CLEAR(tup); + } + if (pCertCtx) { + /* loop ended with an error, need to clean up context manually */ + CertFreeCertificateContext(pCertCtx); + } + } else { + PCCRL_CONTEXT pCrlCtx = NULL; + while (pCrlCtx = CertEnumCRLsInStore(hStore, pCrlCtx)) { + cert = PyBytes_FromStringAndSize((const char*)pCrlCtx->pbCrlEncoded, + pCrlCtx->cbCrlEncoded); + if (!cert) { + ok = 0; + break; + } + if ((enc = PyLong_FromLong(pCrlCtx->dwCertEncodingType)) == NULL) { + ok = 0; + break; + } + if ((tup = PyTuple_New(2)) == NULL) { + ok = 0; + break; + } + PyTuple_SET_ITEM(tup, 0, cert); cert = NULL; + PyTuple_SET_ITEM(tup, 1, enc); enc = NULL; + + if (PyList_Append(result, tup) < 0) { + ok = 0; + break; + } + Py_CLEAR(tup); + } + if (pCrlCtx) { + /* loop ended with an error, need to clean up context manually */ + CertFreeCRLContext(pCrlCtx); + } + } + + /* In error cases cert, enc and tup may not be NULL */ + Py_XDECREF(cert); + Py_XDECREF(enc); + Py_XDECREF(tup); + + if (!CertCloseStore(hStore, 0)) { + /* This error case might shadow another exception.*/ + Py_DECREF(result); + return PyErr_SetFromWindowsErr(GetLastError()); + } + if (ok) { + return result; + } else { + Py_DECREF(result); + return NULL; + } +} +#endif /* List of functions exported by this module. */