Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r2992:115ee1bd9bc7
Date: 2017-07-08 19:21 +0200
http://bitbucket.org/cffi/cffi/changeset/115ee1bd9bc7/

Log:    Apply the patch of issue 321 if __NetBSD__ is defined.

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -60,7 +60,38 @@
 # endif
 #endif
 
-#include "malloc_closure.h"
+
+/* Define the following macro ONLY if you trust libffi's version of
+ * ffi_closure_alloc() more than the code in malloc_closure.h.
+ * IMPORTANT: DO NOT ENABLE THIS ON LINUX, unless you understand exactly
+ * why I recommend against it and decide that you trust it more than my
+ * analysis below.
+ *
+ * There are two versions of this code: one inside libffi itself, and
+ * one inside malloc_closure.h here.  Both should be fine as long as the
+ * Linux distribution does _not_ enable extra security features.  If it
+ * does, then the code in malloc_closure.h will cleanly crash because
+ * there is no reasonable way to obtain a read-write-execute memory
+ * page.  On the other hand, the code in libffi will appear to
+ * work---but will actually randomly crash after a fork() if the child
+ * does not immediately call exec().  This second crash is of the kind
+ * that can be turned into an attack vector by a motivated attacker.
+ * So, _enabling_ extra security features _opens_ an attack vector.
+ * That sounds like a horribly bad idea to me, and is the reason for why
+ * I prefer CFFI crashing cleanly.
+ *
+ * Currently, we use libffi's ffi_closure_alloc() only on NetBSD.  It is
+ * known that on the NetBSD kernel, a different strategy is used which
+ * should not be open to the fork() bug.
+ */
+#ifdef __NetBSD__
+# define CFFI_TRUST_LIBFFI
+#endif
+
+#ifndef CFFI_TRUST_LIBFFI
+# include "malloc_closure.h"
+#endif
+
 
 #if PY_MAJOR_VERSION >= 3
 # define STR_OR_BYTES "bytes"
@@ -259,6 +290,11 @@
 } CDataObject_gcp;
 
 typedef struct {
+    CDataObject head;
+    ffi_closure *closure;
+} CDataObject_closure;
+
+typedef struct {
     ffi_cif cif;
     /* the following information is used when doing the call:
        - a buffer of size 'exchange_size' is malloced
@@ -1781,10 +1817,14 @@
         Py_DECREF(x);
     }
     else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) {   /* a callback */
-        ffi_closure *closure = (ffi_closure *)cd->c_data;
+        ffi_closure *closure = ((CDataObject_closure *)cd)->closure;
         PyObject *args = (PyObject *)(closure->user_data);
         Py_XDECREF(args);
+#ifdef CFFI_TRUST_LIBFFI
+        ffi_closure_free(closure);
+#else
         cffi_closure_free(closure);
+#endif
     }
     else if (cd->c_type->ct_flags & CT_IS_UNSIZED_CHAR_A) {  /* from_buffer */
         Py_buffer *view = ((CDataObject_owngc_frombuf *)cd)->bufferview;
@@ -1801,7 +1841,7 @@
         Py_VISIT(x);
     }
     else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) {   /* a callback */
-        ffi_closure *closure = (ffi_closure *)cd->c_data;
+        ffi_closure *closure = ((CDataObject_closure *)cd)->closure;
         PyObject *args = (PyObject *)(closure->user_data);
         Py_VISIT(args);
     }
@@ -1822,7 +1862,7 @@
         Py_DECREF(x);
     }
     else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) {   /* a callback */
-        ffi_closure *closure = (ffi_closure *)cd->c_data;
+        ffi_closure *closure = ((CDataObject_closure *)cd)->closure;
         PyObject *args = (PyObject *)(closure->user_data);
         closure->user_data = NULL;
         Py_XDECREF(args);
@@ -2036,7 +2076,8 @@
         return _cdata_repr2(cd, "handle to", x);
     }
     else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) {   /* a callback */
-        PyObject *args = (PyObject *)((ffi_closure *)cd->c_data)->user_data;
+        ffi_closure *closure = ((CDataObject_closure *)cd)->closure;
+        PyObject *args = (PyObject *)closure->user_data;
         if (args == NULL)
             return cdata_repr(cd);
         else
@@ -5727,11 +5768,12 @@
 static PyObject *b_callback(PyObject *self, PyObject *args)
 {
     CTypeDescrObject *ct;
-    CDataObject *cd;
+    CDataObject_closure *cd;
     PyObject *ob, *error_ob = Py_None, *onerror_ob = Py_None;
     PyObject *infotuple;
     cif_description_t *cif_descr;
     ffi_closure *closure;
+    void *closure_exec;
 
     if (!PyArg_ParseTuple(args, "O!O|OO:callback", &CTypeDescr_Type, &ct, &ob,
                           &error_ob, &onerror_ob))
@@ -5741,15 +5783,24 @@
     if (infotuple == NULL)
         return NULL;
 
+#ifdef CFFI_TRUST_LIBFFI
+    closure = ffi_closure_alloc(sizeof(ffi_closure), &closure_exec);
+#else
     closure = cffi_closure_alloc();
-
-    cd = PyObject_GC_New(CDataObject, &CDataOwningGC_Type);
+    closure_exec = closure;
+#endif
+    if (closure == NULL) {
+        Py_DECREF(infotuple);
+        return NULL;
+    }
+    cd = PyObject_GC_New(CDataObject_closure, &CDataOwningGC_Type);
     if (cd == NULL)
         goto error;
     Py_INCREF(ct);
-    cd->c_type = ct;
-    cd->c_data = (char *)closure;
-    cd->c_weakreflist = NULL;
+    cd->head.c_type = ct;
+    cd->head.c_data = (char *)closure_exec;
+    cd->head.c_weakreflist = NULL;
+    cd->closure = closure;
     PyObject_GC_Track(cd);
 
     cif_descr = (cif_description_t *)ct->ct_extra;
@@ -5759,8 +5810,13 @@
                      "return type or with '...'", ct->ct_name);
         goto error;
     }
+#ifdef CFFI_TRUST_LIBFFI
+    if (ffi_prep_closure_loc(closure, &cif_descr->cif,
+                         invoke_callback, infotuple, closure_exec) != FFI_OK) {
+#else
     if (ffi_prep_closure(closure, &cif_descr->cif,
                          invoke_callback, infotuple) != FFI_OK) {
+#endif
         PyErr_SetString(PyExc_SystemError,
                         "libffi failed to build this callback");
         goto error;
@@ -5783,8 +5839,13 @@
 
  error:
     closure->user_data = NULL;
-    if (cd == NULL)
+    if (cd == NULL) {
+#ifdef CFFI_TRUST_LIBFFI
+        ffi_closure_free(closure);
+#else
         cffi_closure_free(closure);
+#endif
+    }
     else
         Py_DECREF(cd);
     Py_XDECREF(infotuple);
diff --git a/doc/source/installation.rst b/doc/source/installation.rst
--- a/doc/source/installation.rst
+++ b/doc/source/installation.rst
@@ -201,9 +201,5 @@
 NetBSD
 ++++++
 
-Reports on NetBSD are not good.  You first need to make sure you have an
-up-to-date version of libffi, which fixes some bugs.  However, there are
-still a number of segfaults and failures running the CFFI tests (see
-`issue 321`__).  Contributions welcome.
-
-.. __: 
https://bitbucket.org/cffi/cffi/issues/321/cffi-191-segmentation-fault-during-self
+You need to make sure you have an up-to-date version of libffi, which
+fixes some bugs.
diff --git a/doc/source/whatsnew.rst b/doc/source/whatsnew.rst
--- a/doc/source/whatsnew.rst
+++ b/doc/source/whatsnew.rst
@@ -38,6 +38,10 @@
   typically, console applications that crash close immediately, but that
   is also the situation where stderr should be visible anyway.
 
+* Progress on support for `callbacks in NetBSD`__.
+
+.. __: 
https://bitbucket.org/cffi/cffi/issues/321/cffi-191-segmentation-fault-during-self
+
 
 v1.10.1
 =======
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to