]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
include: detect corrupt frag from byteswap 66540/head
authorPatrick Donnelly <pdonnell@ibm.com>
Thu, 13 Nov 2025 19:51:20 +0000 (14:51 -0500)
committerPatrick Donnelly <pdonnell@ibm.com>
Sat, 6 Dec 2025 01:01:21 +0000 (20:01 -0500)
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 <pdonnell@ibm.com>
(cherry picked from commit 6bf91e4f6e49d99711b8be845eb77c883d662704)

src/common/frag.cc
src/include/frag.h

index aa7e94fe813b929d4ce365a2701ef4cd4a6ba22a..ab6e0a4e868ae8194d23280ad28207c68e83f98b 100644 (file)
@@ -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 <boost/endian/conversion.hpp>
 #include <fmt/format.h>
 
 #include <iostream>
@@ -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 {
index 0ee481a9869df4f91c303d534d941ccef9b97543..f30981c58189dd96fd79ec5bb0821e239d532ed2 100644 (file)
@@ -100,6 +100,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); }