Zope3 security checker python and C code is inconsistent

Reported by Ignas Mikalajūnas on 2008-07-25
2
Affects Status Importance Assigned to Milestone
Zope 3
Undecided
Unassigned

Bug Description

Testing schooltool on python 2.5 I have noticed a strange bug, I was getting "Invalid value, None. for security checker" while displaying a view for Not Found exception, the traceback seemed to indicate that i was getting an error while trying to look up __parent__ for the context object (the not found exception) in a viewlet on that page. I could not find the error in python code, as it only exists in C code and was introduced in:

http://mail.zope.org/pipermail/zope3-checkins/2004-July/021976.html

What I found strange is that python code handles None differently from it's C counterpart. If I remove C modules - both python 2.4 and python 2.5 work properly.

Any ideas why the same C code can be acting differently with different pythons?

And why is the C code implementation of Checker.proxy different from python code?

The python code looks like this:

    def proxy(self, value):
        'See IChecker'
        if type(value) is Proxy:
            return value
        checker = getattr(value, '__Security_checker__', None)
        if checker is None:
            checker = selectChecker(value)
            if checker is None:
                return value

        return Proxy(value, checker)

the C code:

/* def proxy(self, value): */
static PyObject *
Checker_proxy(Checker *self, PyObject *value)
{
  PyObject *checker, *r;

/* if type(value) is Proxy: */
/* return value */
  if ((PyObject*)(value->ob_type) == Proxy)
    {
      Py_INCREF(value);
      return value;
    }

/* checker = getattr(value, '__Security_checker__', None) */
  checker = PyObject_GetAttr(value, str___Security_checker__);
/* if checker is None: */
  if (checker == NULL)
    {
      PyErr_Clear();

/* checker = selectChecker(value) */
      checker = selectChecker(NULL, value);
      if (checker == NULL)
        return NULL;

/* if checker is None: */
/* return value */
      if (checker == Py_None)
        {
          Py_DECREF(checker);
          Py_INCREF(value);
          return value;
        }
    }
  else if (checker == Py_None)
    {
      PyObject *errv = Py_BuildValue("sO",
                                     "Invalid value, None. "
                                     "for security checker",
                                     value);
      if (errv != NULL)
        {
          PyErr_SetObject(PyExc_ValueError, errv);
          Py_DECREF(errv);
        }

      return NULL;
    }

  r = PyObject_CallFunctionObjArgs(Proxy, value, checker, NULL);
  Py_DECREF(checker);
  return r;
}

Ignas Mikalajūnas (ignas) wrote :

Ok, continuing the investigation:

it seems that python2.5 and python2.4 diverged in a different place in the code, as __Security_checker__ is a property not an attribute, the problem is in it's implementation. Which again is different in C from what it is in python...

The method selectChecker in C has:

/* if checker is _defaultChecker and isinstance(object, Exception): */
/* return None */

  if (checker == _defaultChecker
      && PyObject_IsInstance(object, PyExc_Exception))
    {
      Py_INCREF(Py_None);
      return Py_None;
    }

While there is no such line in the python implementation.

And that line seems to be triggered in python2.5 while it is not in python2.4

Any ideas?

Ignas Mikalajūnas (ignas) wrote :

Apparently - all the exceptions ins python2.4 were of <type 'instance'> , and were using _instanceChecker (as defined by zope.security.checker._checkers)

In python2.5 - exceptions have types of their own like: <class 'zope.publisher.interfaces.NotFound'> and _checkers dict
has no entries for these kinds of exceptions so it's as if none of the exceptions have any checkers defined for them.

Thus C implementation of selecChecker returns None for all the Exceptions in python2.5

Albertas Agejevas (alga) wrote :

The underlying bug is fixed in revision 98289.

DecoratedSecurityCheckerDescriptor sometimes returned None as the value of __Security_checker__, which made zope.security.checker.Checker.proxy raise the following exception:

ValueError: ('Invalid value, None. for security checker', NotFound())

Changed in zope3:
status: New → Fix Committed
Wolfgang Schnerring (wosc) wrote :

released as zope.security-3.6.3

Changed in zope3:
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers