]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
msg/async, v2: introduce frame late abort facility.
authorRadoslaw Zarzynski <rzarzyns@redhat.com>
Mon, 4 Mar 2019 00:43:43 +0000 (01:43 +0100)
committerRadoslaw Zarzynski <rzarzyns@redhat.com>
Mon, 4 Mar 2019 00:50:14 +0000 (01:50 +0100)
Signed-off-by: Radoslaw Zarzynski <rzarzyns@redhat.com>
src/include/msgr.h
src/msg/async/ProtocolV2.cc
src/msg/async/frames_v2.h

index c61bebda0f61e9cf83331ed9ae3b2f2bd2fca4a5..4029443d0a4e588b5288c92ba50b511220134a70 100644 (file)
@@ -235,7 +235,6 @@ struct ceph_msg_footer {
 #define CEPH_MSG_FOOTER_COMPLETE  (1<<0)   /* msg wasn't aborted */
 #define CEPH_MSG_FOOTER_NOCRC     (1<<1)   /* no data crc */
 #define CEPH_MSG_FOOTER_SIGNED   (1<<2)   /* msg was signed */
-#define CEPH_MSG_FOOTER_LATEABRT  (1<<3)   /* msg was aborted after txing data */
 
 
 #endif
index fa4776d2b6bee484716c5f5a5d9a89828a34c99f..ff5cff1686f5eece123fe800b3d203cd10a3e4ee 100644 (file)
@@ -701,11 +701,13 @@ uint32_t ProtocolV2::get_onwire_size(uint32_t logical_size) const {
 
 uint32_t ProtocolV2::get_epilogue_size() const {
   // In secure mode size of epilogue is flexible and depends on particular
-  // cipher implementation. See the comment for epilogue_crc_block_t.
+  // cipher implementation. See the comment for epilogue_secure_block_t or
+  // epilogue_plain_block_t.
   if (session_stream_handlers.rx) {
-    return session_stream_handlers.rx->get_extra_size_at_final();
+    return FRAME_SECURE_EPILOGUE_SIZE + \
+        session_stream_handlers.rx->get_extra_size_at_final();
   } else {
-    return FRAME_CRC_EPILOGUE_SIZE;
+    return FRAME_PLAIN_EPILOGUE_SIZE;
   }
 }
 
@@ -1278,28 +1280,33 @@ CtPtr ProtocolV2::handle_read_frame_epilogue_main(char *buffer, int r)
     return _fault();
   }
 
+  __u8 late_flags;
+
   // FIXME: if (auth_meta->is_mode_secure()) {
   if (session_stream_handlers.rx) {
-    // if we still have more bytes to read is because we signed or encrypted
-    // the message payload
     ldout(cct, 1) << __func__ << " read frame epilogue bytes="
                   << get_epilogue_size() << dendl;
 
-    // I expect that ::temp_buffer is being used here.
+    // decrypt epilogue and authenticate entire frame.
     ceph::bufferlist epilogue_bl;
-    epilogue_bl.push_back(buffer::create_static(get_epilogue_size(),
-        buffer));
-    try {
-      session_stream_handlers.rx->authenticated_decrypt_update_final(
-       std::move(epilogue_bl), segment_t::DEFAULT_ALIGNMENT);
-    } catch (ceph::crypto::onwire::MsgAuthError &e) {
-      ldout(cct, 5) << __func__ << " message authentication failed: "
-                   << e.what() << dendl;
-      ceph_assert("oops" == nullptr);
-      return _fault();
+    {
+      epilogue_bl.push_back(buffer::create_static(get_epilogue_size(),
+          buffer));
+      try {
+        epilogue_bl =
+            session_stream_handlers.rx->authenticated_decrypt_update_final(
+               std::move(epilogue_bl), segment_t::DEFAULT_ALIGNMENT);
+      } catch (ceph::crypto::onwire::MsgAuthError &e) {
+        ldout(cct, 5) << __func__ << " message authentication failed: "
+                      << e.what() << dendl;
+        return _fault();
+      }
     }
+    auto& epilogue =
+        reinterpret_cast<epilogue_plain_block_t&>(*epilogue_bl.c_str());
+    late_flags = epilogue.late_flags;
   } else {
-    auto& epilogue = reinterpret_cast<epilogue_crc_block_t&>(*buffer);
+    auto& epilogue = reinterpret_cast<epilogue_plain_block_t&>(*buffer);
 
     for (std::uint8_t idx = 0; idx < rx_segments_data.size(); idx++) {
       const __u32 expected_crc = epilogue.crc_values[idx];
@@ -1317,9 +1324,19 @@ CtPtr ProtocolV2::handle_read_frame_epilogue_main(char *buffer, int r)
                       << dendl;
       }
     }
+    late_flags = epilogue.late_flags;
   }
 
-  return handle_read_frame_dispatch();
+  // we do have a mechanism that allows transmitter to start sending message
+  // and abort after putting entire data field on wire. This will be used by
+  // the kernel client to avoid unnecessary buffering.
+  if (late_flags & FRAME_FLAGS_LATEABRT) {
+    reset_throttle();
+    state = READY;
+    return CONTINUE(read_frame);
+  } else {
+    return handle_read_frame_dispatch();
+  }
 }
 
 CtPtr ProtocolV2::handle_message() {
@@ -1374,17 +1391,6 @@ CtPtr ProtocolV2::handle_message() {
                          0};
   ceph_msg_footer footer{0, 0, 0, 0, current_header.flags};
 
-  // we do have a mechanism that allows transmitter to start sending message
-  // and abort after putting entire data field on wire. This will be used by
-  // the kernel client to avoid unnecessary buffering.
-  if (current_header.flags & CEPH_MSG_FOOTER_LATEABRT) {
-    ceph_assert(state == THROTTLE_DONE);
-
-    reset_throttle();
-    state = READY;
-    return CONTINUE(read_frame);
-  }
-
   Message *message = decode_message(cct, 0, header, footer,
       rx_segments_data[SegmentIndex::Msg::FRONT],
       rx_segments_data[SegmentIndex::Msg::MIDDLE],
index 010b14c79e52bd733ca3923f7ed5dce8790c652b..94a729684077010b3eb9f27e8f5f2996eaf48fea 100644 (file)
@@ -119,15 +119,33 @@ static_assert(std::is_standard_layout<preamble_block_t>::value);
 // *auth tag* (following OpenSSL's terminology). However, it would be OK
 // to switch to e.g. AES128-CBC + HMAC-SHA512 without affecting protocol
 // (expect the cipher negotiation, of course).
-struct epilogue_crc_block_t {
+//
+// In addition to integrity/authenticity data each variant of epilogue
+// conveys late_flags. The initial user of this field will be the late
+// frame abortion facility.
+struct epilogue_plain_block_t {
+  __u8 late_flags;
   std::array<__le32, MAX_NUM_SEGMENTS> crc_values;
-};
-static_assert(sizeof(epilogue_crc_block_t) % CRYPTO_BLOCK_SIZE == 0);
-static_assert(std::is_standard_layout<epilogue_crc_block_t>::value);
+} __attribute__((packed));
+static_assert(std::is_standard_layout<epilogue_plain_block_t>::value);
+
+struct epilogue_secure_block_t {
+  __u8 late_flags;
+  __u8 padding[CRYPTO_BLOCK_SIZE - sizeof(late_flags)];
+
+  __u8 ciphers_private_data[];
+} __attribute__((packed));
+static_assert(sizeof(epilogue_secure_block_t) % CRYPTO_BLOCK_SIZE == 0);
+static_assert(std::is_standard_layout<epilogue_secure_block_t>::value);
 
 
 static constexpr uint32_t FRAME_PREAMBLE_SIZE = sizeof(preamble_block_t);
-static constexpr uint32_t FRAME_CRC_EPILOGUE_SIZE = sizeof(epilogue_crc_block_t);
+static constexpr uint32_t FRAME_PLAIN_EPILOGUE_SIZE =
+    sizeof(epilogue_plain_block_t);
+static constexpr uint32_t FRAME_SECURE_EPILOGUE_SIZE =
+    sizeof(epilogue_secure_block_t);
+
+#define FRAME_FLAGS_LATEABRT      (1<<0)   /* frame was aborted after txing data */
 
 template <class T>
 struct Frame {
@@ -177,7 +195,7 @@ public:
     fill_preamble({segment_t{payload.length() - FRAME_PREAMBLE_SIZE,
                    segment_t::DEFAULT_ALIGNMENT}});
 
-    epilogue_crc_block_t epilogue;
+    epilogue_plain_block_t epilogue;
     ::memset(&epilogue, 0, sizeof(epilogue));
 
     ceph::bufferlist::const_iterator hdriter(&this->payload, FRAME_PREAMBLE_SIZE);
@@ -376,6 +394,10 @@ struct SignedEncryptedFrame : public PayloadFrame<T, Args...> {
                      segment_t::DEFAULT_ALIGNMENT}});
 
     if (session_stream_handlers.tx) {
+      epilogue_secure_block_t epilogue;
+      ::memset(&epilogue, 0, sizeof(epilogue));
+      c.payload.append(reinterpret_cast<const char*>(&epilogue), sizeof(epilogue));
+
       ceph_assert(session_stream_handlers.tx);
       session_stream_handlers.tx->reset_tx_handler({c.payload.length()});
 
@@ -383,7 +405,7 @@ struct SignedEncryptedFrame : public PayloadFrame<T, Args...> {
           std::move(c.payload));
       c.payload = session_stream_handlers.tx->authenticated_encrypt_final();
     } else {
-      epilogue_crc_block_t epilogue;
+      epilogue_plain_block_t epilogue;
       ::memset(&epilogue, 0, sizeof(epilogue));
 
       ceph::bufferlist::const_iterator hdriter(&c.payload, FRAME_PREAMBLE_SIZE);
@@ -644,10 +666,22 @@ struct MessageHeaderFrame
         session_stream_handlers.tx->authenticated_encrypt_update(data);
       }
 
+      // craft the secure's mode epilogue
+      {
+        epilogue_secure_block_t epilogue;
+        ::memset(&epilogue, 0, sizeof(epilogue));
+        ceph::bufferlist epilogue_bl;
+        epilogue_bl.append(reinterpret_cast<const char*>(&epilogue),
+                                   sizeof(epilogue));
+        session_stream_handlers.tx->authenticated_encrypt_update(epilogue_bl);
+      }
+
       // auth tag will be appended at the end
       f.payload = session_stream_handlers.tx->authenticated_encrypt_final();
     } else {
-      epilogue_crc_block_t epilogue;
+      epilogue_plain_block_t epilogue;
+      ::memset(&epilogue, 0, sizeof(epilogue));
+
       ceph::bufferlist::const_iterator hdriter(&f.payload, FRAME_PREAMBLE_SIZE);
       epilogue.crc_values[SegmentIndex::Msg::HEADER] =
           hdriter.crc32c(hdriter.get_remaining(), -1);