CVE-2018-1129 (published 2018-07-10T14:29Z)

A flaw was found in the way signature calculation was handled by cephx authentication protocol. An attacker having access to ceph cluster network who is able to alter the message payload was able to bypass signature checks done by cephx protocol. Ceph branches master, mimic, luminous and jewel are believed to be vulnerable.

Severity: LOW
CVSS v2 base score: 3.3 (AV:A/AC:L/Au:N/C:N/I:P/A:N)
CVSS v3 base score: 6.5, MEDIUM (CVSS:3.0/AV:A/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N)

Weakness information:
cwe_id: CWE-287
cwe_name: Improper Authentication
description: When an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct.
extended_description: 
            
			
         
         

Fix information:
repo_url: https://github.com/ceph/ceph
commit_details: repo_url: https://github.com/ceph/ceph
author: Sage Weil
author_date: 2018-05-04 10:21:26-05:00
msg: auth/cephx/CephxSessionHandler: implement CEPHX_V2 calculation mode

Derive the signature from the entire buffer (both cipher blocks).

Signed-off-by: Sage Weil <sage@redhat.com>
repository: repo_url: https://github.com/ceph/ceph
repo_name: ceph/ceph
description: Ceph is a distributed object, block, and file storage platform 
repo_language: C++
owner: ceph
file_changes: filename: CephxSessionHandler.cc
change_type: ModificationType.MODIFY
diff: @@ -29,42 +29,88 @@ int CephxSessionHandler::_calc_signature(Message *m, uint64_t *psig)
   const ceph_msg_header& header = m->get_header();
   const ceph_msg_footer& footer = m->get_footer();
 
-  // optimized signature calculation
-  // - avoid temporary allocated buffers from encode_encrypt[_enc_bl]
-  // - skip the leading 4 byte wrapper from encode_encrypt
-  struct {
-    __u8 v;
-    __le64 magic;
-    __le32 len;
-    __le32 header_crc;
-    __le32 front_crc;
-    __le32 middle_crc;
-    __le32 data_crc;
-  } __attribute__ ((packed)) sigblock = {
-    1, mswab(AUTH_ENC_MAGIC), mswab<uint32_t>(4*4),
-    mswab<uint32_t>(header.crc), mswab<uint32_t>(footer.front_crc),
-    mswab<uint32_t>(footer.middle_crc), mswab<uint32_t>(footer.data_crc)
-  };
-
-  char exp_buf[CryptoKey::get_max_outbuf_size(sizeof(sigblock))];
-
-  try {
-    const CryptoKey::in_slice_t in {
-      sizeof(sigblock),
-      reinterpret_cast<const unsigned char*>(&sigblock)
+  if (!HAVE_FEATURE(features, CEPHX_V2)) {
+    // legacy pre-mimic behavior for compatibility
+
+    // optimized signature calculation
+    // - avoid temporary allocated buffers from encode_encrypt[_enc_bl]
+    // - skip the leading 4 byte wrapper from encode_encrypt
+    struct {
+      __u8 v;
+      __le64 magic;
+      __le32 len;
+      __le32 header_crc;
+      __le32 front_crc;
+      __le32 middle_crc;
+      __le32 data_crc;
+    } __attribute__ ((packed)) sigblock = {
+      1, mswab(AUTH_ENC_MAGIC), mswab<uint32_t>(4*4),
+      mswab<uint32_t>(header.crc), mswab<uint32_t>(footer.front_crc),
+      mswab<uint32_t>(footer.middle_crc), mswab<uint32_t>(footer.data_crc)
     };
-    const CryptoKey::out_slice_t out {
-      sizeof(exp_buf),
-      reinterpret_cast<unsigned char*>(&exp_buf)
+
+    char exp_buf[CryptoKey::get_max_outbuf_size(sizeof(sigblock))];
+
+    try {
+      const CryptoKey::in_slice_t in {
+	sizeof(sigblock),
+	reinterpret_cast<const unsigned char*>(&sigblock)
+      };
+      const CryptoKey::out_slice_t out {
+	sizeof(exp_buf),
+	reinterpret_cast<unsigned char*>(&exp_buf)
+      };
+      key.encrypt(cct, in, out);
+    } catch (std::exception& e) {
+      lderr(cct) << __func__ << " failed to encrypt signature block" << dendl;
+      return -1;
+    }
+
+    *psig = *reinterpret_cast<__le64*>(exp_buf);
+  } else {
+    // newer mimic+ signatures
+    struct {
+      __le32 header_crc;
+      __le32 front_crc;
+      __le32 front_len;
+      __le32 middle_crc;
+      __le32 middle_len;
+      __le32 data_crc;
+      __le32 data_len;
+      __le32 seq_lower_word;
+    } __attribute__ ((packed)) sigblock = {
+      mswab<uint32_t>(header.crc),
+      mswab<uint32_t>(footer.front_crc),
+      mswab<uint32_t>(header.front_len),
+      mswab<uint32_t>(footer.middle_crc),
+      mswab<uint32_t>(header.middle_len),
+      mswab<uint32_t>(footer.data_crc),
+      mswab<uint32_t>(header.data_len),
+      mswab<uint32_t>(header.seq)
     };
 
-    key.encrypt(cct, in, out);
-  } catch (std::exception& e) {
-    lderr(cct) << __func__ << " failed to encrypt signature block" << dendl;
-    return -1;
-  }
+    char exp_buf[CryptoKey::get_max_outbuf_size(sizeof(sigblock))];
+
+    try {
+      const CryptoKey::in_slice_t in {
+	sizeof(sigblock),
+	reinterpret_cast<const unsigned char*>(&sigblock)
+      };
+      const CryptoKey::out_slice_t out {
+	sizeof(exp_buf),
+	reinterpret_cast<unsigned char*>(&exp_buf)
+      };
+      key.encrypt(cct, in, out);
+    } catch (std::exception& e) {
+      lderr(cct) << __func__ << " failed to encrypt signature block" << dendl;
+      return -1;
+    }
 
-  *psig = *reinterpret_cast<__le64*>(exp_buf);
+    struct enc {
+      __le64 a, b, c, d;
+    } *penc = reinterpret_cast<enc*>(exp_buf);
+    *psig = penc->a ^ penc->b ^ penc->c ^ penc->d;
+  }
 
   ldout(cct, 10) << __func__ << " seq " << m->get_seq()
 		 << " front_crc_ = " << footer.front_crc

programming_language: C++