From: Zooko O'Whielacronx Date: Sat, 3 Jan 2009 18:44:27 +0000 (-0700) Subject: immutable: fix test for truncated reads of URI extension block size X-Git-Url: https://git.rkrishnan.org/pf/content/install.html?a=commitdiff_plain;h=5954ab456d6c625b9e7c837723dd1cac5bd3e8e6;p=tahoe-lafs%2Ftahoe-lafs.git immutable: fix test for truncated reads of URI extension block size --- diff --git a/src/allmydata/immutable/layout.py b/src/allmydata/immutable/layout.py index 1f5de5ab..aec80b38 100644 --- a/src/allmydata/immutable/layout.py +++ b/src/allmydata/immutable/layout.py @@ -3,7 +3,7 @@ from zope.interface import implements from twisted.internet import defer from allmydata.interfaces import IStorageBucketWriter, IStorageBucketReader, \ FileTooLargeError, HASH_SIZE -from allmydata.util import mathutil, idlib +from allmydata.util import log, mathutil, idlib from allmydata.util.assertutil import precondition from allmydata import storage diff --git a/src/allmydata/test/test_immutable.py b/src/allmydata/test/test_immutable.py index dd4da451..82def7d7 100644 --- a/src/allmydata/test/test_immutable.py +++ b/src/allmydata/test/test_immutable.py @@ -63,9 +63,9 @@ def _corrupt_segment_size(data): sharevernum = struct.unpack(">l", data[0x0c:0x0c+4])[0] assert sharevernum in (1, 2), "This test is designed to corrupt immutable shares of v1 or v2 in specific ways." if sharevernum == 1: - return corrupt_field(data, 0x0c+0x04, 4, debug=True) + return corrupt_field(data, 0x0c+0x04, 4, debug=False) else: - return corrupt_field(data, 0x0c+0x04, 8, debug=True) + return corrupt_field(data, 0x0c+0x04, 8, debug=False) def _corrupt_size_of_sharedata(data): """ Scramble the file data -- the field showing the size of the data within the share @@ -94,9 +94,9 @@ def _corrupt_offset_of_ciphertext_hash_tree(data): sharevernum = struct.unpack(">l", data[0x0c:0x0c+4])[0] assert sharevernum in (1, 2), "This test is designed to corrupt immutable shares of v1 or v2 in specific ways." if sharevernum == 1: - return corrupt_field(data, 0x0c+0x14, 4, debug=True) + return corrupt_field(data, 0x0c+0x14, 4, debug=False) else: - return corrupt_field(data, 0x0c+0x24, 8, debug=True) + return corrupt_field(data, 0x0c+0x24, 8, debug=False) def _corrupt_offset_of_block_hashes(data): """ Scramble the file data -- the field showing the offset of the block hash tree within @@ -128,6 +128,23 @@ def _corrupt_offset_of_uri_extension(data): else: return corrupt_field(data, 0x0c+0x3c, 8) +def _corrupt_offset_of_uri_extension_to_force_short_read(data, debug=False): + """ Scramble the file data -- the field showing the offset of the uri extension will be set + to the size of the file minus 3. This means when the client tries to read the length field + from that location it will get a short read -- the result string will be only 3 bytes long, + not the 4 or 8 bytes necessary to do a successful struct.unpack.""" + sharevernum = struct.unpack(">l", data[0x0c:0x0c+4])[0] + assert sharevernum in (1, 2), "This test is designed to corrupt immutable shares of v1 or v2 in specific ways." + # The "-0x0c" in here is to skip the server-side header in the share file, which the client doesn't see when seeking and reading. + if sharevernum == 1: + if debug: + log.msg("testing: corrupting offset %d, size %d, changing %d to %d (len(data) == %d)" % (0x2c, 4, struct.unpack(">L", data[0x2c:0x2c+4])[0], len(data)-0x0c-3, len(data))) + return data[:0x2c] + struct.pack(">L", len(data)-0x0c-3) + data[0x2c+4:] + else: + if debug: + log.msg("testing: corrupting offset %d, size %d, changing %d to %d (len(data) == %d)" % (0x48, 8, struct.unpack(">Q", data[0x48:0x48+8])[0], len(data)-0x0c-3, len(data))) + return data[:0x48] + struct.pack(">Q", len(data)-0x0c-3) + data[0x48+8:] + def _corrupt_share_data(data): """ Scramble the file data -- the field containing the share data itself will have one bit flipped or else will be changed to a random value. """ @@ -341,12 +358,18 @@ class Test(ShareManglingMixin, unittest.TestCase): shares[k] = corruptor_func(shares[k]) self.replace_shares(shares, storage_index=self.uri.storage_index) + def _corrupt_all_shares(self, unused, corruptor_func): + """ All shares on disk will be corrupted by corruptor_func. """ + shares = self.find_shares() + for k in shares.keys(): + self._corrupt_a_share(unused, corruptor_func, k[1]) + def _corrupt_a_random_share(self, unused, corruptor_func): """ Exactly one share on disk will be corrupted by corruptor_func. """ shares = self.find_shares() ks = shares.keys() k = random.choice(ks) - return self._corrupt_a_share(unused, corruptor_func, k) + return self._corrupt_a_share(unused, corruptor_func, k[1]) def test_download(self): """ Basic download. (This functionality is more or less already tested by test code in @@ -646,6 +669,7 @@ class Test(ShareManglingMixin, unittest.TestCase): _corrupt_offset_of_block_hashes, _corrupt_offset_of_share_hashes, _corrupt_offset_of_uri_extension, + _corrupt_offset_of_uri_extension_to_force_short_read, _corrupt_share_data, _corrupt_crypttext_hash_tree, _corrupt_block_hashes,