From 44d8fec01e309bf5c02ee4e757fb7f71aee8d4d6 Mon Sep 17 00:00:00 2001 From: Xinze Chi Date: Thu, 3 Mar 2022 21:20:24 +0800 Subject: [PATCH] fix CVE-2021-20288 Signed-off-by: Xinze Chi --- 0025-CVE-2021-20288-1.patch | 68 +++++++++++ 0026-CVE-2021-20288-2.patch | 232 ++++++++++++++++++++++++++++++++++++ 0027-CVE-2021-20288-3.patch | 73 ++++++++++++ ceph.spec | 8 +- 4 files changed, 380 insertions(+), 1 deletion(-) create mode 100644 0025-CVE-2021-20288-1.patch create mode 100644 0026-CVE-2021-20288-2.patch create mode 100644 0027-CVE-2021-20288-3.patch diff --git a/0025-CVE-2021-20288-1.patch b/0025-CVE-2021-20288-1.patch new file mode 100644 index 0000000..4ec2b8d --- /dev/null +++ b/0025-CVE-2021-20288-1.patch @@ -0,0 +1,68 @@ +From 17f736d91d372c5f932a86643e231fbbe4ad6a60 Mon Sep 17 00:00:00 2001 +From: Ilya Dryomov +Date: Thu, 15 Apr 2021 09:47:50 +0200 +Subject: [PATCH 1/3] auth/cephx: drop redundant + KeyServerData::get_service_secret() overload + +Signed-off-by: Ilya Dryomov +(cherry picked from commit 3078af716505ae754723864786a41a6d6af0534c) +--- + src/auth/cephx/CephxKeyServer.cc | 20 +++++--------------- + src/auth/cephx/CephxKeyServer.h | 2 -- + 2 files changed, 5 insertions(+), 17 deletions(-) + +diff --git a/src/auth/cephx/CephxKeyServer.cc b/src/auth/cephx/CephxKeyServer.cc +index ec9fe990382..dccee44d9a7 100644 +--- a/src/auth/cephx/CephxKeyServer.cc ++++ b/src/auth/cephx/CephxKeyServer.cc +@@ -22,7 +22,7 @@ + #define dout_prefix *_dout << "cephx keyserverdata: " + + bool KeyServerData::get_service_secret(CephContext *cct, uint32_t service_id, +- ExpiringCryptoKey& secret, uint64_t& secret_id) const ++ CryptoKey& secret, uint64_t& secret_id) const + { + map::const_iterator iter = + rotating_secrets.find(service_id); +@@ -43,21 +43,11 @@ bool KeyServerData::get_service_secret(CephContext *cct, uint32_t service_id, + ++riter; // "current" key has expired, use "next" key instead + + secret_id = riter->first; +- secret = riter->second; +- ldout(cct, 30) << "get_service_secret service " << ceph_entity_type_name(service_id) +- << " id " << secret_id << " " << secret << dendl; +- return true; +-} +- +-bool KeyServerData::get_service_secret(CephContext *cct, uint32_t service_id, +- CryptoKey& secret, uint64_t& secret_id) const +-{ +- ExpiringCryptoKey e; +- +- if (!get_service_secret(cct, service_id, e, secret_id)) +- return false; ++ secret = riter->second.key; + +- secret = e.key; ++ ldout(cct, 30) << __func__ << " service " ++ << ceph_entity_type_name(service_id) << " secret_id " ++ << secret_id << " " << riter->second << dendl; + return true; + } + +diff --git a/src/auth/cephx/CephxKeyServer.h b/src/auth/cephx/CephxKeyServer.h +index cd3cf123467..2a342e30302 100644 +--- a/src/auth/cephx/CephxKeyServer.h ++++ b/src/auth/cephx/CephxKeyServer.h +@@ -95,8 +95,6 @@ struct KeyServerData { + secrets.erase(iter); + } + +- bool get_service_secret(CephContext *cct, uint32_t service_id, +- ExpiringCryptoKey& secret, uint64_t& secret_id) const; + bool get_service_secret(CephContext *cct, uint32_t service_id, + CryptoKey& secret, uint64_t& secret_id) const; + bool get_service_secret(CephContext *cct, uint32_t service_id, +-- +2.23.0 + diff --git a/0026-CVE-2021-20288-2.patch b/0026-CVE-2021-20288-2.patch new file mode 100644 index 0000000..8dfa84a --- /dev/null +++ b/0026-CVE-2021-20288-2.patch @@ -0,0 +1,232 @@ +From d5328bc0c80868898fdf9a8c60ed6f47eb24f51f Mon Sep 17 00:00:00 2001 +From: Ilya Dryomov +Date: Thu, 15 Apr 2021 09:48:13 +0200 +Subject: [PATCH 2/3] auth/cephx: cap ticket validity by expiration of "next" + key + +If auth_mon_ticket_ttl is increased by several times as done in +commit 522a52e6c258 ("auth/cephx: rotate auth tickets less often"), +active clients eventually get stuck because the monitor sends out an +auth ticket with a bogus validity. The ticket is secured with the +"current" secret that is scheduled to expire according to the old TTL, +but the validity of the ticket is set to the new TTL. As a result, +the client simply doesn't attempt to renew, letting the secrets rotate +potentially more than once. When that happens, the client first hits +auth authorizer errors as it tries to renew service tickets and when +it finally gets to renewing the auth ticket, it hits the insecure +global_id reclaim wall. + +Cap TTL by expiration of "next" key -- the "current" key may be +milliseconds away from expiration and still be used, legitimately. +Do it in KeyServerData alongside key rotation code and propagate the +capped TTL to the upper layer. + +Signed-off-by: Ilya Dryomov +(cherry picked from commit 370c9b13970d47a55b1b20ef983c6f01236c9565) + +Conflicts: + src/auth/cephx/CephxKeyServer.cc [ commit ef3c42cd6481 ("auth: + EACCES, not EPERM") not in nautilus ] +--- + src/auth/cephx/CephxKeyServer.cc | 40 ++++++++++++++++++--------- + src/auth/cephx/CephxKeyServer.h | 10 ++++--- + src/auth/cephx/CephxServiceHandler.cc | 23 +++++++-------- + 3 files changed, 45 insertions(+), 28 deletions(-) + +diff --git a/src/auth/cephx/CephxKeyServer.cc b/src/auth/cephx/CephxKeyServer.cc +index dccee44d9a7..700e4abf78b 100644 +--- a/src/auth/cephx/CephxKeyServer.cc ++++ b/src/auth/cephx/CephxKeyServer.cc +@@ -22,7 +22,8 @@ + #define dout_prefix *_dout << "cephx keyserverdata: " + + bool KeyServerData::get_service_secret(CephContext *cct, uint32_t service_id, +- CryptoKey& secret, uint64_t& secret_id) const ++ CryptoKey& secret, uint64_t& secret_id, ++ double& ttl) const + { + map::const_iterator iter = + rotating_secrets.find(service_id); +@@ -39,15 +40,25 @@ bool KeyServerData::get_service_secret(CephContext *cct, uint32_t service_id, + if (secrets.secrets.size() > 1) + ++riter; + +- if (riter->second.expiration < ceph_clock_now()) ++ utime_t now = ceph_clock_now(); ++ if (riter->second.expiration < now) + ++riter; // "current" key has expired, use "next" key instead + + secret_id = riter->first; + secret = riter->second.key; + ++ // ttl may have just been increased by the user ++ // cap it by expiration of "next" key to prevent handing out a ticket ++ // with a bogus, possibly way into the future, validity ++ ttl = service_id == CEPH_ENTITY_TYPE_AUTH ? ++ cct->_conf->auth_mon_ticket_ttl : cct->_conf->auth_service_ticket_ttl; ++ ttl = min(ttl, static_cast( ++ secrets.secrets.rbegin()->second.expiration - now)); ++ + ldout(cct, 30) << __func__ << " service " + << ceph_entity_type_name(service_id) << " secret_id " +- << secret_id << " " << riter->second << dendl; ++ << secret_id << " " << riter->second << " ttl " << ttl ++ << dendl; + return true; + } + +@@ -223,12 +234,12 @@ bool KeyServer::get_caps(const EntityName& name, const string& type, + return data.get_caps(cct, name, type, caps_info); + } + +-bool KeyServer::get_service_secret(uint32_t service_id, +- CryptoKey& secret, uint64_t& secret_id) const ++bool KeyServer::get_service_secret(uint32_t service_id, CryptoKey& secret, ++ uint64_t& secret_id, double& ttl) const + { + std::scoped_lock l{lock}; + +- return data.get_service_secret(cct, service_id, secret, secret_id); ++ return data.get_service_secret(cct, service_id, secret, secret_id, ttl); + } + + bool KeyServer::get_service_secret(uint32_t service_id, +@@ -402,12 +413,13 @@ bool KeyServer::get_service_caps(const EntityName& name, uint32_t service_id, + + int KeyServer::_build_session_auth_info(uint32_t service_id, + const AuthTicket& parent_ticket, +- CephXSessionAuthInfo& info) ++ CephXSessionAuthInfo& info, ++ double ttl) + { + info.service_id = service_id; + info.ticket = parent_ticket; +- info.ticket.init_timestamps(ceph_clock_now(), +- cct->_conf->auth_service_ticket_ttl); ++ info.ticket.init_timestamps(ceph_clock_now(), ttl); ++ info.validity.set_from_double(ttl); + + generate_secret(info.session_key); + +@@ -425,13 +437,14 @@ int KeyServer::build_session_auth_info(uint32_t service_id, + const AuthTicket& parent_ticket, + CephXSessionAuthInfo& info) + { +- if (!get_service_secret(service_id, info.service_secret, info.secret_id)) { ++ double ttl; ++ if (!get_service_secret(service_id, info.service_secret, info.secret_id, ++ ttl)) { + return -EPERM; + } + + std::scoped_lock l{lock}; +- +- return _build_session_auth_info(service_id, parent_ticket, info); ++ return _build_session_auth_info(service_id, parent_ticket, info, ttl); + } + + int KeyServer::build_session_auth_info(uint32_t service_id, +@@ -444,6 +457,7 @@ int KeyServer::build_session_auth_info(uint32_t service_id, + info.secret_id = secret_id; + + std::scoped_lock l{lock}; +- return _build_session_auth_info(service_id, parent_ticket, info); ++ return _build_session_auth_info(service_id, parent_ticket, info, ++ cct->_conf->auth_service_ticket_ttl); + } + +diff --git a/src/auth/cephx/CephxKeyServer.h b/src/auth/cephx/CephxKeyServer.h +index 2a342e30302..390e2e4f170 100644 +--- a/src/auth/cephx/CephxKeyServer.h ++++ b/src/auth/cephx/CephxKeyServer.h +@@ -96,7 +96,8 @@ struct KeyServerData { + } + + bool get_service_secret(CephContext *cct, uint32_t service_id, +- CryptoKey& secret, uint64_t& secret_id) const; ++ CryptoKey& secret, uint64_t& secret_id, ++ double& ttl) const; + bool get_service_secret(CephContext *cct, uint32_t service_id, + uint64_t secret_id, CryptoKey& secret) const; + bool get_auth(const EntityName& name, EntityAuth& auth) const; +@@ -201,7 +202,8 @@ class KeyServer : public KeyStore { + void _dump_rotating_secrets(); + int _build_session_auth_info(uint32_t service_id, + const AuthTicket& parent_ticket, +- CephXSessionAuthInfo& info); ++ CephXSessionAuthInfo& info, ++ double ttl); + bool _get_service_caps(const EntityName& name, uint32_t service_id, + AuthCapsInfo& caps) const; + public: +@@ -225,8 +227,8 @@ public: + uint64_t secret_id); + + /* get current secret for specific service type */ +- bool get_service_secret(uint32_t service_id, CryptoKey& service_key, +- uint64_t& secret_id) const; ++ bool get_service_secret(uint32_t service_id, CryptoKey& secret, ++ uint64_t& secret_id, double& ttl) const; + bool get_service_secret(uint32_t service_id, uint64_t secret_id, + CryptoKey& secret) const override; + +diff --git a/src/auth/cephx/CephxServiceHandler.cc b/src/auth/cephx/CephxServiceHandler.cc +index 82c964e47fa..886014e8bb9 100644 +--- a/src/auth/cephx/CephxServiceHandler.cc ++++ b/src/auth/cephx/CephxServiceHandler.cc +@@ -210,11 +210,20 @@ int CephxServiceHandler::handle_request( + break; + } + +- info.ticket.init_timestamps(ceph_clock_now(), +- cct->_conf->auth_mon_ticket_ttl); ++ double ttl; ++ if (!key_server->get_service_secret(CEPH_ENTITY_TYPE_AUTH, ++ info.service_secret, info.secret_id, ++ ttl)) { ++ ldout(cct, 0) << " could not get service secret for auth subsystem" << dendl; ++ ret = -EIO; ++ break; ++ } ++ ++ info.service_id = CEPH_ENTITY_TYPE_AUTH; + info.ticket.name = entity_name; + info.ticket.global_id = global_id; +- info.validity += cct->_conf->auth_mon_ticket_ttl; ++ info.ticket.init_timestamps(ceph_clock_now(), ttl); ++ info.validity.set_from_double(ttl); + + key_server->generate_secret(session_key); + +@@ -222,12 +231,6 @@ int CephxServiceHandler::handle_request( + if (psession_key) { + *psession_key = session_key; + } +- info.service_id = CEPH_ENTITY_TYPE_AUTH; +- if (!key_server->get_service_secret(CEPH_ENTITY_TYPE_AUTH, info.service_secret, info.secret_id)) { +- ldout(cct, 0) << " could not get service secret for auth subsystem" << dendl; +- ret = -EIO; +- break; +- } + + vector info_vec; + info_vec.push_back(info); +@@ -288,7 +291,6 @@ int CephxServiceHandler::handle_request( + service_id, + info.ticket, + svc_info); +- svc_info.validity += cct->_conf->auth_service_ticket_ttl; + info_vec.push_back(svc_info); + } + } +@@ -358,7 +360,6 @@ int CephxServiceHandler::handle_request( + service_err = r; + continue; + } +- info.validity += cct->_conf->auth_service_ticket_ttl; + info_vec.push_back(info); + ++found_services; + } +-- +2.23.0 + diff --git a/0027-CVE-2021-20288-3.patch b/0027-CVE-2021-20288-3.patch new file mode 100644 index 0000000..3e961c2 --- /dev/null +++ b/0027-CVE-2021-20288-3.patch @@ -0,0 +1,73 @@ +From 4a484defa41990fd66da31a0d82368eaa41ecbb5 Mon Sep 17 00:00:00 2001 +From: Ilya Dryomov +Date: Thu, 15 Apr 2021 15:18:58 +0200 +Subject: [PATCH 3/3] auth/cephx: make KeyServer::build_session_auth_info() + less confusing + +The second KeyServer::build_session_auth_info() overload is used only +by the monitor, for mon <-> mon authentication. The monitor passes in +service_secret (mon secret) and secret_id (-1). The TTL is irrelevant +because there is no rotation. + +However the signature doesn't make it obvious. Clarify that +service_secret and secret_id are input parameters and info is the only +output parameter. + +Signed-off-by: Ilya Dryomov +(cherry picked from commit 6f12cd3688b753633c8ff29fb3bd64758f960b2b) +--- + src/auth/cephx/CephxKeyServer.cc | 6 +++--- + src/auth/cephx/CephxKeyServer.h | 6 +++--- + src/mon/Monitor.cc | 2 +- + 3 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/src/auth/cephx/CephxKeyServer.cc b/src/auth/cephx/CephxKeyServer.cc +index 700e4abf78b..0fcf4536202 100644 +--- a/src/auth/cephx/CephxKeyServer.cc ++++ b/src/auth/cephx/CephxKeyServer.cc +@@ -449,9 +449,9 @@ int KeyServer::build_session_auth_info(uint32_t service_id, + + int KeyServer::build_session_auth_info(uint32_t service_id, + const AuthTicket& parent_ticket, +- CephXSessionAuthInfo& info, +- CryptoKey& service_secret, +- uint64_t secret_id) ++ const CryptoKey& service_secret, ++ uint64_t secret_id, ++ CephXSessionAuthInfo& info) + { + info.service_secret = service_secret; + info.secret_id = secret_id; +diff --git a/src/auth/cephx/CephxKeyServer.h b/src/auth/cephx/CephxKeyServer.h +index 390e2e4f170..2662c64c0f1 100644 +--- a/src/auth/cephx/CephxKeyServer.h ++++ b/src/auth/cephx/CephxKeyServer.h +@@ -222,9 +222,9 @@ public: + CephXSessionAuthInfo& info); + int build_session_auth_info(uint32_t service_id, + const AuthTicket& parent_ticket, +- CephXSessionAuthInfo& info, +- CryptoKey& service_secret, +- uint64_t secret_id); ++ const CryptoKey& service_secret, ++ uint64_t secret_id, ++ CephXSessionAuthInfo& info); + + /* get current secret for specific service type */ + bool get_service_secret(uint32_t service_id, CryptoKey& secret, +diff --git a/src/mon/Monitor.cc b/src/mon/Monitor.cc +index d7665a15d75..edf3b78933d 100644 +--- a/src/mon/Monitor.cc ++++ b/src/mon/Monitor.cc +@@ -6203,7 +6203,7 @@ bool Monitor::ms_get_authorizer(int service_id, AuthAuthorizer **authorizer) + } + + ret = key_server.build_session_auth_info( +- service_id, auth_ticket_info.ticket, info, secret, (uint64_t)-1); ++ service_id, auth_ticket_info.ticket, secret, (uint64_t)-1, info); + if (ret < 0) { + dout(0) << __func__ << " failed to build mon session_auth_info " + << cpp_strerror(ret) << dendl; +-- +2.23.0 + diff --git a/ceph.spec b/ceph.spec index 78203f5..b9b1aa6 100644 --- a/ceph.spec +++ b/ceph.spec @@ -68,7 +68,7 @@ ################################################################################# Name: ceph Version: 12.2.8 -Release: 20 +Release: 21 Epoch: 2 # define _epoch_prefix macro which will expand to the empty string if epoch is @@ -108,6 +108,9 @@ Patch21: 0021-common-mempool-Add-test-for-mempool-shards.patch Patch22: 0022-common-mempool-Modify-shard-selection-function.patch Patch23: 0023-common-mempool-only-fail-tests-if-sharding-is-very-b.patch Patch24: 0024-CVE-2021-3979.patch +Patch25: 0025-CVE-2021-20288-1.patch +Patch26: 0026-CVE-2021-20288-2.patch +Patch27: 0027-CVE-2021-20288-3.patch Requires: glibc >= 2.28-66 @@ -1856,6 +1859,9 @@ exit 0 %changelog +* Sat Mar 5 2022 chixizne - 1:12.2.8-21 +- fix CVE-2021-20288.patch + * Sun Jan 29 2022 luo rixin - 1:12.2.8-20 - fix CVE-2021-3979 -- Gitee