]> granicus.if.org Git - python/commitdiff
Issue #18747: Re-seed OpenSSL's pseudo-random number generator after fork.
authorChristian Heimes <christian@cheimes.de>
Wed, 21 Aug 2013 11:26:34 +0000 (13:26 +0200)
committerChristian Heimes <christian@cheimes.de>
Wed, 21 Aug 2013 11:26:34 +0000 (13:26 +0200)
A pthread_atfork() child handler is used to seeded the PRNG with pid, time
and some stack data.

1  2 
Lib/test/test_ssl.py
Misc/NEWS
Modules/_ssl.c
configure
configure.ac
pyconfig.h.in

Simple merge
diff --cc Misc/NEWS
index 5961ae590c1bd87e903595ff2a7dac86f9da29bc,f02c18ea437b41d59621066af42a5c5199d225c1..b95ce2d8d2ccd99ac64c9f4759712c3f56aca4d1
+++ 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 dda266eda210cb3e91a1f1cdebf0ae7f0c49acb2,cd6640f499b9c8cab9a4d11ccdcd1467bedea2c2..3eb03a7478e3c4b0c33c6e912756053041a719dc
@@@ -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. */
  
diff --cc configure
Simple merge
diff --cc configure.ac
Simple merge
diff --cc pyconfig.h.in
Simple merge