]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
include: detect corrupt frag from byteswap
authorPatrick Donnelly <pdonnell@ibm.com>
Thu, 13 Nov 2025 19:51:20 +0000 (14:51 -0500)
committerVenky Shankar <vshankar@redhat.com>
Wed, 19 Nov 2025 13:06:49 +0000 (13:06 +0000)
Fixes: https://tracker.ceph.com/issues/73792
Signed-off-by: Patrick Donnelly <pdonnell@ibm.com>
(cherry picked from commit 59461534437ed0c422d42b265ab0f401053c8a7f)
Resolves: rhbz#2414841

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

index 452f30ff5dc8e818822169b89b7e851b2edfa8e9..0808e6bee12be5713d18ba103ce7b56cb241395b 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); }