diff options
Diffstat (limited to 'recipes-extended/ceph/ceph/0001-msg-async-ProtocolV2-avoid-AES-GCM-nonce-reuse-vulne.patch')
-rw-r--r-- | recipes-extended/ceph/ceph/0001-msg-async-ProtocolV2-avoid-AES-GCM-nonce-reuse-vulne.patch | 256 |
1 files changed, 0 insertions, 256 deletions
diff --git a/recipes-extended/ceph/ceph/0001-msg-async-ProtocolV2-avoid-AES-GCM-nonce-reuse-vulne.patch b/recipes-extended/ceph/ceph/0001-msg-async-ProtocolV2-avoid-AES-GCM-nonce-reuse-vulne.patch deleted file mode 100644 index 54156698..00000000 --- a/recipes-extended/ceph/ceph/0001-msg-async-ProtocolV2-avoid-AES-GCM-nonce-reuse-vulne.patch +++ /dev/null @@ -1,256 +0,0 @@ -From 20b7bb685c5ea74c651ca1ea547ac66b0fee7035 Mon Sep 17 00:00:00 2001 -From: Ilya Dryomov <idryomov@gmail.com> -Date: Fri, 6 Mar 2020 20:16:45 +0100 -Subject: [PATCH] msg/async/ProtocolV2: avoid AES-GCM nonce reuse - vulnerabilities - -The secure mode uses AES-128-GCM with 96-bit nonces consisting of a -32-bit counter followed by a 64-bit salt. The counter is incremented -after processing each frame, the salt is fixed for the duration of -the session. Both are initialized from the session key generated -during session negotiation, so the counter starts with essentially -a random value. It is allowed to wrap, and, after 2**32 frames, it -repeats, resulting in nonce reuse (the actual sequence numbers that -the messenger works with are 64-bit, so the session continues on). - -Because of how GCM works, this completely breaks both confidentiality -and integrity aspects of the secure mode. A single nonce reuse reveals -the XOR of two plaintexts and almost completely reveals the subkey -used for producing authentication tags. After a few nonces get used -twice, all confidentiality and integrity goes out the window and the -attacker can potentially encrypt-authenticate plaintext of their -choice. - -We can't easily change the nonce format to extend the counter to -64 bits (and possibly XOR it with a longer salt). Instead, just -remember the initial nonce and cut the session before it repeats, -forcing renegotiation. - -Signed-off-by: Ilya Dryomov <idryomov@gmail.com> -Reviewed-by: Radoslaw Zarzynski <rzarzyns@redhat.com> -Reviewed-by: Sage Weil <sage@redhat.com> - -Conflicts: - src/msg/async/ProtocolV2.h [ context: commit ed3ec4c01d17 - ("msg: Build target 'common' without using namespace in - headers") not in octopus ] - -CVE: CVE-2020-1759 -Upstream Status: Backport [20b7bb685c5ea74c651ca1ea547ac66b0fee7035] - -Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com> ---- - src/msg/async/ProtocolV2.cc | 62 ++++++++++++++++++++++++---------- - src/msg/async/ProtocolV2.h | 5 +-- - src/msg/async/crypto_onwire.cc | 17 ++++++++-- - src/msg/async/crypto_onwire.h | 5 +++ - 4 files changed, 67 insertions(+), 22 deletions(-) - -diff --git a/src/msg/async/ProtocolV2.cc b/src/msg/async/ProtocolV2.cc -index 8fc02db6e5..c69f2ccf79 100644 ---- a/src/msg/async/ProtocolV2.cc -+++ b/src/msg/async/ProtocolV2.cc -@@ -533,7 +533,10 @@ ssize_t ProtocolV2::write_message(Message *m, bool more) { - m->get_payload(), - m->get_middle(), - m->get_data()); -- connection->outgoing_bl.append(message.get_buffer(session_stream_handlers)); -+ if (!append_frame(message)) { -+ m->put(); -+ return -EILSEQ; -+ } - - ldout(cct, 5) << __func__ << " sending message m=" << m - << " seq=" << m->get_seq() << " " << *m << dendl; -@@ -566,15 +569,17 @@ ssize_t ProtocolV2::write_message(Message *m, bool more) { - return rc; - } - --void ProtocolV2::append_keepalive() { -- ldout(cct, 10) << __func__ << dendl; -- auto keepalive_frame = KeepAliveFrame::Encode(); -- connection->outgoing_bl.append(keepalive_frame.get_buffer(session_stream_handlers)); --} -- --void ProtocolV2::append_keepalive_ack(utime_t ×tamp) { -- auto keepalive_ack_frame = KeepAliveFrameAck::Encode(timestamp); -- connection->outgoing_bl.append(keepalive_ack_frame.get_buffer(session_stream_handlers)); -+template <class F> -+bool ProtocolV2::append_frame(F& frame) { -+ ceph::bufferlist bl; -+ try { -+ bl = frame.get_buffer(session_stream_handlers); -+ } catch (ceph::crypto::onwire::TxHandlerError &e) { -+ ldout(cct, 1) << __func__ << " " << e.what() << dendl; -+ return false; -+ } -+ connection->outgoing_bl.append(bl); -+ return true; - } - - void ProtocolV2::handle_message_ack(uint64_t seq) { -@@ -612,7 +617,15 @@ void ProtocolV2::write_event() { - connection->write_lock.lock(); - if (can_write) { - if (keepalive) { -- append_keepalive(); -+ ldout(cct, 10) << __func__ << " appending keepalive" << dendl; -+ auto keepalive_frame = KeepAliveFrame::Encode(); -+ if (!append_frame(keepalive_frame)) { -+ connection->write_lock.unlock(); -+ connection->lock.lock(); -+ fault(); -+ connection->lock.unlock(); -+ return; -+ } - keepalive = false; - } - -@@ -663,13 +676,16 @@ void ProtocolV2::write_event() { - if (r == 0) { - uint64_t left = ack_left; - if (left) { -- auto ack = AckFrame::Encode(in_seq); -- connection->outgoing_bl.append(ack.get_buffer(session_stream_handlers)); - ldout(cct, 10) << __func__ << " try send msg ack, acked " << left - << " messages" << dendl; -- ack_left -= left; -- left = ack_left; -- r = connection->_try_send(left); -+ auto ack_frame = AckFrame::Encode(in_seq); -+ if (append_frame(ack_frame)) { -+ ack_left -= left; -+ left = ack_left; -+ r = connection->_try_send(left); -+ } else { -+ r = -EILSEQ; -+ } - } else if (is_queued()) { - r = connection->_try_send(); - } -@@ -769,7 +785,13 @@ template <class F> - CtPtr ProtocolV2::write(const std::string &desc, - CONTINUATION_TYPE<ProtocolV2> &next, - F &frame) { -- ceph::bufferlist bl = frame.get_buffer(session_stream_handlers); -+ ceph::bufferlist bl; -+ try { -+ bl = frame.get_buffer(session_stream_handlers); -+ } catch (ceph::crypto::onwire::TxHandlerError &e) { -+ ldout(cct, 1) << __func__ << " " << e.what() << dendl; -+ return _fault(); -+ } - return write(desc, next, bl); - } - -@@ -1672,7 +1694,11 @@ CtPtr ProtocolV2::handle_keepalive2(ceph::bufferlist &payload) - ldout(cct, 30) << __func__ << " got KEEPALIVE2 tag ..." << dendl; - - connection->write_lock.lock(); -- append_keepalive_ack(keepalive_frame.timestamp()); -+ auto keepalive_ack_frame = KeepAliveFrameAck::Encode(keepalive_frame.timestamp()); -+ if (!append_frame(keepalive_ack_frame)) { -+ connection->write_lock.unlock(); -+ return _fault(); -+ } - connection->write_lock.unlock(); - - ldout(cct, 20) << __func__ << " got KEEPALIVE2 " -diff --git a/src/msg/async/ProtocolV2.h b/src/msg/async/ProtocolV2.h -index 2dbe647ae5..9897d18cf2 100644 ---- a/src/msg/async/ProtocolV2.h -+++ b/src/msg/async/ProtocolV2.h -@@ -129,6 +129,9 @@ private: - CONTINUATION_TYPE<ProtocolV2> &next, - bufferlist &buffer); - -+ template <class F> -+ bool append_frame(F& frame); -+ - void requeue_sent(); - uint64_t discard_requeued_up_to(uint64_t out_seq, uint64_t seq); - void reset_recv_state(); -@@ -140,8 +143,6 @@ private: - void prepare_send_message(uint64_t features, Message *m); - out_queue_entry_t _get_next_outgoing(); - ssize_t write_message(Message *m, bool more); -- void append_keepalive(); -- void append_keepalive_ack(utime_t ×tamp); - void handle_message_ack(uint64_t seq); - - CONTINUATION_DECL(ProtocolV2, _wait_for_peer_banner); -diff --git a/src/msg/async/crypto_onwire.cc b/src/msg/async/crypto_onwire.cc -index acf3f66689..07e7fe6553 100644 ---- a/src/msg/async/crypto_onwire.cc -+++ b/src/msg/async/crypto_onwire.cc -@@ -22,6 +22,10 @@ static constexpr const std::size_t AESGCM_BLOCK_LEN{16}; - struct nonce_t { - std::uint32_t random_seq; - std::uint64_t random_rest; -+ -+ bool operator==(const nonce_t& rhs) const { -+ return !memcmp(this, &rhs, sizeof(*this)); -+ } - } __attribute__((packed)); - static_assert(sizeof(nonce_t) == AESGCM_IV_LEN); - -@@ -35,7 +39,8 @@ class AES128GCM_OnWireTxHandler : public ceph::crypto::onwire::TxHandler { - CephContext* const cct; - std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)> ectx; - ceph::bufferlist buffer; -- nonce_t nonce; -+ nonce_t nonce, initial_nonce; -+ bool used_initial_nonce; - static_assert(sizeof(nonce) == AESGCM_IV_LEN); - - public: -@@ -44,7 +49,7 @@ public: - const nonce_t& nonce) - : cct(cct), - ectx(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_free), -- nonce(nonce) { -+ nonce(nonce), initial_nonce(nonce), used_initial_nonce(false) { - ceph_assert_always(ectx); - ceph_assert_always(key.size() * CHAR_BIT == 128); - -@@ -61,6 +66,7 @@ public: - - ~AES128GCM_OnWireTxHandler() override { - ::ceph::crypto::zeroize_for_security(&nonce, sizeof(nonce)); -+ ::ceph::crypto::zeroize_for_security(&initial_nonce, sizeof(initial_nonce)); - } - - std::uint32_t calculate_segment_size(std::uint32_t size) override -@@ -78,6 +84,13 @@ public: - void AES128GCM_OnWireTxHandler::reset_tx_handler( - std::initializer_list<std::uint32_t> update_size_sequence) - { -+ if (nonce == initial_nonce) { -+ if (used_initial_nonce) { -+ throw ceph::crypto::onwire::TxHandlerError("out of nonces"); -+ } -+ used_initial_nonce = true; -+ } -+ - if(1 != EVP_EncryptInit_ex(ectx.get(), nullptr, nullptr, nullptr, - reinterpret_cast<const unsigned char*>(&nonce))) { - throw std::runtime_error("EVP_EncryptInit_ex failed"); -diff --git a/src/msg/async/crypto_onwire.h b/src/msg/async/crypto_onwire.h -index bd682e8c71..0c544f205a 100644 ---- a/src/msg/async/crypto_onwire.h -+++ b/src/msg/async/crypto_onwire.h -@@ -45,6 +45,11 @@ struct MsgAuthError : public std::runtime_error { - } - }; - -+struct TxHandlerError : public std::runtime_error { -+ TxHandlerError(const char* what) -+ : std::runtime_error(std::string("tx handler error: ") + what) {} -+}; -+ - struct TxHandler { - virtual ~TxHandler() = default; - --- -2.20.1 - |