Commit 4490c04a authored by Jim Fulton's avatar Jim Fulton

Bugs Fixed:

- Fixed vulnerabilities in the ZEO network protocol that allow:

CVE-2009-0668 Arbitrary Python code execution in ZODB ZEO storage servers
  CVE-2009-0669 Authentication bypass in ZODB ZEO storage servers

- Limit the number of object ids that can be allocated at once to
  avoid running out of memory.
parent 73587f58
......@@ -2,6 +2,29 @@
Change History
================
3.9.0b5 (2009-08-06)
====================
Bugs Fixed
----------
- Fixed vulnerabilities in the ZEO network protocol that allow:
- CVE-2009-0668 Arbitrary Python code execution in ZODB ZEO storage servers
- CVE-2009-0669 Authentication bypass in ZODB ZEO storage servers
The vulnerabilities only apply if you are using ZEO to share a
database among multiple applications or application instances and if
untrusted clients are able to connect to your ZEO servers.
3.9.0b4 (2009-07-30)
====================
Bugs Fixed
----------
- Sources were ommitted due to setup script problems.
3.9.0b3 (2009-07-30)
====================
......
......@@ -114,7 +114,7 @@ class ZEOStorage:
# transaction iterator.
self._txn_iterators_last = {}
def finish_auth(self, authenticated):
def _finish_auth(self, authenticated):
if not self.auth_realm:
return 1
self.authenticated = authenticated
......@@ -381,6 +381,7 @@ class ZEOStorage:
def new_oids(self, n=100):
"""Return a sequence of n new oids, where n defaults to 100"""
n = min(n, 100)
if self.read_only:
raise ReadOnlyError()
if n <= 0:
......
......@@ -121,7 +121,7 @@ class StorageClass(ZEOStorage):
check = hexdigest("%s:%s" % (h_up, challenge))
if check == response:
self.connection.setSessionKey(session_key(h_up, self._key_nonce))
return self.finish_auth(check == response)
return self._finish_auth(check == response)
extensions = [auth_get_challenge, auth_response]
......
......@@ -41,7 +41,7 @@ class StorageClass(ZEOStorage):
self.connection.setSessionKey(session_key(username,
self.database.realm,
password))
return self.finish_auth(dbpw == password_dig)
return self._finish_auth(dbpw == password_dig)
class PlaintextClient(Client):
extensions = ["auth"]
......
......@@ -23,7 +23,7 @@ import traceback, time
from ZEO.zrpc import smac
from ZEO.zrpc.error import ZRPCError, DisconnectedError
from ZEO.zrpc.marshal import Marshaller
from ZEO.zrpc.marshal import Marshaller, ServerMarshaller
from ZEO.zrpc.trigger import trigger
from ZEO.zrpc.log import short_repr, log
from ZODB.loglevels import BLATHER, TRACE
......@@ -794,6 +794,7 @@ class ManagedServerConnection(Connection):
def __init__(self, sock, addr, obj, mgr):
self.mgr = mgr
Connection.__init__(self, sock, addr, obj, 'S')
self.marshal = ServerMarshaller()
def handshake(self):
# Send the server's preferred protocol to the client.
......
......@@ -52,6 +52,20 @@ class Marshaller:
level=logging.ERROR)
raise
class ServerMarshaller(Marshaller):
def decode(self, msg):
"""Decodes msg and returns its parts"""
unpickler = cPickle.Unpickler(StringIO(msg))
unpickler.find_global = server_find_global
try:
return unpickler.load() # msgid, flags, name, args
except:
log("can't decode message: %s" % short_repr(msg),
level=logging.ERROR)
raise
_globals = globals()
_silly = ('__doc__',)
......@@ -78,3 +92,19 @@ def find_global(module, name):
return r
raise ZRPCError("Unsafe global: %s.%s" % (module, name))
def server_find_global(module, name):
"""Helper for message unpickler"""
try:
if module != 'ZopeUndo.Prefix':
raise ImportError
m = __import__(module, _globals, _globals, _silly)
except ImportError, msg:
raise ZRPCError("import error %s: %s" % (module, msg))
try:
r = getattr(m, name)
except AttributeError:
raise ZRPCError("module %s has no global %s" % (module, name))
return r
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment