summaryrefslogtreecommitdiffstats
path: root/test/unit/common/test_utils.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/unit/common/test_utils.py')
-rw-r--r--test/unit/common/test_utils.py82
1 files changed, 81 insertions, 1 deletions
diff --git a/test/unit/common/test_utils.py b/test/unit/common/test_utils.py
index 1fea1fc..0b173be 100644
--- a/test/unit/common/test_utils.py
+++ b/test/unit/common/test_utils.py
@@ -16,6 +16,7 @@
""" Tests for common.utils """
import os
+import json
import unittest
import errno
import xattr
@@ -23,10 +24,12 @@ import tempfile
import hashlib
import tarfile
import shutil
+import cPickle as pickle
from collections import defaultdict
from mock import patch, Mock
from gluster.swift.common import utils, Glusterfs
-from gluster.swift.common.utils import deserialize_metadata, serialize_metadata
+from gluster.swift.common.utils import deserialize_metadata, \
+ serialize_metadata, PICKLE_PROTOCOL
from gluster.swift.common.exceptions import GlusterFileSystemOSError,\
GlusterFileSystemIOError
from swift.common.exceptions import DiskFileNoSpace
@@ -138,6 +141,32 @@ def _mock_os_fsync(fd):
return
+class TestSafeUnpickler(unittest.TestCase):
+
+ class Exploit(object):
+ def __reduce__(self):
+ return (os.system, ('touch /tmp/pickle-exploit',))
+
+ def test_loads(self):
+ valid_md = {'key1': 'val1', 'key2': 'val2'}
+ for protocol in (0, 1, 2):
+ valid_dump = pickle.dumps(valid_md, protocol)
+ mal_dump = pickle.dumps(self.Exploit(), protocol)
+ # malicious dump is appended to valid dump
+ payload1 = valid_dump[:-1] + mal_dump
+ # malicious dump is prefixed to valid dump
+ payload2 = mal_dump[:-1] + valid_dump
+ # entire dump is malicious
+ payload3 = mal_dump
+ for payload in (payload1, payload2, payload3):
+ try:
+ utils.SafeUnpickler.loads(payload)
+ except pickle.UnpicklingError as err:
+ self.assertTrue('Potentially unsafe pickle' in err)
+ else:
+ self.fail("Expecting cPickle.UnpicklingError")
+
+
class TestUtils(unittest.TestCase):
""" Tests for common.utils """
@@ -321,6 +350,57 @@ class TestUtils(unittest.TestCase):
assert _xattr_op_cnt['get'] == 1, "%r" % _xattr_op_cnt
assert _xattr_op_cnt['set'] == 0, "%r" % _xattr_op_cnt
+ def test_deserialize_metadata_pickle(self):
+ orig__read_pickled_metadata = Glusterfs._read_pickled_metadata
+ orig_md = {'key1': 'value1', 'key2': 'value2'}
+ pickled_md = pickle.dumps(orig_md, PICKLE_PROTOCOL)
+ _m_pickle_loads = Mock(return_value={})
+ try:
+ with patch('gluster.swift.common.utils.pickle.loads',
+ _m_pickle_loads):
+ # Conf option turned off
+ Glusterfs._read_pickled_metadata = False
+ # pickled
+ utils.deserialize_metadata(pickled_md)
+ self.assertFalse(_m_pickle_loads.called)
+ _m_pickle_loads.reset_mock()
+ # not pickled
+ utils.deserialize_metadata("not_pickle")
+ self.assertFalse(_m_pickle_loads.called)
+ _m_pickle_loads.reset_mock()
+
+ # Conf option turned on
+ Glusterfs._read_pickled_metadata = True
+ # pickled
+ md = utils.deserialize_metadata(pickled_md)
+ self.assertTrue(_m_pickle_loads.called)
+ self.assertTrue(isinstance(md, dict))
+ _m_pickle_loads.reset_mock()
+ # not pickled
+ utils.deserialize_metadata("not_pickle")
+ self.assertFalse(_m_pickle_loads.called)
+ _m_pickle_loads.reset_mock()
+
+ # malformed pickle
+ _m_pickle_loads.side_effect = pickle.UnpicklingError
+ md = utils.deserialize_metadata("malformed_pickle")
+ self.assertTrue(isinstance(md, dict))
+ finally:
+ Glusterfs._read_pickled_metadata = orig__read_pickled_metadata
+
+ def test_deserialize_metadata_json(self):
+ orig_md = {'key1': 'value1', 'key2': 'value2'}
+ json_md = json.dumps(orig_md, separators=(',', ':'))
+ _m_json_loads = Mock(return_value={})
+ with patch('gluster.swift.common.utils.json.loads',
+ _m_json_loads):
+ utils.deserialize_metadata("not_json")
+ self.assertFalse(_m_json_loads.called)
+ _m_json_loads.reset_mock()
+ utils.deserialize_metadata("{fake_valid_json}")
+ self.assertTrue(_m_json_loads.called)
+ _m_json_loads.reset_mock()
+
def test_add_timestamp_empty(self):
orig = {}
res = utils._add_timestamp(orig)