scripts: Added better branch cksum checks

If we're fetching branches anyways, we might as well check that the
checksums match. This helps protect against infinite loops in B-tree
branches.

Also fixed an issue where we weren't xoring perturb state on finding an
explicit trunk.

Note this is equivalent to LFS_M_CKFETCHES in lfs.c.

---

This doesn't mean we always need LFS_M_CKFETCHES. Our dbg scripts just
need to be a little bit tougher because 1. running tests with -j creates
wildly corrupted and entangled littlefs images, and 2. Rbyd.fetch is
almost too forgiving in choosing the nearest trunk.
This commit is contained in:
Christopher Haster
2024-11-07 14:07:27 -06:00
parent e3fdc3dbd7
commit 0260f0bcee
5 changed files with 100 additions and 79 deletions

View File

@@ -616,13 +616,13 @@ class Rbyd:
self.trunk)
@classmethod
def fetch(cls, f, block_size, blocks, trunk=None):
def fetch(cls, f, block_size, blocks, trunk=None, cksum=None):
if isinstance(blocks, int):
blocks = (blocks,)
if len(blocks) > 1:
# fetch all blocks
rbyds = [cls.fetch(f, block_size, block, trunk)
rbyds = [cls.fetch(f, block_size, block, trunk, cksum)
for block in blocks]
# determine most recent revision
i = 0
@@ -654,9 +654,9 @@ class Rbyd:
# fetch the rbyd
rev = fromle32(data[0:4])
cksum = 0
cksum_ = crc32c(data[0:4])
cksum__ = cksum_
cksum_ = 0
cksum__ = crc32c(data[0:4])
cksum___ = cksum__
perturb = False
eoff = 0
eoff_ = None
@@ -670,10 +670,10 @@ class Rbyd:
while j_ < len(data) and (not trunk or eoff <= trunk):
# read next tag
v, tag, w, size, d = fromtag(data[j_:])
if v != parity(cksum__):
if v != parity(cksum___):
break
cksum__ ^= 0x00000080 if v else 0
cksum__ = crc32c(data[j_:j_+d], cksum__)
cksum___ ^= 0x00000080 if v else 0
cksum___ = crc32c(data[j_:j_+d], cksum___)
j_ += d
if not tag & TAG_ALT and j_ + size > len(data):
break
@@ -681,22 +681,22 @@ class Rbyd:
# take care of cksums
if not tag & TAG_ALT:
if (tag & 0xff00) != TAG_CKSUM:
cksum__ = crc32c(data[j_:j_+size], cksum__)
cksum___ = crc32c(data[j_:j_+size], cksum___)
# found a cksum?
else:
# check cksum
cksum___ = fromle32(data[j_:j_+4])
if cksum__ != cksum___:
cksum____ = fromle32(data[j_:j_+4])
if cksum___ != cksum____:
break
# commit what we have
eoff = eoff_ if eoff_ else j_ + size
cksum = cksum_
cksum_ = cksum__
trunk_ = trunk__
weight = weight_
# update perturb bit
perturb = tag & TAG_P
# revert to data cksum and perturb
cksum__ = cksum_ ^ (0xfca42daf if perturb else 0)
cksum___ = cksum__ ^ (0xfca42daf if perturb else 0)
# evaluate trunks
if (tag & 0xf000) != TAG_CKSUM:
@@ -720,18 +720,23 @@ class Rbyd:
if trunk and j_ + size > trunk:
eoff_ = j_ + size
eoff = eoff_
cksum = cksum_
cksum_ = cksum___ ^ (
0xfca42daf if perturb else 0)
trunk_ = trunk__
weight = weight_
trunk___ = 0
# update canonical checksum, xoring out any perturb state
cksum_ = cksum__ ^ (0xfca42daf if perturb else 0)
cksum__ = cksum___ ^ (0xfca42daf if perturb else 0)
if not tag & TAG_ALT:
j_ += size
return cls(block, data, rev, eoff, trunk_, weight, cksum)
# cksum mismatch?
if cksum is not None and cksum_ != cksum:
return cls(block, data, rev, 0, 0, 0, cksum_)
return cls(block, data, rev, eoff, trunk_, weight, cksum_)
def lookup(self, rid, tag):
if not self:
@@ -861,7 +866,7 @@ class Rbyd:
not depth or depth_ < depth):
tag, j, d, data = branch
block, trunk, cksum = frombranch(data)
rbyd = Rbyd.fetch(f, block_size, block, trunk)
rbyd = Rbyd.fetch(f, block_size, block, trunk, cksum)
# corrupted? bail here so we can keep traversing the tree
if not rbyd:
@@ -878,7 +883,7 @@ class Rbyd:
done, rid, tag, w, j, d, data, _ = self.lookup(-1, TAG_MTREE)
if not done and rid == -1 and tag == TAG_MTREE:
w, block, trunk, cksum = frombtree(data)
mtree = Rbyd.fetch(f, block_size, block, trunk)
mtree = Rbyd.fetch(f, block_size, block, trunk, cksum)
# corrupted?
if not mtree:
return True, -1, 0, None
@@ -1161,7 +1166,7 @@ def main(disk, mroots=None, *,
done, rid, tag, w, j, d, data, _ = mroot.lookup(-1, TAG_MTREE)
if not done and rid == -1 and tag == TAG_MTREE:
w, block, trunk, cksum = frombtree(data)
mtree = Rbyd.fetch(f, block_size, block, trunk)
mtree = Rbyd.fetch(f, block_size, block, trunk, cksum)
# traverse entries
mbid = -1
@@ -1263,7 +1268,7 @@ def main(disk, mroots=None, *,
# indirect btree?
elif tag == TAG_BTREE:
w, block, trunk, cksum = frombtree(data)
btree = Rbyd.fetch(f, block_size, block, trunk)
btree = Rbyd.fetch(f, block_size, block, trunk, cksum)
shrub = False
else: