From 204bcc8bfcab819f27fc74b2edc0c6272ca5674c Mon Sep 17 00:00:00 2001 From: Patrick Donnelly Date: Thu, 13 Nov 2025 14:51:20 -0500 Subject: [PATCH] include: detect corrupt frag from byteswap If a big-endian MDS writes frag_t values into the metadata pool, these will persist and confuse the MDS after it tries properly parsing them as little-endian. Fortunately detecting this situation is fairly easy as we restrict the number of bits and the number of bits restricts the mask value. Fixes: https://tracker.ceph.com/issues/73792 Signed-off-by: Patrick Donnelly (cherry picked from commit 6bf91e4f6e49d99711b8be845eb77c883d662704) --- src/common/frag.cc | 20 ++++++++++++++++++++ src/include/frag.h | 12 ++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/common/frag.cc b/src/common/frag.cc index aa7e94fe813b..ab6e0a4e868a 100644 --- a/src/common/frag.cc +++ b/src/common/frag.cc @@ -16,7 +16,9 @@ #include "include/types.h" // for operator<<(std::set) #include "common/debug.h" #include "common/Formatter.h" +#include "common/StackStringStream.h" +#include #include #include @@ -38,6 +40,24 @@ void frag_t::encode(ceph::buffer::list& bl) const { void frag_t::decode(ceph::buffer::list::const_iterator& p) { ceph::decode(_enc, p); + if (!is_frag_valid()) { + /* Oops, did this get encoded as big-endian? + * See: https://tracker.ceph.com/issues/73792 + */ + auto nfg = frag_t(boost::endian::endian_reverse(_enc)); + if (nfg.is_frag_valid()) { + std::cerr << "correcting byte swapped frag_t(0x" << std::hex << std::setfill('0') << std::setw(8) << _enc + << ") to frag_t(0x" << std::hex << std::setfill('0') << std::setw(8) << nfg._enc << ")" + << " aka " << nfg + << std::endl; + _enc = nfg._enc; + } else { + CachedStackStringStream css; + *css << "Invalid frag_t(0x" << std::hex << std::setfill('0') << std::setw(8) << _enc << ")"; + throw ceph::buffer::malformed_input(css->str()); + } + } + } void frag_t::dump(ceph::Formatter *f) const { diff --git a/src/include/frag.h b/src/include/frag.h index b58507f8474b..7dbf2468245a 100644 --- a/src/include/frag.h +++ b/src/include/frag.h @@ -101,6 +101,18 @@ public: operator _frag_t() const { return _enc; } + bool is_frag_valid() const { + if (bits() > 24) { + /* bits must be in range [0,24] */ + return false; + } else if ((value() & ~mask()) != 0) { + /* unused bits must be 0 */ + return false; + } else { + return true; + } + } + // tests bool contains(unsigned v) const { return ceph_frag_contains_value(_enc, v); } bool contains(frag_t sub) const { return ceph_frag_contains_frag(_enc, sub._enc); } -- 2.47.3