From 0fc4428ebb8b152384ffed450046411ab31fbb6e Mon Sep 17 00:00:00 2001 From: markeryang Date: Wed, 30 Dec 2020 14:08:48 +0800 Subject: [PATCH 01/12] fix CVE-2020-12059 --- ...8-16889.patch => 0001-CVE-2018-16889.patch | 0 ...846-1.patch => 0002-CVE-2018-16846-1.patch | 0 ...846-2.patch => 0003-CVE-2018-16846-2.patch | 0 ...8-14662.patch => 0004-CVE-2018-14662.patch | 0 0005-CVE-2020-12059.patch | 30 +++++++++++++++++++ ceph.spec | 14 +++++---- 6 files changed, 39 insertions(+), 5 deletions(-) rename 6000-CVE-2018-16889.patch => 0001-CVE-2018-16889.patch (100%) rename 6001-CVE-2018-16846-1.patch => 0002-CVE-2018-16846-1.patch (100%) rename 6002-CVE-2018-16846-2.patch => 0003-CVE-2018-16846-2.patch (100%) rename 6003-CVE-2018-14662.patch => 0004-CVE-2018-14662.patch (100%) create mode 100644 0005-CVE-2020-12059.patch diff --git a/6000-CVE-2018-16889.patch b/0001-CVE-2018-16889.patch similarity index 100% rename from 6000-CVE-2018-16889.patch rename to 0001-CVE-2018-16889.patch diff --git a/6001-CVE-2018-16846-1.patch b/0002-CVE-2018-16846-1.patch similarity index 100% rename from 6001-CVE-2018-16846-1.patch rename to 0002-CVE-2018-16846-1.patch diff --git a/6002-CVE-2018-16846-2.patch b/0003-CVE-2018-16846-2.patch similarity index 100% rename from 6002-CVE-2018-16846-2.patch rename to 0003-CVE-2018-16846-2.patch diff --git a/6003-CVE-2018-14662.patch b/0004-CVE-2018-14662.patch similarity index 100% rename from 6003-CVE-2018-14662.patch rename to 0004-CVE-2018-14662.patch diff --git a/0005-CVE-2020-12059.patch b/0005-CVE-2020-12059.patch new file mode 100644 index 0000000..4096aa4 --- /dev/null +++ b/0005-CVE-2020-12059.patch @@ -0,0 +1,30 @@ +From 375d926a4f2720a29b079c216bafb884eef985c3 Mon Sep 17 00:00:00 2001 +From: Abhishek Lekshmanan +Date: Wed, 22 Apr 2020 11:24:34 +0200 +Subject: [PATCH] rgw: check for tagging element in POST Obj requests + +Check for null element when reading the tagging field from POST obj XML + +Fixes: https://tracker.ceph.com/issues/44967 +Signed-off-by: Abhishek Lekshmanan +--- + src/rgw/rgw_rest_s3.cc | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc +index bfda4232..ac2a0272 100644 +--- a/src/rgw/rgw_rest_s3.cc ++++ b/src/rgw/rgw_rest_s3.cc +@@ -420,6 +420,9 @@ int RGWPutObjTags_ObjStore_S3::get_params() + RGWObjTagging_S3 *tagging; + + tagging = static_cast(parser.find_first("Tagging")); ++ if (!tagging) { ++ return -ERR_MALFORMED_XML; ++ } + obj_tags_s3 = static_cast(tagging->find_first("TagSet")); + if(!obj_tags_s3){ + return -ERR_MALFORMED_XML; +-- +2.27.0 + diff --git a/ceph.spec b/ceph.spec index dddcffc..d5d2a9e 100644 --- a/ceph.spec +++ b/ceph.spec @@ -68,7 +68,7 @@ ################################################################################# Name: ceph Version: 12.2.8 -Release: 8 +Release: 9 Epoch: 2 # define _epoch_prefix macro which will expand to the empty string if epoch is @@ -84,10 +84,11 @@ URL: http://ceph.com/ Source0: http://ceph.com/download/ceph-12.2.8.tar.gz # backport for cves -Patch6000: 6000-CVE-2018-16889.patch -Patch6001: 6001-CVE-2018-16846-1.patch -Patch6002: 6002-CVE-2018-16846-2.patch -Patch6003: 6003-CVE-2018-14662.patch +Patch1: 0001-CVE-2018-16889.patch +Patch2: 0002-CVE-2018-16846-1.patch +Patch3: 0003-CVE-2018-16846-2.patch +Patch4: 0004-CVE-2018-14662.patch +Patch5: 0005-CVE-2020-12059.patch %if 0%{?suse_version} %if 0%{?is_opensuse} @@ -1796,6 +1797,9 @@ exit 0 %changelog +* Wed Dec 30 2020 yanglongkang - 1:12.2.8-9 +- fix CVE-2020-12059 + * Fri Sep 25 2020 wuguanghao - 1:12.2.8-8 - remove the python-virtualenv package from BuildRequires to solve the compilation problem -- Gitee From 10e119f42dc93bf4e729dd069dcdeee3b6911bbf Mon Sep 17 00:00:00 2001 From: Zhiqiang Liu Date: Wed, 27 Jan 2021 17:41:04 +0800 Subject: [PATCH 02/12] ceph: fix python-prettytable require version problem ceph-common only supports python2, and it requires python-prettytable without using python<2|3>-prettytable. However, if we try to install python-prettytable, python3-prettytable will be finally installed. Here, we correct python-prettytable requires with python2-prettytable. Signed-off-by: Zhiqiang Liu --- ceph.spec | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ceph.spec b/ceph.spec index d5d2a9e..9434064 100644 --- a/ceph.spec +++ b/ceph.spec @@ -68,7 +68,7 @@ ################################################################################# Name: ceph Version: 12.2.8 -Release: 9 +Release: 10 Epoch: 2 # define _epoch_prefix macro which will expand to the empty string if epoch is @@ -286,10 +286,10 @@ Requires: python-rbd = %{_epoch_prefix}%{version}-%{release} Requires: python-cephfs = %{_epoch_prefix}%{version}-%{release} Requires: python-rgw = %{_epoch_prefix}%{version}-%{release} %if 0%{?fedora} || 0%{?rhel} || 0%{?openEuler} -Requires: python-prettytable +Requires: python2-prettytable %endif %if 0%{?suse_version} -Requires: python-PrettyTable +Requires: python2-PrettyTable %endif Requires: python-requests %{?systemd_requires} @@ -1797,6 +1797,9 @@ exit 0 %changelog +* Wed Jan 27 2021 Zhiqiang Liu - 1:12.2.8-10 +- correct ceph-common requires python2-prettytable version. + * Wed Dec 30 2020 yanglongkang - 1:12.2.8-9 - fix CVE-2020-12059 -- Gitee From e8ae2e052e9bae90eb910bce8f7bb939512ee7b9 Mon Sep 17 00:00:00 2001 From: Zhuohui Zou Date: Tue, 9 Mar 2021 15:05:04 +0800 Subject: [PATCH 03/12] fix CVE-2020-25678 Signed-off-by: Zhuohui Zou (cherry picked from commit f923d4556ff61072cabfc3f385c73738abe14731) --- 0006-CVE-2020-25678-1.patch | 109 ++++++++++++++++++++++++++++++++++++ 0007-CVE-2020-25678-2.patch | 76 +++++++++++++++++++++++++ ceph.spec | 10 +++- 3 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 0006-CVE-2020-25678-1.patch create mode 100644 0007-CVE-2020-25678-2.patch diff --git a/0006-CVE-2020-25678-1.patch b/0006-CVE-2020-25678-1.patch new file mode 100644 index 0000000..39d226f --- /dev/null +++ b/0006-CVE-2020-25678-1.patch @@ -0,0 +1,109 @@ +From b23bc377f4781789766f94a830e345daed08f504 Mon Sep 17 00:00:00 2001 +From: Neha Ojha +Date: Thu, 3 Dec 2020 19:18:04 +0000 +Subject: [PATCH 1/2] messages/MMonCommand, MMonCommandAck: don't log values + for "config set" and "config-key set" + +This acts like a big hammer to avoid adding sensitive information, like passwords +into mon/mgr/cluster logs when using "config set" and "config-key set" to set keys +whose values should be secure. + +Fixes: https://tracker.ceph.com/issues/37503 +Signed-off-by: Neha Ojha +(cherry picked from commit 3d54660ca1a9a7ae54e884c3181fca17a40d8cd3) + + Conflicts: + src/messages/MMonCommand.h - trivial resolution + src/messages/MMonCommandAck.h - trivial resolution +--- + src/messages/MMonCommand.h | 23 ++++++++++++++++++++--- + src/messages/MMonCommandAck.h | 24 +++++++++++++++++++++++- + 2 files changed, 43 insertions(+), 4 deletions(-) + +diff --git a/src/messages/MMonCommand.h b/src/messages/MMonCommand.h +index c6764475dc..e0ef5a7355 100644 +--- a/src/messages/MMonCommand.h ++++ b/src/messages/MMonCommand.h +@@ -15,6 +15,7 @@ + #ifndef CEPH_MMONCOMMAND_H + #define CEPH_MMONCOMMAND_H + ++#include "common/cmdparse.h" + #include "messages/PaxosServiceMessage.h" + + #include +@@ -37,10 +38,26 @@ private: + public: + const char *get_type_name() const override { return "mon_command"; } + void print(ostream& o) const override { ++ cmdmap_t cmdmap; ++ stringstream ss; ++ string prefix; ++ cmdmap_from_json(cmd, &cmdmap, ss); ++ cmd_getval(g_ceph_context, cmdmap, "prefix", prefix); ++ // Some config values contain sensitive data, so don't log them + o << "mon_command("; +- for (unsigned i=0; i +Date: Thu, 3 Dec 2020 19:24:39 +0000 +Subject: [PATCH 2/2] mon: don't log "config set" and "config-key set" dispatch + and finished messages + +Signed-off-by: Neha Ojha +(cherry picked from commit 4b83dfb1f74e8a59c802ff3c0eb4595f7e763762) +--- + src/mon/Monitor.cc | 18 ++++++++++-------- + src/mon/Monitor.h | 9 ++++++++- + 2 files changed, 18 insertions(+), 9 deletions(-) + +diff --git a/src/mon/Monitor.cc b/src/mon/Monitor.cc +index da1fac90ed..f6c9a1bd8b 100644 +--- a/src/mon/Monitor.cc ++++ b/src/mon/Monitor.cc +@@ -3170,18 +3170,20 @@ void Monitor::handle_command(MonOpRequestRef op) + if (!_allowed_command(session, service, prefix, cmdmap, + param_str_map, mon_cmd)) { + dout(1) << __func__ << " access denied" << dendl; +- (cmd_is_rw ? audit_clog->info() : audit_clog->debug()) +- << "from='" << session->inst << "' " +- << "entity='" << session->entity_name << "' " +- << "cmd=" << m->cmd << ": access denied"; ++ if (prefix != "config set" && prefix != "config-key set") ++ (cmd_is_rw ? audit_clog->info() : audit_clog->debug()) ++ << "from='" << session->inst << "' " ++ << "entity='" << session->entity_name << "' " ++ << "cmd=" << m->cmd << ": access denied"; + reply_command(op, -EACCES, "access denied", 0); + return; + } + +- (cmd_is_rw ? audit_clog->info() : audit_clog->debug()) +- << "from='" << session->inst << "' " +- << "entity='" << session->entity_name << "' " +- << "cmd=" << m->cmd << ": dispatch"; ++ if (prefix != "config set" && prefix != "config-key set") ++ (cmd_is_rw ? audit_clog->info() : audit_clog->debug()) ++ << "from='" << session->inst << "' " ++ << "entity='" << session->entity_name << "' " ++ << "cmd=" << m->cmd << ": dispatch"; + + if (mon_cmd->is_mgr() && + osdmon()->osdmap.require_osd_release >= CEPH_RELEASE_LUMINOUS) { +diff --git a/src/mon/Monitor.h b/src/mon/Monitor.h +index 008947e85b..e8f712e984 100644 +--- a/src/mon/Monitor.h ++++ b/src/mon/Monitor.h +@@ -40,6 +40,7 @@ + #include "PGStatService.h" + #include "MonCommand.h" + ++#include "common/cmdparse.h" + #include "common/LogClient.h" + #include "auth/cephx/CephxKeyServer.h" + #include "auth/AuthMethodList.h" +@@ -860,7 +861,13 @@ public: + ss << "session dropped for command "; + } + } +- ss << "cmd='" << m->cmd << "': finished"; ++ cmdmap_t cmdmap; ++ stringstream ds; ++ string prefix; ++ cmdmap_from_json(m->cmd, &cmdmap, ds); ++ cmd_getval(g_ceph_context, cmdmap, "prefix", prefix); ++ if (prefix != "config set" && prefix != "config-key set") ++ ss << "cmd='" << m->cmd << "': finished"; + + mon->audit_clog->info() << ss.str(); + mon->reply_command(op, rc, rs, rdata, version); +-- +2.29.2 + diff --git a/ceph.spec b/ceph.spec index 9434064..a35ca3f 100644 --- a/ceph.spec +++ b/ceph.spec @@ -68,7 +68,7 @@ ################################################################################# Name: ceph Version: 12.2.8 -Release: 10 +Release: 12 Epoch: 2 # define _epoch_prefix macro which will expand to the empty string if epoch is @@ -89,6 +89,8 @@ Patch2: 0002-CVE-2018-16846-1.patch Patch3: 0003-CVE-2018-16846-2.patch Patch4: 0004-CVE-2018-14662.patch Patch5: 0005-CVE-2020-12059.patch +Patch6: 0006-CVE-2020-25678-1.patch +Patch7: 0007-CVE-2020-25678-2.patch %if 0%{?suse_version} %if 0%{?is_opensuse} @@ -1797,6 +1799,12 @@ exit 0 %changelog +* Wed Mar 10 2021 Zhuohui Zou - 1:12.2.8-12 +- fix CVE-2020-25678 + +* Thu Mar 4 2021 Shaoning Zhang - 1:12.2.8-11 +- correct ceph-mgr requires python2-jinja2 and python2-werkzeug + * Wed Jan 27 2021 Zhiqiang Liu - 1:12.2.8-10 - correct ceph-common requires python2-prettytable version. -- Gitee From 6352b0c062b3c49b53d66e438e0ada76478f516e Mon Sep 17 00:00:00 2001 From: chixinze Date: Sun, 18 Jul 2021 17:25:28 +0800 Subject: [PATCH 04/12] fix CVE-2020-27781 Signed-off-by: chixinze --- ...nt-allow-atomic-updates-for-RADOS-ob.patch | 154 ++++++++++ ...-add-a-test-for-put_object_versioned.patch | 49 ++++ ...test_volume_client.py-py3-compatible.patch | 160 ++++++++++ 0011-CVE-2020-27781-1.patch | 48 +++ 0012-CVE-2020-27781-2.patch | 172 +++++++++++ 0013-CVE-2020-27781-3.patch | 113 +++++++ 0014-CVE-2020-27781-4.patch | 52 ++++ 0015-CVE-2020-27781-5.patch | 275 ++++++++++++++++++ ceph.spec | 15 +- 9 files changed, 1037 insertions(+), 1 deletion(-) create mode 100644 0008-ceph-volume-client-allow-atomic-updates-for-RADOS-ob.patch create mode 100644 0009-qa-ceph-volume-add-a-test-for-put_object_versioned.patch create mode 100644 0010-qa-make-test_volume_client.py-py3-compatible.patch create mode 100644 0011-CVE-2020-27781-1.patch create mode 100644 0012-CVE-2020-27781-2.patch create mode 100644 0013-CVE-2020-27781-3.patch create mode 100644 0014-CVE-2020-27781-4.patch create mode 100644 0015-CVE-2020-27781-5.patch diff --git a/0008-ceph-volume-client-allow-atomic-updates-for-RADOS-ob.patch b/0008-ceph-volume-client-allow-atomic-updates-for-RADOS-ob.patch new file mode 100644 index 0000000..49cfdf6 --- /dev/null +++ b/0008-ceph-volume-client-allow-atomic-updates-for-RADOS-ob.patch @@ -0,0 +1,154 @@ +From c3f9c972297c4d73a901453e806c16044e570667 Mon Sep 17 00:00:00 2001 +From: Rishabh Dave +Date: Thu, 7 Jun 2018 12:26:44 +0000 +Subject: [PATCH 1/2] ceph-volume-client: allow atomic updates for RADOS + objects + +put_object_versioned() takes the version of the object and verifies if +the version of the object is the expected one before updating the data +in the object. This verification of version before actually writing +makes put_objcet_version() atomic. + +Rest of the changes include adding get_object_and_version() so that +current version of the object can be obtained and modification of +get_object() and put_object() to use get_object_and_version() and +put_object_versioned() respectively. + +Fixes: http://tracker.ceph.com/issues/24173 +Signed-off-by: Rishabh Dave +(cherry picked from commit ca7253cff6cdac590bb14d0d297c02452bf75bf6) +--- + src/pybind/ceph_volume_client.py | 46 +++++++++++++++++++++++++++++--- + src/pybind/rados/rados.pyx | 14 ++++++++++ + 2 files changed, 57 insertions(+), 3 deletions(-) + +diff --git a/src/pybind/ceph_volume_client.py b/src/pybind/ceph_volume_client.py +index d38f72be9a3..c43681bef21 100644 +--- a/src/pybind/ceph_volume_client.py ++++ b/src/pybind/ceph_volume_client.py +@@ -205,6 +205,7 @@ CEPHFSVOLUMECLIENT_VERSION_HISTORY = """ + * 1 - Initial version + * 2 - Added get_object, put_object, delete_object methods to CephFSVolumeClient + * 3 - Allow volumes to be created without RADOS namespace isolation ++ * 4 - Added get_object_and_version, put_object_versioned method to CephFSVolumeClient + """ + + +@@ -228,7 +229,7 @@ class CephFSVolumeClient(object): + """ + + # Current version +- version = 3 ++ version = 4 + + # Where shall we create our volumes? + POOL_PREFIX = "fsvolume_" +@@ -1403,15 +1404,40 @@ class CephFSVolumeClient(object): + :param data: data to write + :type data: bytes + """ ++ return self.put_object_versioned(pool_name, object_name, data) ++ ++ def put_object_versioned(self, pool_name, object_name, data, version=None): ++ """ ++ Synchronously write data to an object only if version of the object ++ version matches the expected version. ++ ++ :param pool_name: name of the pool ++ :type pool_name: str ++ :param object_name: name of the object ++ :type object_name: str ++ :param data: data to write ++ :type data: bytes ++ :param version: expected version of the object to write ++ :type version: int ++ """ + ioctx = self.rados.open_ioctx(pool_name) ++ + max_size = int(self.rados.conf_get('osd_max_write_size')) * 1024 * 1024 + if len(data) > max_size: + msg = ("Data to be written to object '{0}' exceeds " + "{1} bytes".format(object_name, max_size)) + log.error(msg) + raise CephFSVolumeClientError(msg) ++ + try: +- ioctx.write_full(object_name, data) ++ with rados.WriteOpCtx(ioctx) as wop: ++ if version is not None: ++ wop.assert_version(version) ++ wop.write_full(data) ++ ioctx.operate_write_op(wop, object_name) ++ except rados.OSError as e: ++ log.error(e) ++ raise e + finally: + ioctx.close() + +@@ -1426,6 +1452,19 @@ class CephFSVolumeClient(object): + + :returns: bytes - data read from object + """ ++ return self.get_object_and_version(pool_name, object_name)[0] ++ ++ def get_object_and_version(self, pool_name, object_name): ++ """ ++ Synchronously read data from object and get its version. ++ ++ :param pool_name: name of the pool ++ :type pool_name: str ++ :param object_name: name of the object ++ :type object_name: str ++ ++ :returns: tuple of object data and version ++ """ + ioctx = self.rados.open_ioctx(pool_name) + max_size = int(self.rados.conf_get('osd_max_write_size')) * 1024 * 1024 + try: +@@ -1434,9 +1473,10 @@ class CephFSVolumeClient(object): + (ioctx.read(object_name, 1, offset=max_size))): + log.warning("Size of object {0} exceeds '{1}' bytes " + "read".format(object_name, max_size)) ++ obj_version = ioctx.get_last_version() + finally: + ioctx.close() +- return bytes_read ++ return (bytes_read, obj_version) + + def delete_object(self, pool_name, object_name): + ioctx = self.rados.open_ioctx(pool_name) +diff --git a/src/pybind/rados/rados.pyx b/src/pybind/rados/rados.pyx +index e9829937a11..c0df28645b8 100644 +--- a/src/pybind/rados/rados.pyx ++++ b/src/pybind/rados/rados.pyx +@@ -284,6 +284,7 @@ cdef extern from "rados/librados.h" nogil: + void rados_write_op_create(rados_write_op_t write_op, int exclusive, const char *category) + void rados_write_op_append(rados_write_op_t write_op, const char *buffer, size_t len) + void rados_write_op_write_full(rados_write_op_t write_op, const char *buffer, size_t len) ++ void rados_write_op_assert_version(rados_write_op_t write_op, uint64_t ver) + void rados_write_op_write(rados_write_op_t write_op, const char *buffer, size_t len, uint64_t offset) + void rados_write_op_remove(rados_write_op_t write_op) + void rados_write_op_truncate(rados_write_op_t write_op, uint64_t offset) +@@ -1941,6 +1942,19 @@ cdef class WriteOp(object): + with nogil: + rados_write_op_write(self.write_op, _to_write, length, _offset) + ++ @requires(('version', int)) ++ def assert_version(self, version): ++ """ ++ Check if object's version is the expected one. ++ :param version: expected version of the object ++ :param type: int ++ """ ++ cdef: ++ uint64_t _version = version ++ ++ with nogil: ++ rados_write_op_assert_version(self.write_op, _version) ++ + @requires(('offset', int), ('length', int)) + def zero(self, offset, length): + """ +-- +2.23.0 + diff --git a/0009-qa-ceph-volume-add-a-test-for-put_object_versioned.patch b/0009-qa-ceph-volume-add-a-test-for-put_object_versioned.patch new file mode 100644 index 0000000..08bac94 --- /dev/null +++ b/0009-qa-ceph-volume-add-a-test-for-put_object_versioned.patch @@ -0,0 +1,49 @@ +From ee6625c29179dd5aa34b2da4d9af75e87f13316e Mon Sep 17 00:00:00 2001 +From: Rishabh Dave +Date: Thu, 7 Jun 2018 12:29:36 +0000 +Subject: [PATCH 2/2] qa/ceph-volume: add a test for put_object_versioned() + +Test if the version passed to put_object_versioned() is used to +crosscheck. + +Signed-off-by: Rishabh Dave +(cherry picked from commit 8ab6f84d5799cf2f32fb2b08168ff1cfb82f7d15) +--- + qa/tasks/cephfs/test_volume_client.py | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/qa/tasks/cephfs/test_volume_client.py b/qa/tasks/cephfs/test_volume_client.py +index 9be7fc2fff5..cf135bce122 100644 +--- a/qa/tasks/cephfs/test_volume_client.py ++++ b/qa/tasks/cephfs/test_volume_client.py +@@ -970,6 +970,27 @@ vc.disconnect() + obj_data = obj_data + ))) + ++ def test_put_object_versioned(self): ++ vc_mount = self.mounts[1] ++ vc_mount.umount_wait() ++ self._configure_vc_auth(vc_mount, "manila") ++ ++ obj_data = 'test_data' ++ obj_name = 'test_vc_ob_2' ++ pool_name = self.fs.get_data_pool_names()[0] ++ self.fs.rados(['put', obj_name, '-'], pool=pool_name, stdin_data=obj_data) ++ ++ # Test if put_object_versioned() crosschecks the version of the ++ # given object. Being a negative test, an exception is expected. ++ with self.assertRaises(CommandFailedError): ++ self._volume_client_python(vc_mount, dedent(""" ++ data, version = vc.get_object_and_version("{pool_name}", "{obj_name}") ++ data += 'm1' ++ vc.put_object("{pool_name}", "{obj_name}", data) ++ data += 'm2' ++ vc.put_object_versioned("{pool_name}", "{obj_name}", data, version) ++ """).format(pool_name=pool_name, obj_name=obj_name)) ++ + def test_delete_object(self): + vc_mount = self.mounts[1] + vc_mount.umount_wait() +-- +2.23.0 + diff --git a/0010-qa-make-test_volume_client.py-py3-compatible.patch b/0010-qa-make-test_volume_client.py-py3-compatible.patch new file mode 100644 index 0000000..90788d3 --- /dev/null +++ b/0010-qa-make-test_volume_client.py-py3-compatible.patch @@ -0,0 +1,160 @@ +From 7012f930e09275889857b9c800d087fb0c3e34a8 Mon Sep 17 00:00:00 2001 +From: Rishabh Dave +Date: Tue, 15 May 2018 06:06:39 +0000 +Subject: [PATCH] qa: make test_volume_client.py py3 compatible + +Signed-off-by: Rishabh Dave +(cherry picked from commit f28274dc70aa102e3c4523059a65e5da8c8a0426) +--- + qa/tasks/cephfs/test_volume_client.py | 35 +++++++++++++++------------ + 1 file changed, 20 insertions(+), 15 deletions(-) + +diff --git a/qa/tasks/cephfs/test_volume_client.py b/qa/tasks/cephfs/test_volume_client.py +index 2e0bf6751e3..d94e2fa7b92 100644 +--- a/qa/tasks/cephfs/test_volume_client.py ++++ b/qa/tasks/cephfs/test_volume_client.py +@@ -24,6 +24,7 @@ class TestVolumeClient(CephFSTestCase): + if ns_prefix: + ns_prefix = "\"" + ns_prefix + "\"" + return client.run_python(""" ++from __future__ import print_function + from ceph_volume_client import CephFSVolumeClient, VolumePath + import logging + log = logging.getLogger("ceph_volume_client") +@@ -101,7 +102,7 @@ vc.disconnect() + vp = VolumePath("{group_id}", "{volume_id}") + auth_result = vc.authorize(vp, "{guest_entity}", readonly={readonly}, + tenant_id="{tenant_id}") +- print auth_result['auth_key'] ++ print(auth_result['auth_key']) + """.format( + group_id=group_id, + volume_id=volume_id, +@@ -198,7 +199,7 @@ vc.disconnect() + mount_path = self._volume_client_python(self.mount_b, dedent(""" + vp = VolumePath("{group_id}", "{volume_id}") + create_result = vc.create_volume(vp, 1024*1024*{volume_size}) +- print create_result['mount_path'] ++ print(create_result['mount_path']) + """.format( + group_id=group_id, + volume_id=volume_id, +@@ -479,7 +480,7 @@ vc.disconnect() + self._volume_client_python(volumeclient_mount, dedent(""" + vp = VolumePath("{group_id}", "{volume_id}") + create_result = vc.create_volume(vp, 10 * 1024 * 1024) +- print create_result['mount_path'] ++ print(create_result['mount_path']) + """.format( + group_id=group_id, + volume_id=volume_ids[i] +@@ -562,7 +563,7 @@ vc.disconnect() + mount_path = self._volume_client_python(self.mount_b, dedent(""" + vp = VolumePath("{group_id}", u"{volume_id}") + create_result = vc.create_volume(vp, 10) +- print create_result['mount_path'] ++ print(create_result['mount_path']) + """.format( + group_id=group_id, + volume_id=volume_id +@@ -612,7 +613,7 @@ vc.disconnect() + mount_path = self._volume_client_python(volumeclient_mount, dedent(""" + vp = VolumePath("{group_id}", "{volume_id}") + create_result = vc.create_volume(vp, 1024*1024*10) +- print create_result['mount_path'] ++ print(create_result['mount_path']) + """.format( + group_id=group_id, + volume_id=volume_id, +@@ -667,14 +668,14 @@ vc.disconnect() + guest_entity_1 = "guest1" + guest_entity_2 = "guest2" + +- log.info("print group ID: {0}".format(group_id)) ++ log.info("print(group ID: {0})".format(group_id)) + + # Create a volume. + auths = self._volume_client_python(volumeclient_mount, dedent(""" + vp = VolumePath("{group_id}", "{volume_id}") + vc.create_volume(vp, 1024*1024*10) + auths = vc.get_authorized_ids(vp) +- print auths ++ print(auths) + """.format( + group_id=group_id, + volume_id=volume_id, +@@ -689,7 +690,7 @@ vc.disconnect() + vc.authorize(vp, "{guest_entity_1}", readonly=False) + vc.authorize(vp, "{guest_entity_2}", readonly=True) + auths = vc.get_authorized_ids(vp) +- print auths ++ print(auths) + """.format( + group_id=group_id, + volume_id=volume_id, +@@ -697,7 +698,11 @@ vc.disconnect() + guest_entity_2=guest_entity_2, + ))) + # Check the list of authorized IDs and their access levels. +- expected_result = [(u'guest1', u'rw'), (u'guest2', u'r')] ++ if self.py_version == 'python3': ++ expected_result = [('guest1', 'rw'), ('guest2', 'r')] ++ else: ++ expected_result = [(u'guest1', u'rw'), (u'guest2', u'r')] ++ + self.assertItemsEqual(str(expected_result), auths) + + # Disallow both the auth IDs' access to the volume. +@@ -706,7 +711,7 @@ vc.disconnect() + vc.deauthorize(vp, "{guest_entity_1}") + vc.deauthorize(vp, "{guest_entity_2}") + auths = vc.get_authorized_ids(vp) +- print auths ++ print(auths) + """.format( + group_id=group_id, + volume_id=volume_id, +@@ -783,11 +788,11 @@ vc.disconnect() + "version": 2, + "compat_version": 1, + "dirty": False, +- "tenant_id": u"tenant1", ++ "tenant_id": "tenant1", + "volumes": { + "groupid/volumeid": { + "dirty": False, +- "access_level": u"rw", ++ "access_level": "rw" + } + } + } +@@ -817,7 +822,7 @@ vc.disconnect() + "auths": { + "guest": { + "dirty": False, +- "access_level": u"rw" ++ "access_level": "rw" + } + } + } +@@ -1021,7 +1026,7 @@ vc.disconnect() + mount_path = self._volume_client_python(vc_mount, dedent(""" + vp = VolumePath("{group_id}", "{volume_id}") + create_result = vc.create_volume(vp, 1024*1024*10) +- print create_result['mount_path'] ++ print(create_result['mount_path']) + """.format( + group_id=group_id, + volume_id=volume_id +@@ -1060,7 +1065,7 @@ vc.disconnect() + mount_path = self._volume_client_python(vc_mount, dedent(""" + vp = VolumePath("{group_id}", "{volume_id}") + create_result = vc.create_volume(vp, 1024*1024*10, namespace_isolated=False) +- print create_result['mount_path'] ++ print(create_result['mount_path']) + """.format( + group_id=group_id, + volume_id=volume_id +-- +2.23.0 + diff --git a/0011-CVE-2020-27781-1.patch b/0011-CVE-2020-27781-1.patch new file mode 100644 index 0000000..81153e7 --- /dev/null +++ b/0011-CVE-2020-27781-1.patch @@ -0,0 +1,48 @@ +From 7e45e2905f2f61bf9d100308df979f432754982b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?=C4=90=E1=BA=B7ng=20Minh=20D=C5=A9ng?= +Date: Sun, 10 May 2020 11:37:23 +0700 +Subject: [PATCH 1/5] pybind/ceph_volume_client: Fix PEP-8 SyntaxWarning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Đặng Minh Dũng +(cherry picked from commit 3ce9a89a5a1a2d7fa3d57c597b781a6aece7cbb5) +--- + src/pybind/ceph_volume_client.py | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/pybind/ceph_volume_client.py b/src/pybind/ceph_volume_client.py +index 06380ef417f..215c74f5186 100644 +--- a/src/pybind/ceph_volume_client.py ++++ b/src/pybind/ceph_volume_client.py +@@ -335,7 +335,7 @@ class CephFSVolumeClient(object): + continue + + (group_id, volume_id) = volume.split('/') +- group_id = group_id if group_id is not 'None' else None ++ group_id = group_id if group_id != 'None' else None + volume_path = VolumePath(group_id, volume_id) + access_level = volume_data['access_level'] + +@@ -358,7 +358,7 @@ class CephFSVolumeClient(object): + if vol_meta['auths'][auth_id] == want_auth: + continue + +- readonly = True if access_level is 'r' else False ++ readonly = access_level == 'r' + self._authorize_volume(volume_path, auth_id, readonly) + + # Recovered from partial auth updates for the auth ID's access +@@ -1088,7 +1088,7 @@ class CephFSVolumeClient(object): + + # Construct auth caps that if present might conflict with the desired + # auth caps. +- unwanted_access_level = 'r' if want_access_level is 'rw' else 'rw' ++ unwanted_access_level = 'r' if want_access_level == 'rw' else 'rw' + unwanted_mds_cap = 'allow {0} path={1}'.format(unwanted_access_level, path) + if namespace: + unwanted_osd_cap = 'allow {0} pool={1} namespace={2}'.format( +-- +2.23.0 + diff --git a/0012-CVE-2020-27781-2.patch b/0012-CVE-2020-27781-2.patch new file mode 100644 index 0000000..0d03989 --- /dev/null +++ b/0012-CVE-2020-27781-2.patch @@ -0,0 +1,172 @@ +From 1de5caf2da9b06aa4f363f9706c693213a6ee59f Mon Sep 17 00:00:00 2001 +From: Ramana Raja +Date: Wed, 25 Nov 2020 16:44:35 +0530 +Subject: [PATCH 2/5] pybind/ceph_volume_client: Disallow authorize auth_id + +This patch disallow the ceph_volume_client to authorize the auth_id +which is not created by ceph_volume_client. Those auth_ids could be +created by other means for other use cases which should not be modified +by ceph_volume_client. + +Fixes: https://tracker.ceph.com/issues/48555 +Signed-off-by: Ramana Raja +Signed-off-by: Kotresh HR +(cherry picked from commit 3a85d2d04028a323952a31d18cdbefb710be2e2b) +--- + src/pybind/ceph_volume_client.py | 63 ++++++++++++++++++++------------ + 1 file changed, 39 insertions(+), 24 deletions(-) + +diff --git a/src/pybind/ceph_volume_client.py b/src/pybind/ceph_volume_client.py +index 215c74f5186..a639fee7dea 100644 +--- a/src/pybind/ceph_volume_client.py ++++ b/src/pybind/ceph_volume_client.py +@@ -213,6 +213,7 @@ CEPHFSVOLUMECLIENT_VERSION_HISTORY = """ + * 2 - Added get_object, put_object, delete_object methods to CephFSVolumeClient + * 3 - Allow volumes to be created without RADOS namespace isolation + * 4 - Added get_object_and_version, put_object_versioned method to CephFSVolumeClient ++ * 5 - Disallow authorize API for users not created by CephFSVolumeClient + """ + + +@@ -236,7 +237,7 @@ class CephFSVolumeClient(object): + """ + + # Current version +- version = 4 ++ version = 5 + + # Where shall we create our volumes? + POOL_PREFIX = "fsvolume_" +@@ -359,7 +360,18 @@ class CephFSVolumeClient(object): + continue + + readonly = access_level == 'r' +- self._authorize_volume(volume_path, auth_id, readonly) ++ client_entity = "client.{0}".format(auth_id) ++ try: ++ existing_caps = self._rados_command( ++ 'auth get', ++ { ++ 'entity': client_entity ++ } ++ ) ++ # FIXME: rados raising Error instead of ObjectNotFound in auth get failure ++ except rados.Error: ++ existing_caps = None ++ self._authorize_volume(volume_path, auth_id, readonly, existing_caps) + + # Recovered from partial auth updates for the auth ID's access + # to a volume. +@@ -943,6 +955,18 @@ class CephFSVolumeClient(object): + """ + + with self._auth_lock(auth_id): ++ client_entity = "client.{0}".format(auth_id) ++ try: ++ existing_caps = self._rados_command( ++ 'auth get', ++ { ++ 'entity': client_entity ++ } ++ ) ++ # FIXME: rados raising Error instead of ObjectNotFound in auth get failure ++ except rados.Error: ++ existing_caps = None ++ + # Existing meta, or None, to be updated + auth_meta = self._auth_metadata_get(auth_id) + +@@ -956,7 +980,14 @@ class CephFSVolumeClient(object): + 'dirty': True, + } + } ++ + if auth_meta is None: ++ if existing_caps is not None: ++ msg = "auth ID: {0} exists and not created by ceph_volume_client. Not allowed to modify".format(auth_id) ++ log.error(msg) ++ raise CephFSVolumeClientError(msg) ++ ++ # non-existent auth IDs + sys.stderr.write("Creating meta for ID {0} with tenant {1}\n".format( + auth_id, tenant_id + )) +@@ -966,14 +997,6 @@ class CephFSVolumeClient(object): + 'tenant_id': tenant_id.__str__() if tenant_id else None, + 'volumes': volume + } +- +- # Note: this is *not* guaranteeing that the key doesn't already +- # exist in Ceph: we are allowing VolumeClient tenants to +- # 'claim' existing Ceph keys. In order to prevent VolumeClient +- # tenants from reading e.g. client.admin keys, you need to +- # have configured your VolumeClient user (e.g. Manila) to +- # have mon auth caps that prevent it from accessing those keys +- # (e.g. limit it to only access keys with a manila.* prefix) + else: + # Disallow tenants to share auth IDs + if auth_meta['tenant_id'].__str__() != tenant_id.__str__(): +@@ -993,7 +1016,7 @@ class CephFSVolumeClient(object): + self._auth_metadata_set(auth_id, auth_meta) + + with self._volume_lock(volume_path): +- key = self._authorize_volume(volume_path, auth_id, readonly) ++ key = self._authorize_volume(volume_path, auth_id, readonly, existing_caps) + + auth_meta['dirty'] = False + auth_meta['volumes'][volume_path_str]['dirty'] = False +@@ -1010,7 +1033,7 @@ class CephFSVolumeClient(object): + 'auth_key': None + } + +- def _authorize_volume(self, volume_path, auth_id, readonly): ++ def _authorize_volume(self, volume_path, auth_id, readonly, existing_caps): + vol_meta = self._volume_metadata_get(volume_path) + + access_level = 'r' if readonly else 'rw' +@@ -1029,14 +1052,14 @@ class CephFSVolumeClient(object): + vol_meta['auths'].update(auth) + self._volume_metadata_set(volume_path, vol_meta) + +- key = self._authorize_ceph(volume_path, auth_id, readonly) ++ key = self._authorize_ceph(volume_path, auth_id, readonly, existing_caps) + + vol_meta['auths'][auth_id]['dirty'] = False + self._volume_metadata_set(volume_path, vol_meta) + + return key + +- def _authorize_ceph(self, volume_path, auth_id, readonly): ++ def _authorize_ceph(self, volume_path, auth_id, readonly, existing_caps): + path = self._get_path(volume_path) + log.debug("Authorizing Ceph id '{0}' for path '{1}'".format( + auth_id, path +@@ -1064,15 +1087,7 @@ class CephFSVolumeClient(object): + want_osd_cap = 'allow {0} pool={1}'.format(want_access_level, + pool_name) + +- try: +- existing = self._rados_command( +- 'auth get', +- { +- 'entity': client_entity +- } +- ) +- # FIXME: rados raising Error instead of ObjectNotFound in auth get failure +- except rados.Error: ++ if existing_caps is None: + caps = self._rados_command( + 'auth get-or-create', + { +@@ -1084,7 +1099,7 @@ class CephFSVolumeClient(object): + }) + else: + # entity exists, update it +- cap = existing[0] ++ cap = existing_caps[0] + + # Construct auth caps that if present might conflict with the desired + # auth caps. +-- +2.23.0 + diff --git a/0013-CVE-2020-27781-3.patch b/0013-CVE-2020-27781-3.patch new file mode 100644 index 0000000..d6e8528 --- /dev/null +++ b/0013-CVE-2020-27781-3.patch @@ -0,0 +1,113 @@ +From eb2fa6934fc736f8abe6d9e237b0a14c9d877626 Mon Sep 17 00:00:00 2001 +From: Kotresh HR +Date: Thu, 26 Nov 2020 14:48:16 +0530 +Subject: [PATCH 3/5] pybind/ceph_volume_client: Preserve existing caps while + authorize/deauthorize auth-id + +Authorize/Deauthorize used to overwrite the caps of auth-id which would +end up deleting existing caps. This patch fixes the same by retaining +the existing caps by appending or deleting the new caps as needed. + +Fixes: https://tracker.ceph.com/issues/48555 +Signed-off-by: Kotresh HR +(cherry picked from commit 47100e528ef77e7e82dc9877424243dc6a7e7533) +--- + src/pybind/ceph_volume_client.py | 43 ++++++++++++++++++++++---------- + 1 file changed, 30 insertions(+), 13 deletions(-) + +diff --git a/src/pybind/ceph_volume_client.py b/src/pybind/ceph_volume_client.py +index a639fee7dea..33f6beabd18 100644 +--- a/src/pybind/ceph_volume_client.py ++++ b/src/pybind/ceph_volume_client.py +@@ -941,6 +941,26 @@ class CephFSVolumeClient(object): + data['version'] = self.version + return self._metadata_set(self._volume_metadata_path(volume_path), data) + ++ def _prepare_updated_caps_list(self, existing_caps, mds_cap_str, osd_cap_str, authorize=True): ++ caps_list = [] ++ for k, v in existing_caps['caps'].items(): ++ if k == 'mds' or k == 'osd': ++ continue ++ elif k == 'mon': ++ if not authorize and v == 'allow r': ++ continue ++ caps_list.extend((k,v)) ++ ++ if mds_cap_str: ++ caps_list.extend(('mds', mds_cap_str)) ++ if osd_cap_str: ++ caps_list.extend(('osd', osd_cap_str)) ++ ++ if authorize and 'mon' not in caps_list: ++ caps_list.extend(('mon', 'allow r')) ++ ++ return caps_list ++ + def authorize(self, volume_path, auth_id, readonly=False, tenant_id=None): + """ + Get-or-create a Ceph auth identity for `auth_id` and grant them access +@@ -1119,8 +1139,8 @@ class CephFSVolumeClient(object): + if not orig_mds_caps: + return want_mds_cap, want_osd_cap + +- mds_cap_tokens = orig_mds_caps.split(",") +- osd_cap_tokens = orig_osd_caps.split(",") ++ mds_cap_tokens = [x.strip() for x in orig_mds_caps.split(",")] ++ osd_cap_tokens = [x.strip() for x in orig_osd_caps.split(",")] + + if want_mds_cap in mds_cap_tokens: + return orig_mds_caps, orig_osd_caps +@@ -1141,15 +1161,14 @@ class CephFSVolumeClient(object): + orig_mds_caps, orig_osd_caps, want_mds_cap, want_osd_cap, + unwanted_mds_cap, unwanted_osd_cap) + ++ caps_list = self._prepare_updated_caps_list(cap, mds_cap_str, osd_cap_str) + caps = self._rados_command( + 'auth caps', + { + 'entity': client_entity, +- 'caps': [ +- 'mds', mds_cap_str, +- 'osd', osd_cap_str, +- 'mon', cap['caps'].get('mon', 'allow r')] ++ 'caps': caps_list + }) ++ + caps = self._rados_command( + 'auth get', + { +@@ -1274,8 +1293,8 @@ class CephFSVolumeClient(object): + ) + + def cap_remove(orig_mds_caps, orig_osd_caps, want_mds_caps, want_osd_caps): +- mds_cap_tokens = orig_mds_caps.split(",") +- osd_cap_tokens = orig_osd_caps.split(",") ++ mds_cap_tokens = [x.strip() for x in orig_mds_caps.split(",")] ++ osd_cap_tokens = [x.strip() for x in orig_osd_caps.split(",")] + + for want_mds_cap, want_osd_cap in zip(want_mds_caps, want_osd_caps): + if want_mds_cap in mds_cap_tokens: +@@ -1291,17 +1310,15 @@ class CephFSVolumeClient(object): + mds_cap_str, osd_cap_str = cap_remove(orig_mds_caps, orig_osd_caps, + want_mds_caps, want_osd_caps) + +- if not mds_cap_str: ++ caps_list = self._prepare_updated_caps_list(cap, mds_cap_str, osd_cap_str, authorize=False) ++ if not caps_list: + self._rados_command('auth del', {'entity': client_entity}, decode=False) + else: + self._rados_command( + 'auth caps', + { + 'entity': client_entity, +- 'caps': [ +- 'mds', mds_cap_str, +- 'osd', osd_cap_str, +- 'mon', cap['caps'].get('mon', 'allow r')] ++ 'caps': caps_list + }) + + # FIXME: rados raising Error instead of ObjectNotFound in auth get failure +-- +2.23.0 + diff --git a/0014-CVE-2020-27781-4.patch b/0014-CVE-2020-27781-4.patch new file mode 100644 index 0000000..f887a38 --- /dev/null +++ b/0014-CVE-2020-27781-4.patch @@ -0,0 +1,52 @@ +From ae1889014e5becb774b69ca52ed7465a33873a3f Mon Sep 17 00:00:00 2001 +From: Kotresh HR +Date: Sun, 6 Dec 2020 12:40:20 +0530 +Subject: [PATCH 4/5] pybind/ceph_volume_client: Optionally authorize existing + auth-ids + +Optionally allow authorizing auth-ids not created by ceph_volume_client +via the option 'allow_existing_id'. This can help existing deployers +of manila to disallow/allow authorization of pre-created auth IDs +via a manila driver config that sets 'allow_existing_id' to False/True. + +Fixes: https://tracker.ceph.com/issues/48555 +Signed-off-by: Kotresh HR +(cherry picked from commit 77b42496e25cbd4af2e80a064ddf26221b53733f) +--- + src/pybind/ceph_volume_client.py | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/src/pybind/ceph_volume_client.py b/src/pybind/ceph_volume_client.py +index 33f6beabd18..7f48a466079 100644 +--- a/src/pybind/ceph_volume_client.py ++++ b/src/pybind/ceph_volume_client.py +@@ -961,7 +961,7 @@ class CephFSVolumeClient(object): + + return caps_list + +- def authorize(self, volume_path, auth_id, readonly=False, tenant_id=None): ++ def authorize(self, volume_path, auth_id, readonly=False, tenant_id=None, allow_existing_id=False): + """ + Get-or-create a Ceph auth identity for `auth_id` and grant them access + to +@@ -971,6 +971,8 @@ class CephFSVolumeClient(object): + :param tenant_id: Optionally provide a stringizable object to + restrict any created cephx IDs to other callers + passing the same tenant ID. ++ :allow_existing_id: Optionally authorize existing auth-ids not ++ created by ceph_volume_client + :return: + """ + +@@ -1002,7 +1004,7 @@ class CephFSVolumeClient(object): + } + + if auth_meta is None: +- if existing_caps is not None: ++ if not allow_existing_id and existing_caps is not None: + msg = "auth ID: {0} exists and not created by ceph_volume_client. Not allowed to modify".format(auth_id) + log.error(msg) + raise CephFSVolumeClientError(msg) +-- +2.23.0 + diff --git a/0015-CVE-2020-27781-5.patch b/0015-CVE-2020-27781-5.patch new file mode 100644 index 0000000..8980a20 --- /dev/null +++ b/0015-CVE-2020-27781-5.patch @@ -0,0 +1,275 @@ +From a036cf3cbf47bbc8fd7793a80767c1257ed426d1 Mon Sep 17 00:00:00 2001 +From: Kotresh HR +Date: Tue, 1 Dec 2020 16:14:17 +0530 +Subject: [PATCH 5/5] tasks/cephfs/test_volume_client: Add tests for + authorize/deauthorize + +1. Add testcase for authorizing auth_id which is not added by + ceph_volume_client +2. Add testcase to test 'allow_existing_id' option +3. Add testcase for deauthorizing auth_id which has got it's caps + updated out of band + +Signed-off-by: Kotresh HR +(cherry picked from commit aa4beb3d993649a696af95cf27150cc460baaf70) + +Conflicts: + qa/tasks/cephfs/test_volume_client.py +--- + qa/tasks/cephfs/test_volume_client.py | 213 +++++++++++++++++++++++++- + 1 file changed, 209 insertions(+), 4 deletions(-) + +diff --git a/qa/tasks/cephfs/test_volume_client.py b/qa/tasks/cephfs/test_volume_client.py +index 06094dd6fe9..bdb4ad022d8 100644 +--- a/qa/tasks/cephfs/test_volume_client.py ++++ b/qa/tasks/cephfs/test_volume_client.py +@@ -81,7 +81,7 @@ vc.disconnect() + def _configure_guest_auth(self, volumeclient_mount, guest_mount, + guest_entity, mount_path, + namespace_prefix=None, readonly=False, +- tenant_id=None): ++ tenant_id=None, allow_existing_id=False): + """ + Set up auth credentials for the guest client to mount a volume. + +@@ -106,14 +106,16 @@ vc.disconnect() + key = self._volume_client_python(volumeclient_mount, dedent(""" + vp = VolumePath("{group_id}", "{volume_id}") + auth_result = vc.authorize(vp, "{guest_entity}", readonly={readonly}, +- tenant_id="{tenant_id}") ++ tenant_id="{tenant_id}", ++ allow_existing_id="{allow_existing_id}") + print(auth_result['auth_key']) + """.format( + group_id=group_id, + volume_id=volume_id, + guest_entity=guest_entity, + readonly=readonly, +- tenant_id=tenant_id)), volume_prefix, namespace_prefix ++ tenant_id=tenant_id, ++ allow_existing_id=allow_existing_id)), volume_prefix, namespace_prefix + ) + + # CephFSVolumeClient's authorize() does not return the secret +@@ -886,6 +888,209 @@ vc.disconnect() + ))) + self.assertNotIn(vol_metadata_filename, self.mounts[0].ls("volumes")) + ++ def test_authorize_auth_id_not_created_by_ceph_volume_client(self): ++ """ ++ If the auth_id already exists and is not created by ++ ceph_volume_client, it's not allowed to authorize ++ the auth-id by default. ++ """ ++ volumeclient_mount = self.mounts[1] ++ volumeclient_mount.umount_wait() ++ ++ # Configure volumeclient_mount as the handle for driving volumeclient. ++ self._configure_vc_auth(volumeclient_mount, "manila") ++ ++ group_id = "groupid" ++ volume_id = "volumeid" ++ ++ # Create auth_id ++ out = self.fs.mon_manager.raw_cluster_cmd( ++ "auth", "get-or-create", "client.guest1", ++ "mds", "allow *", ++ "osd", "allow rw", ++ "mon", "allow *" ++ ) ++ ++ auth_id = "guest1" ++ guestclient_1 = { ++ "auth_id": auth_id, ++ "tenant_id": "tenant1", ++ } ++ ++ # Create a volume. ++ self._volume_client_python(volumeclient_mount, dedent(""" ++ vp = VolumePath("{group_id}", "{volume_id}") ++ vc.create_volume(vp, 1024*1024*10) ++ """.format( ++ group_id=group_id, ++ volume_id=volume_id, ++ ))) ++ ++ # Cannot authorize 'guestclient_1' to access the volume. ++ # It uses auth ID 'guest1', which already exists and not ++ # created by ceph_volume_client ++ with self.assertRaises(CommandFailedError): ++ self._volume_client_python(volumeclient_mount, dedent(""" ++ vp = VolumePath("{group_id}", "{volume_id}") ++ vc.authorize(vp, "{auth_id}", tenant_id="{tenant_id}") ++ """.format( ++ group_id=group_id, ++ volume_id=volume_id, ++ auth_id=guestclient_1["auth_id"], ++ tenant_id=guestclient_1["tenant_id"] ++ ))) ++ ++ # Delete volume ++ self._volume_client_python(volumeclient_mount, dedent(""" ++ vp = VolumePath("{group_id}", "{volume_id}") ++ vc.delete_volume(vp) ++ """.format( ++ group_id=group_id, ++ volume_id=volume_id, ++ ))) ++ ++ def test_authorize_allow_existing_id_option(self): ++ """ ++ If the auth_id already exists and is not created by ++ ceph_volume_client, it's not allowed to authorize ++ the auth-id by default but is allowed with option ++ allow_existing_id. ++ """ ++ volumeclient_mount = self.mounts[1] ++ volumeclient_mount.umount_wait() ++ ++ # Configure volumeclient_mount as the handle for driving volumeclient. ++ self._configure_vc_auth(volumeclient_mount, "manila") ++ ++ group_id = "groupid" ++ volume_id = "volumeid" ++ ++ # Create auth_id ++ out = self.fs.mon_manager.raw_cluster_cmd( ++ "auth", "get-or-create", "client.guest1", ++ "mds", "allow *", ++ "osd", "allow rw", ++ "mon", "allow *" ++ ) ++ ++ auth_id = "guest1" ++ guestclient_1 = { ++ "auth_id": auth_id, ++ "tenant_id": "tenant1", ++ } ++ ++ # Create a volume. ++ self._volume_client_python(volumeclient_mount, dedent(""" ++ vp = VolumePath("{group_id}", "{volume_id}") ++ vc.create_volume(vp, 1024*1024*10) ++ """.format( ++ group_id=group_id, ++ volume_id=volume_id, ++ ))) ++ ++ # Cannot authorize 'guestclient_1' to access the volume ++ # by default, which already exists and not created by ++ # ceph_volume_client but is allowed with option 'allow_existing_id'. ++ self._volume_client_python(volumeclient_mount, dedent(""" ++ vp = VolumePath("{group_id}", "{volume_id}") ++ vc.authorize(vp, "{auth_id}", tenant_id="{tenant_id}", ++ allow_existing_id="{allow_existing_id}") ++ """.format( ++ group_id=group_id, ++ volume_id=volume_id, ++ auth_id=guestclient_1["auth_id"], ++ tenant_id=guestclient_1["tenant_id"], ++ allow_existing_id=True ++ ))) ++ ++ # Delete volume ++ self._volume_client_python(volumeclient_mount, dedent(""" ++ vp = VolumePath("{group_id}", "{volume_id}") ++ vc.delete_volume(vp) ++ """.format( ++ group_id=group_id, ++ volume_id=volume_id, ++ ))) ++ ++ def test_deauthorize_auth_id_after_out_of_band_update(self): ++ """ ++ If the auth_id authorized by ceph_volume_client is updated ++ out of band, the auth_id should not be deleted after a ++ deauthorize. It should only remove caps associated it. ++ """ ++ volumeclient_mount = self.mounts[1] ++ volumeclient_mount.umount_wait() ++ ++ # Configure volumeclient_mount as the handle for driving volumeclient. ++ self._configure_vc_auth(volumeclient_mount, "manila") ++ ++ group_id = "groupid" ++ volume_id = "volumeid" ++ ++ ++ auth_id = "guest1" ++ guestclient_1 = { ++ "auth_id": auth_id, ++ "tenant_id": "tenant1", ++ } ++ ++ # Create a volume. ++ self._volume_client_python(volumeclient_mount, dedent(""" ++ vp = VolumePath("{group_id}", "{volume_id}") ++ vc.create_volume(vp, 1024*1024*10) ++ """.format( ++ group_id=group_id, ++ volume_id=volume_id, ++ ))) ++ ++ # Authorize 'guestclient_1' to access the volume. ++ self._volume_client_python(volumeclient_mount, dedent(""" ++ vp = VolumePath("{group_id}", "{volume_id}") ++ vc.authorize(vp, "{auth_id}", tenant_id="{tenant_id}") ++ """.format( ++ group_id=group_id, ++ volume_id=volume_id, ++ auth_id=guestclient_1["auth_id"], ++ tenant_id=guestclient_1["tenant_id"] ++ ))) ++ ++ # Update caps for guestclient_1 out of band ++ out = self.fs.mon_manager.raw_cluster_cmd( ++ "auth", "caps", "client.guest1", ++ "mds", "allow rw path=/volumes/groupid, allow rw path=/volumes/groupid/volumeid", ++ "osd", "allow rw pool=cephfs_data namespace=fsvolumens_volumeid", ++ "mon", "allow r", ++ "mgr", "allow *" ++ ) ++ ++ # Deauthorize guestclient_1 ++ self._volume_client_python(volumeclient_mount, dedent(""" ++ vp = VolumePath("{group_id}", "{volume_id}") ++ vc.deauthorize(vp, "{guest_entity}") ++ """.format( ++ group_id=group_id, ++ volume_id=volume_id, ++ guest_entity=guestclient_1["auth_id"] ++ ))) ++ ++ # Validate the caps of guestclient_1 after deauthorize. It should not have deleted ++ # guestclient_1. The mgr and mds caps should be present which was updated out of band. ++ out = json.loads(self.fs.mon_manager.raw_cluster_cmd("auth", "get", "client.guest1", "--format=json-pretty")) ++ ++ self.assertEqual("client.guest1", out[0]["entity"]) ++ self.assertEqual("allow rw path=/volumes/groupid", out[0]["caps"]["mds"]) ++ self.assertEqual("allow *", out[0]["caps"]["mgr"]) ++ self.assertNotIn("osd", out[0]["caps"]) ++ ++ # Delete volume ++ self._volume_client_python(volumeclient_mount, dedent(""" ++ vp = VolumePath("{group_id}", "{volume_id}") ++ vc.delete_volume(vp) ++ """.format( ++ group_id=group_id, ++ volume_id=volume_id, ++ ))) ++ + def test_recover_metadata(self): + """ + That volume client can recover from partial auth updates using +@@ -1067,7 +1272,7 @@ vc.disconnect() + guest_mount.umount_wait() + + # Set auth caps for the auth ID using the volumeclient +- self._configure_guest_auth(vc_mount, guest_mount, guest_id, mount_path) ++ self._configure_guest_auth(vc_mount, guest_mount, guest_id, mount_path, allow_existing_id=True) + + # Mount the volume in the guest using the auth ID to assert that the + # auth caps are valid +-- +2.23.0 + diff --git a/ceph.spec b/ceph.spec index a35ca3f..b143221 100644 --- a/ceph.spec +++ b/ceph.spec @@ -68,7 +68,7 @@ ################################################################################# Name: ceph Version: 12.2.8 -Release: 12 +Release: 13 Epoch: 2 # define _epoch_prefix macro which will expand to the empty string if epoch is @@ -91,6 +91,14 @@ Patch4: 0004-CVE-2018-14662.patch Patch5: 0005-CVE-2020-12059.patch Patch6: 0006-CVE-2020-25678-1.patch Patch7: 0007-CVE-2020-25678-2.patch +Patch8: 0008-ceph-volume-client-allow-atomic-updates-for-RADOS-ob.patch +Patch9: 0009-qa-ceph-volume-add-a-test-for-put_object_versioned.patch +Patch10: 0010-qa-make-test_volume_client.py-py3-compatible.patch +Patch11: 0011-CVE-2020-27781-1.patch +Patch12: 0012-CVE-2020-27781-2.patch +Patch13: 0013-CVE-2020-27781-3.patch +Patch14: 0014-CVE-2020-27781-4.patch +Patch15: 0015-CVE-2020-27781-5.patch %if 0%{?suse_version} %if 0%{?is_opensuse} @@ -1799,6 +1807,11 @@ exit 0 %changelog +* Sun Jul 18 2021 chixinze - 1:12.2.8-13 +- fix CVE-2020-27781 +- ceph-volume-client: allow atomic updates for RADOS objects +- qa: make test_volume_client.py py3 compatible + * Wed Mar 10 2021 Zhuohui Zou - 1:12.2.8-12 - fix CVE-2020-25678 -- Gitee From aafaabb729bbbe48cfc88da57476880a7fa6d6f8 Mon Sep 17 00:00:00 2001 From: chixinze Date: Mon, 26 Jul 2021 16:47:18 +0800 Subject: [PATCH 05/12] fix CVE-2020-10753 CVE-2021-3524 CVE-2020-1760 Signed-off-by: chixinze --- 0016-CVE-2020-10753-1.patch | 47 +++++++++++++++++++++++++++++ 0017-CVE-2021-3524-1.patch | 36 ++++++++++++++++++++++ 0018-CVE-2020-1760-1.patch | 31 +++++++++++++++++++ 0019-CVE-2020-1760-2.patch | 28 ++++++++++++++++++ 0020-CVE-2020-1760-3.patch | 59 +++++++++++++++++++++++++++++++++++++ ceph.spec | 12 +++++++- 6 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 0016-CVE-2020-10753-1.patch create mode 100644 0017-CVE-2021-3524-1.patch create mode 100644 0018-CVE-2020-1760-1.patch create mode 100644 0019-CVE-2020-1760-2.patch create mode 100644 0020-CVE-2020-1760-3.patch diff --git a/0016-CVE-2020-10753-1.patch b/0016-CVE-2020-10753-1.patch new file mode 100644 index 0000000..15ad687 --- /dev/null +++ b/0016-CVE-2020-10753-1.patch @@ -0,0 +1,47 @@ +From 46817f30cee60bc5df8354ab326762e7c783fe2c Mon Sep 17 00:00:00 2001 +From: Casey Bodley +Date: Tue, 26 May 2020 15:03:03 -0400 +Subject: [PATCH] rgw: sanitize newlines in s3 CORSConfiguration's ExposeHeader + +the values in the element are sent back to clients in a +Access-Control-Expose-Headers response header. if the values are allowed +to have newlines in them, they can be used to inject arbitrary response +headers + +this issue only affects s3, which gets these values from an xml document + +in swift, they're given in the request header +X-Container-Meta-Access-Control-Expose-Headers, so the value itself +cannot contain newlines + +Signed-off-by: Casey Bodley +Reported-by: Adam Mohammed +--- + src/rgw/rgw_cors.cc | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/src/rgw/rgw_cors.cc b/src/rgw/rgw_cors.cc +index 07dbab5d3e2..0b3e4f39455 100644 +--- a/src/rgw/rgw_cors.cc ++++ b/src/rgw/rgw_cors.cc +@@ -144,11 +144,12 @@ bool RGWCORSRule::is_header_allowed(const char *h, size_t len) { + + void RGWCORSRule::format_exp_headers(string& s) { + s = ""; +- for(list::iterator it = exposable_hdrs.begin(); +- it != exposable_hdrs.end(); ++it) { +- if (s.length() > 0) +- s.append(","); +- s.append((*it)); ++ for (const auto& header : exposable_hdrs) { ++ if (s.length() > 0) ++ s.append(","); ++ // these values are sent to clients in a 'Access-Control-Expose-Headers' ++ // response header, so we escape '\n' to avoid header injection ++ boost::replace_all_copy(std::back_inserter(s), header, "\n", "\\n"); + } + } + +-- +2.23.0 + diff --git a/0017-CVE-2021-3524-1.patch b/0017-CVE-2021-3524-1.patch new file mode 100644 index 0000000..f304983 --- /dev/null +++ b/0017-CVE-2021-3524-1.patch @@ -0,0 +1,36 @@ +From 763aebb94678018f89427137ffbc0c5205b1edc1 Mon Sep 17 00:00:00 2001 +From: Casey Bodley +Date: Tue, 4 May 2021 08:32:58 -0400 +Subject: [PATCH] rgw: sanitize \r in s3 CORSConfiguration's ExposeHeader + +follows up on 1524d3c0c5cb11775313ea1e2bb36a93257947f2 to escape \r as +well + +Fixes: CVE-2021-3524 + +Reported-by: Sergey Bobrov +Signed-off-by: Casey Bodley +(cherry picked from commit 87806f48e7a1b8891eb90711f1cedd26f1119aac) +--- + src/rgw/rgw_cors.cc | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/rgw/rgw_cors.cc b/src/rgw/rgw_cors.cc +index 0b3e4f39455..bfe83d6420e 100644 +--- a/src/rgw/rgw_cors.cc ++++ b/src/rgw/rgw_cors.cc +@@ -148,8 +148,9 @@ void RGWCORSRule::format_exp_headers(string& s) { + if (s.length() > 0) + s.append(","); + // these values are sent to clients in a 'Access-Control-Expose-Headers' +- // response header, so we escape '\n' to avoid header injection +- boost::replace_all_copy(std::back_inserter(s), header, "\n", "\\n"); ++ // response header, so we escape '\n' and '\r' to avoid header injection ++ std::string tmp = boost::replace_all_copy(header, "\n", "\\n"); ++ boost::replace_all_copy(std::back_inserter(s), tmp, "\r", "\\r"); + } + } + +-- +2.23.0 + diff --git a/0018-CVE-2020-1760-1.patch b/0018-CVE-2020-1760-1.patch new file mode 100644 index 0000000..cc8664d --- /dev/null +++ b/0018-CVE-2020-1760-1.patch @@ -0,0 +1,31 @@ +From ba0790a01ba5252db1ebc299db6e12cd758d0ff9 Mon Sep 17 00:00:00 2001 +From: Matt Benjamin +Date: Fri, 27 Mar 2020 18:13:48 +0100 +Subject: [PATCH] rgw: reject unauthenticated response-header actions + +Signed-off-by: Matt Benjamin +Reviewed-by: Casey Bodley +(cherry picked from commit d8dd5e513c0c62bbd7d3044d7e2eddcd897bd400) +--- + src/rgw/rgw_rest_s3.cc | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc +index b0e36dec5d8..5dc6a562051 100644 +--- a/src/rgw/rgw_rest_s3.cc ++++ b/src/rgw/rgw_rest_s3.cc +@@ -266,6 +266,11 @@ int RGWGetObj_ObjStore_S3::send_response_data(bufferlist& bl, off_t bl_ofs, + bool exists; + string val = s->info.args.get(p->param, &exists); + if (exists) { ++ /* reject unauthenticated response header manipulation, see ++ * https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html */ ++ if (s->auth.identity->is_anonymous()) { ++ return -EPERM; ++ } + if (strcmp(p->param, "response-content-type") != 0) { + response_attrs[p->http_attr] = val; + } else { +-- +2.23.0 + diff --git a/0019-CVE-2020-1760-2.patch b/0019-CVE-2020-1760-2.patch new file mode 100644 index 0000000..3f6d9e9 --- /dev/null +++ b/0019-CVE-2020-1760-2.patch @@ -0,0 +1,28 @@ +From 607a65fccd8a80c2f2c74853a6dc5c14ed8a75c1 Mon Sep 17 00:00:00 2001 +From: Abhishek Lekshmanan +Date: Fri, 27 Mar 2020 19:29:01 +0100 +Subject: [PATCH] rgw: EPERM to ERR_INVALID_REQUEST + +As per Robin's comments and S3 spec + +Signed-off-by: Abhishek Lekshmanan +--- + src/rgw/rgw_rest_s3.cc | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc +index 5dc6a562051..dc49caae18d 100644 +--- a/src/rgw/rgw_rest_s3.cc ++++ b/src/rgw/rgw_rest_s3.cc +@@ -269,7 +269,7 @@ int RGWGetObj_ObjStore_S3::send_response_data(bufferlist& bl, off_t bl_ofs, + /* reject unauthenticated response header manipulation, see + * https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html */ + if (s->auth.identity->is_anonymous()) { +- return -EPERM; ++ return -ERR_INVALID_REQUEST; + } + if (strcmp(p->param, "response-content-type") != 0) { + response_attrs[p->http_attr] = val; +-- +2.23.0 + diff --git a/0020-CVE-2020-1760-3.patch b/0020-CVE-2020-1760-3.patch new file mode 100644 index 0000000..9141abe --- /dev/null +++ b/0020-CVE-2020-1760-3.patch @@ -0,0 +1,59 @@ +From 9ca5b3628245e2878426602bb24f1a4e45edc850 Mon Sep 17 00:00:00 2001 +From: "Robin H. Johnson" +Date: Fri, 27 Mar 2020 20:48:13 +0100 +Subject: [PATCH] rgw: reject control characters in response-header actions + +S3 GetObject permits overriding response header values, but those inputs +need to be validated to insure only characters that are valid in an HTTP +header value are present. + +Credit: Initial vulnerability discovery by William Bowling (@wcbowling) +Credit: Further vulnerability discovery by Robin H. Johnson +Signed-off-by: Robin H. Johnson +--- + src/rgw/rgw_rest_s3.cc | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc +index dc49caae18d..459dd1dc715 100644 +--- a/src/rgw/rgw_rest_s3.cc ++++ b/src/rgw/rgw_rest_s3.cc +@@ -167,6 +167,15 @@ int decode_attr_bl_single_value(map& attrs, const char *attr + return 0; + } + ++inline bool str_has_cntrl(const std::string s) { ++ return std::any_of(s.begin(), s.end(), ::iscntrl); ++} ++ ++inline bool str_has_cntrl(const char* s) { ++ std::string _s(s); ++ return str_has_cntrl(_s); ++} ++ + int RGWGetObj_ObjStore_S3::send_response_data(bufferlist& bl, off_t bl_ofs, + off_t bl_len) + { +@@ -271,6 +280,19 @@ int RGWGetObj_ObjStore_S3::send_response_data(bufferlist& bl, off_t bl_ofs, + if (s->auth.identity->is_anonymous()) { + return -ERR_INVALID_REQUEST; + } ++ /* HTTP specification says no control characters should be present in ++ * header values: https://tools.ietf.org/html/rfc7230#section-3.2 ++ * field-vchar = VCHAR / obs-text ++ * ++ * Failure to validate this permits a CRLF injection in HTTP headers, ++ * whereas S3 GetObject only permits specific headers. ++ */ ++ if(str_has_cntrl(val)) { ++ /* TODO: return a more distinct error in future; ++ * stating what the problem is */ ++ return -ERR_INVALID_REQUEST; ++ } ++ + if (strcmp(p->param, "response-content-type") != 0) { + response_attrs[p->http_attr] = val; + } else { +-- +2.23.0 + diff --git a/ceph.spec b/ceph.spec index b143221..e61d5f9 100644 --- a/ceph.spec +++ b/ceph.spec @@ -68,7 +68,7 @@ ################################################################################# Name: ceph Version: 12.2.8 -Release: 13 +Release: 14 Epoch: 2 # define _epoch_prefix macro which will expand to the empty string if epoch is @@ -99,6 +99,11 @@ Patch12: 0012-CVE-2020-27781-2.patch Patch13: 0013-CVE-2020-27781-3.patch Patch14: 0014-CVE-2020-27781-4.patch Patch15: 0015-CVE-2020-27781-5.patch +Patch16: 0016-CVE-2020-10753-1.patch +Patch17: 0017-CVE-2021-3524-1.patch +Patch18: 0018-CVE-2020-1760-1.patch +Patch19: 0019-CVE-2020-1760-2.patch +Patch20: 0020-CVE-2020-1760-3.patch %if 0%{?suse_version} %if 0%{?is_opensuse} @@ -1807,6 +1812,11 @@ exit 0 %changelog +* Mon Jul 26 2021 chixinze - 1:12.2.8-14 +- fix CVE-2020-10753 +- fix CVE-2021-3524 +- fix CVE-2020-1760 + * Sun Jul 18 2021 chixinze - 1:12.2.8-13 - fix CVE-2020-27781 - ceph-volume-client: allow atomic updates for RADOS objects -- Gitee From 036c25f9a327d9d1bbaf7439631b252f48bd7114 Mon Sep 17 00:00:00 2001 From: chixinze Date: Fri, 6 Aug 2021 18:10:15 +0800 Subject: [PATCH 06/12] ceph.spec: fix https://gitee.com/src-openeuler/ceph/issues/I43TE9 Signed-off-by: chixinze --- ceph.spec | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ceph.spec b/ceph.spec index e61d5f9..1bcfecc 100644 --- a/ceph.spec +++ b/ceph.spec @@ -68,7 +68,7 @@ ################################################################################# Name: ceph Version: 12.2.8 -Release: 14 +Release: 15 Epoch: 2 # define _epoch_prefix macro which will expand to the empty string if epoch is @@ -781,7 +781,7 @@ Group: System/Filesystems Requires: ceph-base = %{_epoch_prefix}%{version}-%{release} Requires: policycoreutils, libselinux-utils Requires(post): ceph-base = %{_epoch_prefix}%{version}-%{release} -Requires(post): selinux-policy-base >= %{_selinux_policy_version}, policycoreutils, gawk +Requires(post): selinux-policy-minimum >= %{_selinux_policy_version}, policycoreutils, gawk Requires(postun): policycoreutils %description selinux This package contains SELinux support for Ceph MON, OSD and MDS. The package @@ -1812,6 +1812,9 @@ exit 0 %changelog +* Fri Aug 6 2021 chixinze - 1:12.2.8-15 +- fix https://gitee.com/src-openeuler/ceph/issues/I43TE9 + * Mon Jul 26 2021 chixinze - 1:12.2.8-14 - fix CVE-2020-10753 - fix CVE-2021-3524 -- Gitee From 08918b70193f9cf73205fd95828632f926148ffe Mon Sep 17 00:00:00 2001 From: zhouwenpei Date: Fri, 20 Aug 2021 12:15:47 +0800 Subject: [PATCH 07/12] fix ceph dh function unavailable --- ceph.spec | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/ceph.spec b/ceph.spec index 1bcfecc..417e3ff 100644 --- a/ceph.spec +++ b/ceph.spec @@ -68,7 +68,7 @@ ################################################################################# Name: ceph Version: 12.2.8 -Release: 15 +Release: 16 Epoch: 2 # define _epoch_prefix macro which will expand to the empty string if epoch is @@ -105,6 +105,8 @@ Patch18: 0018-CVE-2020-1760-1.patch Patch19: 0019-CVE-2020-1760-2.patch Patch20: 0020-CVE-2020-1760-3.patch +Requires: glibc >= 2.28-66 + %if 0%{?suse_version} %if 0%{?is_opensuse} ExclusiveArch: x86_64 aarch64 ppc64 ppc64le @@ -285,6 +287,7 @@ Requires: which %if 0%{?suse_version} Recommends: ntp-daemon %endif +Requires:glibc >= 2.28-66 %description base Base is the package that includes all the files shared amongst ceph servers @@ -311,6 +314,7 @@ Requires: python-requests %if 0%{?suse_version} Requires(pre): pwdutils %endif +Requires:glibc >= 2.28-66 %description -n ceph-common Common utilities to mount and interact with a ceph storage cluster. Comprised of files that are common to Ceph clients and servers. @@ -321,6 +325,7 @@ Summary: Ceph Metadata Server Daemon Group: System/Filesystems %endif Requires: ceph-base = %{_epoch_prefix}%{version}-%{release} +Requires:glibc >= 2.28-66 %description mds ceph-mds is the metadata server daemon for the Ceph distributed file system. One or more instances of ceph-mds collectively manage the file system @@ -340,6 +345,7 @@ Requires: python-flask %if 0%{?suse_version} Requires: python-Flask %endif +Requires:glibc >= 2.28-66 %description mon ceph-mon is the cluster monitor daemon for the Ceph distributed file system. One or more instances of ceph-mon form a Paxos part-time @@ -366,6 +372,7 @@ Requires: python-Werkzeug Requires: python-pyOpenSSL %endif Requires: python-pecan +Requires:glibc >= 2.28-66 %description mgr ceph-mgr enables python modules that provide services (such as the REST module derived from Calamari) and expose CLI hooks. ceph-mgr gathers @@ -378,6 +385,7 @@ Summary: Ceph fuse-based client Group: System/Filesystems %endif Requires: fuse +Requires:glibc >= 2.28-66 %description fuse FUSE based client for Ceph distributed network file system @@ -388,6 +396,7 @@ Group: System/Filesystems %endif Requires: librados2 = %{_epoch_prefix}%{version}-%{release} Requires: librbd1 = %{_epoch_prefix}%{version}-%{release} +Requires:glibc >= 2.28-66 %description -n rbd-fuse FUSE based client to map Ceph rbd images to files @@ -398,6 +407,7 @@ Group: System/Filesystems %endif Requires: ceph-common = %{_epoch_prefix}%{version}-%{release} Requires: librados2 = %{_epoch_prefix}%{version}-%{release} +Requires:glibc >= 2.28-66 %description -n rbd-mirror Daemon for mirroring RBD images between Ceph clusters, streaming changes asynchronously. @@ -409,6 +419,7 @@ Group: System/Filesystems %endif Requires: librados2 = %{_epoch_prefix}%{version}-%{release} Requires: librbd1 = %{_epoch_prefix}%{version}-%{release} +Requires:glibc >= 2.28-66 %description -n rbd-nbd NBD based client to map Ceph rbd images to local device @@ -426,6 +437,7 @@ Requires: librgw2 = %{_epoch_prefix}%{version}-%{release} %if 0%{?rhel} || 0%{?fedora} || 0%{?openEuler} Requires: mailcap %endif +Requires:glibc >= 2.28-66 %description radosgw RADOS is a distributed object store used by the Ceph distributed storage system. This package provides a REST gateway to the @@ -440,6 +452,7 @@ Group: System/Filesystems %endif Requires: ceph-base = %{_epoch_prefix}%{version} Requires: resource-agents +Requires:glibc >= 2.28-66 %description resource-agents Resource agents for monitoring and managing Ceph daemons under Open Cluster Framework (OCF) compliant resource @@ -461,6 +474,7 @@ Requires: gptfdisk %endif Requires: parted Requires: lvm2 +Requires:glibc >= 2.28-66 %description osd ceph-osd is the object storage daemon for the Ceph distributed file system. It is responsible for storing objects on a local file system @@ -474,6 +488,7 @@ Group: System/Libraries %if 0%{?rhel} || 0%{?fedora} || 0%{?openEuler} Obsoletes: ceph-libs < %{_epoch_prefix}%{version}-%{release} %endif +Requires:glibc >= 2.28-66 %description -n librados2 RADOS is a reliable, autonomic distributed object storage cluster developed as part of the Ceph distributed storage system. This is a @@ -489,6 +504,7 @@ Requires: librados2 = %{_epoch_prefix}%{version}-%{release} Obsoletes: ceph-devel < %{_epoch_prefix}%{version}-%{release} Provides: librados2-devel = %{_epoch_prefix}%{version}-%{release} Obsoletes: librados2-devel < %{_epoch_prefix}%{version}-%{release} +Requires:glibc >= 2.28-66 %description -n librados-devel This package contains libraries and headers needed to develop programs that use RADOS object store. @@ -499,6 +515,7 @@ Summary: RADOS gateway client library Group: System/Libraries %endif Requires: librados2 = %{_epoch_prefix}%{version}-%{release} +Requires:glibc >= 2.28-66 %description -n librgw2 This package provides a library implementation of the RADOS gateway (distributed object store with S3 and Swift personalities). @@ -512,6 +529,7 @@ Requires: librados-devel = %{_epoch_prefix}%{version}-%{release} Requires: librgw2 = %{_epoch_prefix}%{version}-%{release} Provides: librgw2-devel = %{_epoch_prefix}%{version}-%{release} Obsoletes: librgw2-devel < %{_epoch_prefix}%{version}-%{release} +Requires:glibc >= 2.28-66 %description -n librgw-devel This package contains libraries and headers needed to develop programs that use RADOS gateway client library. @@ -524,6 +542,7 @@ Group: Development/Languages/Python Requires: librgw2 = %{_epoch_prefix}%{version}-%{release} Requires: python-rados = %{_epoch_prefix}%{version}-%{release} Obsoletes: python-ceph < %{_epoch_prefix}%{version}-%{release} +Requires:glibc >= 2.28-66 %description -n python-rgw This package contains Python 2 libraries for interacting with Cephs RADOS gateway. @@ -535,6 +554,7 @@ Group: Development/Languages/Python %endif Requires: librgw2 = %{_epoch_prefix}%{version}-%{release} Requires: python%{python3_pkgversion}-rados = %{_epoch_prefix}%{version}-%{release} +Requires:glibc >= 2.28-66 %description -n python%{python3_pkgversion}-rgw This package contains Python 3 libraries for interacting with Cephs RADOS gateway. @@ -546,6 +566,7 @@ Group: Development/Languages/Python %endif Requires: librados2 = %{_epoch_prefix}%{version}-%{release} Obsoletes: python-ceph < %{_epoch_prefix}%{version}-%{release} +Requires:glibc >= 2.28-66 %description -n python-rados This package contains Python 2 libraries for interacting with Cephs RADOS object store. @@ -557,6 +578,7 @@ Group: Development/Languages/Python %endif Requires: python%{python3_pkgversion} Requires: librados2 = %{_epoch_prefix}%{version}-%{release} +Requires:glibc >= 2.28-66 %description -n python%{python3_pkgversion}-rados This package contains Python 3 libraries for interacting with Cephs RADOS object store. @@ -567,6 +589,7 @@ Summary: RADOS striping interface Group: System/Libraries %endif Requires: librados2 = %{_epoch_prefix}%{version}-%{release} +Requires:glibc >= 2.28-66 %description -n libradosstriper1 Striping interface built on top of the rados library, allowing to stripe bigger objects onto several standard rados objects using @@ -582,6 +605,7 @@ Requires: librados-devel = %{_epoch_prefix}%{version}-%{release} Obsoletes: ceph-devel < %{_epoch_prefix}%{version}-%{release} Provides: libradosstriper1-devel = %{_epoch_prefix}%{version}-%{release} Obsoletes: libradosstriper1-devel < %{_epoch_prefix}%{version}-%{release} +Requires:glibc >= 2.28-66 %description -n libradosstriper-devel This package contains libraries and headers needed to develop programs that use RADOS striping interface. @@ -598,6 +622,7 @@ Requires(post): coreutils %if 0%{?rhel} || 0%{?fedora} || 0%{?openEuler} Obsoletes: ceph-libs < %{_epoch_prefix}%{version}-%{release} %endif +Requires:glibc >= 2.28-66 %description -n librbd1 RBD is a block device striped across multiple distributed objects in RADOS, a reliable, autonomic distributed object storage cluster @@ -614,6 +639,7 @@ Requires: librados-devel = %{_epoch_prefix}%{version}-%{release} Obsoletes: ceph-devel < %{_epoch_prefix}%{version}-%{release} Provides: librbd1-devel = %{_epoch_prefix}%{version}-%{release} Obsoletes: librbd1-devel < %{_epoch_prefix}%{version}-%{release} +Requires:glibc >= 2.28-66 %description -n librbd-devel This package contains libraries and headers needed to develop programs that use RADOS block device. @@ -626,6 +652,7 @@ Group: Development/Languages/Python Requires: librbd1 = %{_epoch_prefix}%{version}-%{release} Requires: python-rados = %{_epoch_prefix}%{version}-%{release} Obsoletes: python-ceph < %{_epoch_prefix}%{version}-%{release} +Requires:glibc >= 2.28-66 %description -n python-rbd This package contains Python 2 libraries for interacting with Cephs RADOS block device. @@ -637,6 +664,7 @@ Group: Development/Languages/Python %endif Requires: librbd1 = %{_epoch_prefix}%{version}-%{release} Requires: python%{python3_pkgversion}-rados = %{_epoch_prefix}%{version}-%{release} +Requires:glibc >= 2.28-66 %description -n python%{python3_pkgversion}-rbd This package contains Python 3 libraries for interacting with Cephs RADOS block device. @@ -651,6 +679,7 @@ Obsoletes: libcephfs1 Obsoletes: ceph-libs < %{_epoch_prefix}%{version}-%{release} Obsoletes: ceph-libcephfs %endif +Requires:glibc >= 2.28-66 %description -n libcephfs2 Ceph is a distributed network file system designed to provide excellent performance, reliability, and scalability. This is a shared library @@ -667,6 +696,7 @@ Requires: librados-devel = %{_epoch_prefix}%{version}-%{release} Obsoletes: ceph-devel < %{_epoch_prefix}%{version}-%{release} Provides: libcephfs2-devel = %{_epoch_prefix}%{version}-%{release} Obsoletes: libcephfs2-devel < %{_epoch_prefix}%{version}-%{release} +Requires:glibc >= 2.28-66 %description -n libcephfs-devel This package contains libraries and headers needed to develop programs that use Cephs distributed file system. @@ -681,6 +711,7 @@ Requires: libcephfs2 = %{_epoch_prefix}%{version}-%{release} Recommends: python-rados = %{_epoch_prefix}%{version}-%{release} %endif Obsoletes: python-ceph < %{_epoch_prefix}%{version}-%{release} +Requires:glibc >= 2.28-66 %description -n python-cephfs This package contains Python 2 libraries for interacting with Cephs distributed file system. @@ -692,6 +723,7 @@ Group: Development/Languages/Python %endif Requires: libcephfs2 = %{_epoch_prefix}%{version}-%{release} Requires: python%{python3_pkgversion}-rados = %{_epoch_prefix}%{version}-%{release} +Requires:glibc >= 2.28-66 %description -n python%{python3_pkgversion}-cephfs This package contains Python 3 libraries for interacting with Cephs distributed file system. @@ -701,6 +733,7 @@ Summary: Python 3 utility libraries for Ceph CLI %if 0%{?suse_version} Group: Development/Languages/Python %endif +Requires:glibc >= 2.28-66 %description -n python%{python3_pkgversion}-ceph-argparse This package contains types and routines for Python 3 used by the Ceph CLI as well as the RESTful interface. These have to do with querying the daemons for @@ -717,6 +750,7 @@ Requires: ceph-common = %{_epoch_prefix}%{version}-%{release} Requires: xmlstarlet Requires: jq Requires: socat +Requires:glibc >= 2.28-66 %description -n ceph-test This package contains Ceph benchmarks and test tools. %endif @@ -730,6 +764,7 @@ Group: System/Libraries %endif Requires: java Requires: libcephfs2 = %{_epoch_prefix}%{version}-%{release} +Requires:glibc >= 2.28-66 %description -n libcephfs_jni1 This package contains the Java Native Interface library for CephFS Java bindings. @@ -744,6 +779,7 @@ Requires: libcephfs_jni1 = %{_epoch_prefix}%{version}-%{release} Obsoletes: ceph-devel < %{_epoch_prefix}%{version}-%{release} Provides: libcephfs_jni1-devel = %{_epoch_prefix}%{version}-%{release} Obsoletes: libcephfs_jni1-devel < %{_epoch_prefix}%{version}-%{release} +Requires:glibc >= 2.28-66 %description -n libcephfs_jni-devel This package contains the development files for CephFS Java Native Interface library. @@ -757,6 +793,7 @@ Requires: java Requires: libcephfs_jni1 = %{_epoch_prefix}%{version}-%{release} Requires: junit BuildRequires: junit +Requires:glibc >= 2.28-66 %description -n cephfs-java This package contains the Java libraries for the Ceph File System. @@ -767,6 +804,7 @@ This package contains the Java libraries for the Ceph File System. Summary: RADOS object class development kit Group: Development/Libraries Requires: librados2-devel = %{_epoch_prefix}%{version}-%{release} +Requires:glibc >= 2.28-66 %description -n rados-objclass-devel This package contains libraries and headers needed to develop RADOS object class plugins. @@ -783,6 +821,7 @@ Requires: policycoreutils, libselinux-utils Requires(post): ceph-base = %{_epoch_prefix}%{version}-%{release} Requires(post): selinux-policy-minimum >= %{_selinux_policy_version}, policycoreutils, gawk Requires(postun): policycoreutils +Requires:glibc >= 2.28-66 %description selinux This package contains SELinux support for Ceph MON, OSD and MDS. The package also performs file-system relabelling which can take a long time on heavily @@ -801,6 +840,7 @@ Requires: python-rbd = %{_epoch_prefix}%{version}-%{release} Requires: python-cephfs = %{_epoch_prefix}%{version}-%{release} Requires: python-rgw = %{_epoch_prefix}%{version}-%{release} Provides: python-ceph +Requires:glibc >= 2.28-66 %description -n python-ceph-compat This is a compatibility package to accommodate python-ceph split into python-rados, python-rbd, python-rgw and python-cephfs. Packages still @@ -1812,6 +1852,9 @@ exit 0 %changelog +* Fri Aug 20 2021 zhouwenpei - 1:12.2.8-16 +- fix ceph dh function unavailable + * Fri Aug 6 2021 chixinze - 1:12.2.8-15 - fix https://gitee.com/src-openeuler/ceph/issues/I43TE9 -- Gitee From 323c8c354c9585a33903bc6fdab6d28c983887e9 Mon Sep 17 00:00:00 2001 From: liqiang Date: Wed, 29 Dec 2021 11:33:17 +0800 Subject: [PATCH 08/12] fix performance issue of pick_a_shard --- ...-mempool-Add-test-for-mempool-shards.patch | 39 +++++++++++++++++++ ...pool-Modify-shard-selection-function.patch | 28 +++++++++++++ ...nly-fail-tests-if-sharding-is-very-b.patch | 27 +++++++++++++ ceph.spec | 9 ++++- 4 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 0021-common-mempool-Add-test-for-mempool-shards.patch create mode 100644 0022-common-mempool-Modify-shard-selection-function.patch create mode 100644 0023-common-mempool-only-fail-tests-if-sharding-is-very-b.patch diff --git a/0021-common-mempool-Add-test-for-mempool-shards.patch b/0021-common-mempool-Add-test-for-mempool-shards.patch new file mode 100644 index 0000000..456e265 --- /dev/null +++ b/0021-common-mempool-Add-test-for-mempool-shards.patch @@ -0,0 +1,39 @@ +From e4e07de8f36d0d44b341d5784a8bf56192201b95 Mon Sep 17 00:00:00 2001 +From: Adam Kupczyk +Date: Mon, 25 Jan 2021 11:33:28 +0100 +Subject: [PATCH] common/mempool: Add test for mempool shards + +Add test that checks quality of mempool sharing. +It refuses to accept cases when variance is too large. + +Signed-off-by: Adam Kupczyk +--- + src/include/mempool.h | 9 +++++++-- + 1 files changed, 7 insertions(+), 2 deletions(-) + +diff --git a/src/include/mempool.h b/src/include/mempool.h +index 2247cb15bc0..a18f6a502da 100644 +--- a/src/include/mempool.h ++++ b/src/include/mempool.h +@@ -255,11 +255,16 @@ public: + + void adjust_count(ssize_t items, ssize_t bytes); + +- shard_t* pick_a_shard() { ++ static size_t pick_a_shard_int() { + // Dirt cheap, see: +- // http://fossies.org/dox/glibc-2.24/pthread__self_8c_source.html ++ // https://fossies.org/dox/glibc-2.32/pthread__self_8c_source.html + size_t me = (size_t)pthread_self(); + size_t i = (me >> 3) & ((1 << num_shard_bits) - 1); ++ return i; ++ } ++ ++ shard_t* pick_a_shard() { ++ size_t i = pick_a_shard_int(); + return &shard[i]; + } + +-- +2.23.0.windows.1 + diff --git a/0022-common-mempool-Modify-shard-selection-function.patch b/0022-common-mempool-Modify-shard-selection-function.patch new file mode 100644 index 0000000..c207945 --- /dev/null +++ b/0022-common-mempool-Modify-shard-selection-function.patch @@ -0,0 +1,28 @@ +From fccbdc0905e3868666fbb10803bac6b73f687cb1 Mon Sep 17 00:00:00 2001 +From: Adam Kupczyk +Date: Mon, 25 Jan 2021 11:45:06 +0100 +Subject: [PATCH] common/mempool: Modify shard selection function + +Modify shard selection function, so no longer all threads use the same shard 0. + +Signed-off-by: Adam Kupczyk +--- + src/include/mempool.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/include/mempool.h b/src/include/mempool.h +index a18f6a502da..c03aa175cfa 100644 +--- a/src/include/mempool.h ++++ b/src/include/mempool.h +@@ -259,7 +259,7 @@ public: + // Dirt cheap, see: + // https://fossies.org/dox/glibc-2.32/pthread__self_8c_source.html + size_t me = (size_t)pthread_self(); +- size_t i = (me >> 3) & ((1 << num_shard_bits) - 1); ++ size_t i = (me >> 12) & ((1 << num_shard_bits) - 1); + return i; + } + +-- +2.23.0.windows.1 + diff --git a/0023-common-mempool-only-fail-tests-if-sharding-is-very-b.patch b/0023-common-mempool-only-fail-tests-if-sharding-is-very-b.patch new file mode 100644 index 0000000..4284e03 --- /dev/null +++ b/0023-common-mempool-only-fail-tests-if-sharding-is-very-b.patch @@ -0,0 +1,27 @@ +From db79769d6d557acc021a434ff285db2d69458d0a Mon Sep 17 00:00:00 2001 +From: singuliere +Date: Wed, 17 Mar 2021 07:35:04 +0100 +Subject: [PATCH] common/mempool: only fail tests if sharding is very bad + +Fixes: https://tracker.ceph.com/issues/49781 +Signed-off-by: singuliere +--- + src/include/mempool.h | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/src/include/mempool.h b/src/include/mempool.h +index c03aa175cfa..fe84f3b8f09 100644 +--- a/src/include/mempool.h ++++ b/src/include/mempool.h +@@ -259,7 +259,7 @@ public: + // Dirt cheap, see: + // https://fossies.org/dox/glibc-2.32/pthread__self_8c_source.html + size_t me = (size_t)pthread_self(); +- size_t i = (me >> 12) & ((1 << num_shard_bits) - 1); ++ size_t i = (me >> CEPH_PAGE_SHIFT) & ((1 << num_shard_bits) - 1); + return i; + } + +-- +2.23.0.windows.1 + diff --git a/ceph.spec b/ceph.spec index 417e3ff..ad41d01 100644 --- a/ceph.spec +++ b/ceph.spec @@ -68,7 +68,7 @@ ################################################################################# Name: ceph Version: 12.2.8 -Release: 16 +Release: 17 Epoch: 2 # define _epoch_prefix macro which will expand to the empty string if epoch is @@ -104,6 +104,9 @@ Patch17: 0017-CVE-2021-3524-1.patch Patch18: 0018-CVE-2020-1760-1.patch Patch19: 0019-CVE-2020-1760-2.patch Patch20: 0020-CVE-2020-1760-3.patch +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 Requires: glibc >= 2.28-66 @@ -1852,6 +1855,10 @@ exit 0 %changelog +* Sat Jan 29 2022 liuqinfei - 1:12.2.8-17 +- Synchronize the performance optimization of the pick_a_shard +- function in the upstream community. + * Fri Aug 20 2021 zhouwenpei - 1:12.2.8-16 - fix ceph dh function unavailable -- Gitee From d2d7be7564d6296abb38b39a25baf37ab325ee47 Mon Sep 17 00:00:00 2001 From: zhangshaoning Date: Thu, 4 Mar 2021 12:34:36 +0800 Subject: [PATCH 09/12] correct ceph-mgr requires python2-jinja2 and python2-werkzeug --- ceph.spec | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ceph.spec b/ceph.spec index ad41d01..f2b4178 100644 --- a/ceph.spec +++ b/ceph.spec @@ -68,7 +68,7 @@ ################################################################################# Name: ceph Version: 12.2.8 -Release: 17 +Release: 18 Epoch: 2 # define _epoch_prefix macro which will expand to the empty string if epoch is @@ -364,8 +364,8 @@ Requires: ceph-base = %{_epoch_prefix}%{version}-%{release} Requires: python-six %if 0%{?fedora} || 0%{?rhel} || 0%{?openEuler} Requires: python-cherrypy -Requires: python-jinja2 -Requires: python-werkzeug +Requires: python2-jinja2 +Requires: python2-werkzeug Requires: pyOpenSSL %endif %if 0%{?suse_version} @@ -1855,6 +1855,9 @@ exit 0 %changelog +* Sat Jan 29 2022 liuqinfei - 1:12.2.8-18 +- correct ceph-mgr requires python2-jinja2 and python2-werkzeug + * Sat Jan 29 2022 liuqinfei - 1:12.2.8-17 - Synchronize the performance optimization of the pick_a_shard - function in the upstream community. -- Gitee From 32feac0e33c3572e57addce835adf39a7de107ac Mon Sep 17 00:00:00 2001 From: liuqinfei Date: Sat, 29 Jan 2022 16:39:46 +0800 Subject: [PATCH 10/12] sync release version for openEuler-20.03-LTS* branches --- ceph.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ceph.spec b/ceph.spec index f2b4178..b0a6420 100644 --- a/ceph.spec +++ b/ceph.spec @@ -68,7 +68,7 @@ ################################################################################# Name: ceph Version: 12.2.8 -Release: 18 +Release: 19 Epoch: 2 # define _epoch_prefix macro which will expand to the empty string if epoch is @@ -1855,6 +1855,9 @@ exit 0 %changelog +* Sat Jan 29 2022 liuqinfei - 1:12.2.8-19 +- sync release version for openEuler-20.03-LTS* branches + * Sat Jan 29 2022 liuqinfei - 1:12.2.8-18 - correct ceph-mgr requires python2-jinja2 and python2-werkzeug -- Gitee From 7b5ca83dbf1fad609f03de79f5be26eaaaa15603 Mon Sep 17 00:00:00 2001 From: luo rixin Date: Sat, 29 Jan 2022 10:53:01 +0800 Subject: [PATCH 11/12] fix CVE-2021-3979 Signed-off-by: luo rixin (cherry picked from commit a5245b5232fd486a1656181a0cde96933ededf33) --- 0024-CVE-2021-3979.patch | 297 +++++++++++++++++++++++++++++++++++++++ ceph.spec | 6 +- 2 files changed, 302 insertions(+), 1 deletion(-) create mode 100644 0024-CVE-2021-3979.patch diff --git a/0024-CVE-2021-3979.patch b/0024-CVE-2021-3979.patch new file mode 100644 index 0000000..7e77625 --- /dev/null +++ b/0024-CVE-2021-3979.patch @@ -0,0 +1,297 @@ +From e86c21ad64065fd660515b78cade2fadeaf7b1f4 Mon Sep 17 00:00:00 2001 +From: Guillaume Abrioux +Date: Tue, 25 Jan 2022 10:25:53 +0100 +Subject: [PATCH 1/3] ceph-volume: honour osd_dmcrypt_key_size option + +ceph-volume doesn't honour osd_dmcrypt_key_size. +It means the default size is always applied. + +It also changes the default value in `get_key_size_from_conf()` + +From cryptsetup manpage: + +> For XTS mode you can optionally set a key size of 512 bits with the -s option. + +Using more than 512bits will end up with the following error message: + +``` +Key size in XTS mode must be 256 or 512 bits. +``` + +Fixes: https://tracker.ceph.com/issues/54006 + +Signed-off-by: Guillaume Abrioux +--- + .../ceph_volume/tests/util/test_encryption.py | 45 +++++++++++++++++++ + .../ceph_volume/util/encryption.py | 35 ++++++++++++--- + 2 files changed, 73 insertions(+), 7 deletions(-) + +diff --git a/src/ceph-volume/ceph_volume/tests/util/test_encryption.py b/src/ceph-volume/ceph_volume/tests/util/test_encryption.py +index 8cca42689b4..c02646f564b 100644 +--- a/src/ceph-volume/ceph_volume/tests/util/test_encryption.py ++++ b/src/ceph-volume/ceph_volume/tests/util/test_encryption.py +@@ -1,6 +1,33 @@ ++import os ++import base64 + from ceph_volume.util import encryption + + ++class TestGetKeySize(object): ++ def test_get_size_from_b64key_less_than_512bits(self): ++ assert encryption.get_key_size_from_b64_key(base64.b64encode(os.urandom(int(128 / 8)))) == 128 ++ ++ def test_get_size_from_b64key_greater_than_512bits(self): ++ assert encryption.get_key_size_from_b64_key(base64.b64encode(os.urandom(int(1024 / 8)))) == 512 ++ ++ def test_get_size_from_conf_default(self, conf_ceph_stub): ++ conf_ceph_stub(''' ++ [global] ++ fsid=asdf ++ ''') ++ assert encryption.get_key_size_from_conf() == '512' ++ ++ def test_get_size_from_conf_custom(self, conf_ceph_stub): ++ conf_ceph_stub(''' ++ [global] ++ fsid=asdf ++ [osd] ++ osd_dmcrypt_key_size=256 ++ ''') ++ assert encryption.get_key_size_from_conf() == '256' ++ ++ ++ + class TestStatus(object): + + def test_skips_unuseful_lines(self, stub_call): +@@ -33,3 +60,21 @@ class TestDmcryptClose(object): + file_name = '/path/does/not/exist' + encryption.dmcrypt_close(file_name) + assert fake_run.calls == [] ++ ++ ++class TestDmcryptKey(object): ++ ++ def test_dmcrypt_with_default_size(self, conf_ceph_stub): ++ conf_ceph_stub('[global]\nfsid=asdf-lkjh') ++ result = encryption.create_dmcrypt_key() ++ assert len(result) == 88 ++ ++ def test_dmcrypt_with_custom_size(self, conf_ceph_stub): ++ conf_ceph_stub(''' ++ [global] ++ fsid=asdf ++ [osd] ++ osd_dmcrypt_size=8 ++ ''') ++ result = encryption.create_dmcrypt_key() ++ assert len(result) == 172 +diff --git a/src/ceph-volume/ceph_volume/util/encryption.py b/src/ceph-volume/ceph_volume/util/encryption.py +index cc594a07e83..640074245dd 100644 +--- a/src/ceph-volume/ceph_volume/util/encryption.py ++++ b/src/ceph-volume/ceph_volume/util/encryption.py +@@ -8,21 +8,38 @@ from .disk import lsblk, device_family, get_part_entry_type + + logger = logging.getLogger(__name__) + ++def get_key_size_from_conf(): ++ """ ++ Return the osd dmcrypt key size from config file. ++ Default is 512. ++ """ ++ key_size = conf.ceph.get_safe( ++ 'osd', ++ 'osd_dmcrypt_key_size', ++ default='512') ++ ++ return key_size ++ ++def get_key_size_from_b64_key(key): ++ """ ++ Return the size in bits of a given base64 encoded key. ++ """ ++ key_size = len(base64.b64decode(key)) * 8 ++ if key_size > 512: ++ key_size = 512 ++ return key_size + + def create_dmcrypt_key(): + """ + Create the secret dm-crypt key used to decrypt a device. + """ + # get the customizable dmcrypt key size (in bits) from ceph.conf fallback +- # to the default of 1024 +- dmcrypt_key_size = conf.ceph.get_safe( +- 'osd', +- 'osd_dmcrypt_key_size', +- default=1024, +- ) ++ # to the default of 512 ++ dmcrypt_key_size = int(get_key_size_from_conf()) ++ + # The size of the key is defined in bits, so we must transform that + # value to bytes (dividing by 8) because we read in bytes, not bits +- random_string = os.urandom(dmcrypt_key_size / 8) ++ random_string = os.urandom(int(dmcrypt_key_size / 8)) + key = base64.b64encode(random_string).decode('utf-8') + return key + +@@ -37,6 +54,8 @@ def luks_format(key, device): + command = [ + 'cryptsetup', + '--batch-mode', # do not prompt ++ '--key-size', ++ str(get_key_size_from_b64_key(key)), + '--key-file', # misnomer, should be key + '-', # because we indicate stdin for the key here + 'luksFormat', +@@ -81,6 +100,8 @@ def luks_open(key, device, mapping): + """ + command = [ + 'cryptsetup', ++ '--key-size', ++ str(get_key_size_from_b64_key(key)), + '--key-file', + '-', + 'luksOpen', +-- +2.20.1.windows.1 + + +From 7e02488e2694f83e97fbd5046ae92c29610570a6 Mon Sep 17 00:00:00 2001 +From: Guillaume Abrioux +Date: Tue, 25 Jan 2022 15:22:28 +0100 +Subject: [PATCH 2/3] ceph-volume: fix `TestDmcryptKey()` tests + +This commits fixes two things: + +- the override passed in `conf_ceph_stub()` which is incorrect. +- the assert itself. + +Given it was still using the default value (1024) in the second test +`test_dmcrypt_with_custom_size()`, the assert was expecting the length to be 172 too. + +Signed-off-by: Guillaume Abrioux +--- + src/ceph-volume/ceph_volume/tests/util/test_encryption.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/ceph-volume/ceph_volume/tests/util/test_encryption.py b/src/ceph-volume/ceph_volume/tests/util/test_encryption.py +index c02646f564b..0eb95187539 100644 +--- a/src/ceph-volume/ceph_volume/tests/util/test_encryption.py ++++ b/src/ceph-volume/ceph_volume/tests/util/test_encryption.py +@@ -74,7 +74,7 @@ class TestDmcryptKey(object): + [global] + fsid=asdf + [osd] +- osd_dmcrypt_size=8 ++ osd_dmcrypt_key_size=8 + ''') + result = encryption.create_dmcrypt_key() +- assert len(result) == 172 ++ assert len(result) == 4 +-- +2.20.1.windows.1 + + +From 0765b615ba226cb46ce3b09bc4bf80dab8b1d09b Mon Sep 17 00:00:00 2001 +From: Guillaume Abrioux +Date: Tue, 25 Jan 2022 15:52:07 +0100 +Subject: [PATCH 3/3] ceph-volume: add unit tests in util/encryption.py + +this adds some unit tests in order to cover `luks_format()` and `luks_open()` +in `util/encryption.py`. + +Signed-off-by: Guillaume Abrioux +--- + .../ceph_volume/tests/util/test_encryption.py | 70 +++++++++++++++++++ + 1 file changed, 70 insertions(+) + +diff --git a/src/ceph-volume/ceph_volume/tests/util/test_encryption.py b/src/ceph-volume/ceph_volume/tests/util/test_encryption.py +index 0eb95187539..e7926ffe96d 100644 +--- a/src/ceph-volume/ceph_volume/tests/util/test_encryption.py ++++ b/src/ceph-volume/ceph_volume/tests/util/test_encryption.py +@@ -1,5 +1,6 @@ + import os + import base64 ++from mock.mock import patch + from ceph_volume.util import encryption + + +@@ -78,3 +79,72 @@ class TestDmcryptKey(object): + ''') + result = encryption.create_dmcrypt_key() + assert len(result) == 4 ++ ++class TestLuksFormat(object): ++ @patch('ceph_volume.util.encryption.process.call') ++ def test_luks_format_command_with_default_size(self, m_call, conf_ceph_stub): ++ conf_ceph_stub('[global]\nfsid=abcd') ++ expected = [ ++ 'cryptsetup', ++ '--batch-mode', ++ '--key-size', ++ '512', ++ '--key-file', ++ '-', ++ 'luksFormat', ++ '/dev/foo' ++ ] ++ encryption.luks_format('4YJycMQmkaXi+nRN07HsTrk8LR7kzKDXe745t7atdAuoJ2OiwuZ06aD+7Z8MifKGoBulTNlu9GsYER0dFJWCSw==', '/dev/foo') ++ assert m_call.call_args[0][0] == expected ++ ++ @patch('ceph_volume.util.encryption.process.call') ++ def test_luks_format_command_with_custom_size(self, m_call, conf_ceph_stub): ++ conf_ceph_stub('[global]\nfsid=abcd\n[osd]\nosd_dmcrypt_key_size=256') ++ expected = [ ++ 'cryptsetup', ++ '--batch-mode', ++ '--key-size', ++ '256', ++ '--key-file', ++ '-', ++ 'luksFormat', ++ '/dev/foo' ++ ] ++ encryption.luks_format('F2bk3pbcTX0zzuEdwIMW9lNwcRFg0L48G2JM81yICUI=', '/dev/foo') ++ assert m_call.call_args[0][0] == expected ++ ++ ++class TestLuksOpen(object): ++ @patch('ceph_volume.util.encryption.process.call') ++ def test_luks_open_command_with_default_size(self, m_call, conf_ceph_stub): ++ conf_ceph_stub('[global]\nfsid=abcd') ++ expected = [ ++ 'cryptsetup', ++ '--key-size', ++ '256', ++ '--key-file', ++ '-', ++ '--allow-discards', ++ 'luksOpen', ++ '/dev/foo', ++ '/dev/bar' ++ ] ++ encryption.luks_open('F2bk3pbcTX0zzuEdwIMW9lNwcRFg0L48G2JM81yICUI=', '/dev/foo', '/dev/bar') ++ assert m_call.call_args[0][0] == expected ++ ++ @patch('ceph_volume.util.encryption.process.call') ++ def test_luks_open_command_with_custom_size(self, m_call, conf_ceph_stub): ++ conf_ceph_stub('[global]\nfsid=abcd\n[osd]\nosd_dmcrypt_key_size=128') ++ expected = [ ++ 'cryptsetup', ++ '--key-size', ++ '256', ++ '--key-file', ++ '-', ++ '--allow-discards', ++ 'luksOpen', ++ '/dev/foo', ++ '/dev/bar' ++ ] ++ encryption.luks_open('F2bk3pbcTX0zzuEdwIMW9lNwcRFg0L48G2JM81yICUI=', '/dev/foo', '/dev/bar') ++ assert m_call.call_args[0][0] == expected +\ No newline at end of file +-- +2.20.1.windows.1 + diff --git a/ceph.spec b/ceph.spec index b0a6420..cf13458 100644 --- a/ceph.spec +++ b/ceph.spec @@ -68,7 +68,7 @@ ################################################################################# Name: ceph Version: 12.2.8 -Release: 19 +Release: 20 Epoch: 2 # define _epoch_prefix macro which will expand to the empty string if epoch is @@ -107,6 +107,7 @@ Patch20: 0020-CVE-2020-1760-3.patch 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 Requires: glibc >= 2.28-66 @@ -1855,6 +1856,9 @@ exit 0 %changelog +* Sun Jan 29 2022 luo rixin - 1:12.2.8-20 +- fix CVE-2021-3979 + * Sat Jan 29 2022 liuqinfei - 1:12.2.8-19 - sync release version for openEuler-20.03-LTS* branches -- Gitee From 2e8c9dd58c1f65b2fc9a291597a21de3993ee9d5 Mon Sep 17 00:00:00 2001 From: wangzengliang Date: Thu, 5 May 2022 14:46:48 +0800 Subject: [PATCH 12/12] fix CVE-2021-20288 --- 0025-CVE-2021-20288.patch | 1526 +++++++++++++++++++++++++++++++++++++ ceph.spec | 6 +- 2 files changed, 1531 insertions(+), 1 deletion(-) create mode 100644 0025-CVE-2021-20288.patch diff --git a/0025-CVE-2021-20288.patch b/0025-CVE-2021-20288.patch new file mode 100644 index 0000000..1e3856a --- /dev/null +++ b/0025-CVE-2021-20288.patch @@ -0,0 +1,1526 @@ +diff --git a/doc/rados/operations/health-checks.rst b/doc/rados/operations/health-checks.rst +index c1e22004..4def3fdf 100644 +--- a/doc/rados/operations/health-checks.rst ++++ b/doc/rados/operations/health-checks.rst +@@ -21,6 +21,67 @@ that are defined by ceph-mgr python modules. + Definitions + =========== + ++Monitor ++------- ++ ++AUTH_INSECURE_GLOBAL_ID_RECLAIM ++_______________________________ ++ ++One or more clients or daemons are connected to the cluster that are ++not securely reclaiming their global_id (a unique number identifying ++each entity in the cluster) when reconnecting to a monitor. The ++client is being permitted to connect anyway because the ++``auth_allow_insecure_global_id_reclaim`` option is set to true (which may ++be necessary until all ceph clients have been upgraded), and the ++``auth_expose_insecure_global_id_reclaim`` option set to ``true`` (which ++allows monitors to detect clients with insecure reclaim early by forcing them to ++reconnect right after they first authenticate). ++ ++You can identify which client(s) are using unpatched ceph client code with:: ++ ++ ceph health detail ++ ++Clients global_id reclaim rehavior can also seen in the ++``global_id_status`` field in the dump of clients connected to an ++individual monitor (``reclaim_insecure`` means the client is ++unpatched and is contributing to this health alert):: ++ ++ ceph daemon mon. sessions ++ ++We strongly recommend that all clients in the system are upgraded to a ++newer version of Ceph that correctly reclaims global_id values. Once ++all clients have been updated, you can stop allowing insecure reconnections ++by setting the following option in the ``[mon]`` section of ``ceph.conf``:: ++ ++ auth_allow_insecure_global_id_reclaim = false ++ ++Although we do NOT recommend doing so, you can also disable this warning indefinitely ++by setting the following option in the ``[mon]`` section of ``ceph.conf``:: ++ ++ mon_warn_on_insecure_global_id_reclaim = false ++ ++AUTH_INSECURE_GLOBAL_ID_RECLAIM_ALLOWED ++_______________________________________ ++ ++Ceph is currently configured to allow clients to reconnect to monitors using ++an insecure process to reclaim their previous global_id because the setting ++``auth_allow_insecure_global_id_reclaim`` is set to ``true``. It may be necessary to ++leave this setting enabled while existing Ceph clients are upgraded to newer ++versions of Ceph that correctly and securely reclaim their global_id. ++ ++If the ``AUTH_INSECURE_GLOBAL_ID_RECLAIM`` health alert has not also been raised and ++the ``auth_expose_insecure_global_id_reclaim`` setting has not been disabled (it is ++on by default), then there are currently no clients connected that need to be ++upgraded, and it is safe to disallow insecure global_id reclaim by setting the ++following option in the ``[mon]`` section of ``ceph.conf``:: ++ ++ auth_allow_insecure_global_id_reclaim = false ++ ++Although we do NOT recommend doing so, you can also disable this warning indefinitely ++by setting the following option in the ``[mon]`` section of ``ceph.conf``:: ++ ++ mon_warn_on_insecure_global_id_reclaim_allowed = false ++ + + OSDs + ---- +diff --git a/qa/standalone/ceph-helpers.sh b/qa/standalone/ceph-helpers.sh +index f12f0698..ac2ac180 100755 +--- a/qa/standalone/ceph-helpers.sh ++++ b/qa/standalone/ceph-helpers.sh +@@ -461,6 +461,7 @@ function run_mon() { + --pid-file=$dir/\$name.pid \ + --mon-allow-pool-delete \ + --mon-osd-backfillfull-ratio .99 \ ++ --mon-warn-on-insecure-global-id-reclaim-allowed=false \ + "$@" || return 1 + + cat > $dir/ceph.conf <entity_name.get_type() && !this->global_id && ++ global_id_status == global_id_status_t::NONE); ++ ++ ldout(cct, 10) << __func__ << " entity_name=" << entity_name ++ << " global_id=" << global_id << " is_new_global_id=" ++ << is_new_global_id << dendl; ++ this->entity_name = entity_name; ++ this->global_id = global_id; ++ ++ return do_start_session(is_new_global_id, result, caps); ++} ++ + AuthServiceHandler *get_auth_service_handler(int type, CephContext *cct, KeyServer *ks) + { + switch (type) { +diff --git a/src/auth/AuthServiceHandler.h b/src/auth/AuthServiceHandler.h +index 4d8a6493..ae40adb7 100644 +--- a/src/auth/AuthServiceHandler.h ++++ b/src/auth/AuthServiceHandler.h +@@ -24,21 +24,54 @@ class CephContext; + class KeyServer; + struct AuthCapsInfo; + ++enum class global_id_status_t { ++ NONE, ++ // fresh client (global_id == 0); waiting for CephXAuthenticate ++ NEW_PENDING, ++ // connected client; new enough to correctly reclaim global_id ++ NEW_OK, ++ // connected client; unknown whether it can reclaim global_id correctly ++ NEW_NOT_EXPOSED, ++ // reconnecting client (global_id != 0); waiting for CephXAuthenticate ++ RECLAIM_PENDING, ++ // reconnected client; correctly reclaimed global_id ++ RECLAIM_OK, ++ // reconnected client; did not properly prove prior global_id ownership ++ RECLAIM_INSECURE ++}; ++ ++std::ostream& operator<<(std::ostream& os, ++ global_id_status_t global_id_status); ++ + struct AuthServiceHandler { + protected: + CephContext *cct; +-public: + EntityName entity_name; +- uint64_t global_id; ++ uint64_t global_id = 0; ++ global_id_status_t global_id_status = global_id_status_t::NONE; + +- explicit AuthServiceHandler(CephContext *cct_) : cct(cct_), global_id(0) {} ++public: ++ explicit AuthServiceHandler(CephContext *cct_) : cct(cct_) {} + + virtual ~AuthServiceHandler() { } + +- virtual int start_session(EntityName& name, bufferlist::iterator& indata, bufferlist& result, AuthCapsInfo& caps) = 0; +- virtual int handle_request(bufferlist::iterator& indata, bufferlist& result, uint64_t& global_id, AuthCapsInfo& caps, uint64_t *auid = NULL) = 0; ++ int start_session(const EntityName& name, ++ uint64_t global_id, ++ bool is_new_global_id, ++ bufferlist& result, ++ AuthCapsInfo& caps); ++ virtual int handle_request(bufferlist::iterator& indata, ++ bufferlist& result, ++ AuthCapsInfo& caps, ++ uint64_t *auid = NULL) = 0; ++ const EntityName& get_entity_name() { return entity_name; } ++ uint64_t get_global_id() { return global_id; } ++ global_id_status_t get_global_id_status() { return global_id_status; } + +- EntityName& get_entity_name() { return entity_name; } ++private: ++ virtual int do_start_session(bool is_new_global_id, ++ bufferlist& result, ++ AuthCapsInfo& caps) = 0; + }; + + extern AuthServiceHandler *get_auth_service_handler(int type, CephContext *cct, KeyServer *ks); +diff --git a/src/auth/AuthSessionHandler.cc b/src/auth/AuthSessionHandler.cc +index ab46b60c..76a499c2 100644 +--- a/src/auth/AuthSessionHandler.cc ++++ b/src/auth/AuthSessionHandler.cc +@@ -30,6 +30,10 @@ AuthSessionHandler *get_auth_session_handler(CephContext *cct, int protocol, Cry + + switch (protocol) { + case CEPH_AUTH_CEPHX: ++ ++ if (key.get_type() == CEPH_CRYPTO_NONE) { ++ return nullptr; ++ } + return new CephxSessionHandler(cct, key, features); + case CEPH_AUTH_NONE: + return new AuthNoneSessionHandler(cct, key); +diff --git a/src/auth/Crypto.cc b/src/auth/Crypto.cc +index 0186b7b2..150052bf 100644 +--- a/src/auth/Crypto.cc ++++ b/src/auth/Crypto.cc +@@ -12,6 +12,9 @@ + */ + + #include ++#include ++#include ++ + #include "Crypto.h" + #ifdef USE_CRYPTOPP + # include +@@ -37,7 +40,7 @@ + + int get_random_bytes(char *buf, int len) + { +- int fd = TEMP_FAILURE_RETRY(::open("/dev/urandom", O_RDONLY)); ++ int fd = TEMP_FAILURE_RETRY(::open("/dev/urandom", O_RDONLY|O_CLOEXEC)); + if (fd < 0) + return -errno; + int ret = safe_read_exact(fd, buf, len); +diff --git a/src/auth/cephx/CephxClientHandler.cc b/src/auth/cephx/CephxClientHandler.cc +index 89d42903..5b97917d 100644 +--- a/src/auth/cephx/CephxClientHandler.cc ++++ b/src/auth/cephx/CephxClientHandler.cc +@@ -31,8 +31,6 @@ int CephxClientHandler::build_request(bufferlist& bl) const + { + ldout(cct, 10) << "build_request" << dendl; + +- RWLock::RLocker l(lock); +- + if (need & CEPH_ENTITY_TYPE_AUTH) { + /* authenticate */ + CephXRequestHeader header; +@@ -109,7 +107,6 @@ bool CephxClientHandler::_need_tickets() const + int CephxClientHandler::handle_response(int ret, bufferlist::iterator& indata) + { + ldout(cct, 10) << "handle_response ret = " << ret << dendl; +- RWLock::WLocker l(lock); + + if (ret < 0) + return ret; // hrm! +@@ -203,7 +200,6 @@ int CephxClientHandler::handle_response(int ret, bufferlist::iterator& indata) + + AuthAuthorizer *CephxClientHandler::build_authorizer(uint32_t service_id) const + { +- RWLock::RLocker l(lock); + ldout(cct, 10) << "build_authorizer for service " << ceph_entity_type_name(service_id) << dendl; + return tickets.build_authorizer(service_id); + } +@@ -220,7 +216,6 @@ bool CephxClientHandler::build_rotating_request(bufferlist& bl) const + + void CephxClientHandler::prepare_build_request() + { +- RWLock::WLocker l(lock); + ldout(cct, 10) << "validate_tickets: want=" << want << " need=" << need + << " have=" << have << dendl; + validate_tickets(); +@@ -238,7 +233,6 @@ void CephxClientHandler::validate_tickets() + + bool CephxClientHandler::need_tickets() + { +- RWLock::WLocker l(lock); + validate_tickets(); + + ldout(cct, 20) << "need_tickets: want=" << want +diff --git a/src/auth/cephx/CephxClientHandler.h b/src/auth/cephx/CephxClientHandler.h +index 9c652224..a6539b97 100644 +--- a/src/auth/cephx/CephxClientHandler.h ++++ b/src/auth/cephx/CephxClientHandler.h +@@ -47,8 +47,11 @@ public: + reset(); + } + ++ CephxClientHandler* clone() const override { ++ return new CephxClientHandler(*this); ++ } ++ + void reset() override { +- RWLock::WLocker l(lock); + starting = true; + server_challenge = 0; + } +@@ -64,7 +67,6 @@ public: + bool need_tickets() override; + + void set_global_id(uint64_t id) override { +- RWLock::WLocker l(lock); + global_id = id; + tickets.global_id = id; + } +diff --git a/src/auth/cephx/CephxKeyServer.cc b/src/auth/cephx/CephxKeyServer.cc +index e06de660..5f530271 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, +- ExpiringCryptoKey& 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,25 +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; +- 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; ++ // 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 << " ttl " << ttl ++ << dendl; + return true; + } + +@@ -233,20 +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, +- ExpiringCryptoKey& secret, uint64_t& secret_id) const ++bool KeyServer::get_service_secret(uint32_t service_id, CryptoKey& secret, ++ uint64_t& secret_id, double& ttl) const + { + Mutex::Locker l(lock); + +- return data.get_service_secret(cct, service_id, secret, secret_id); +-} +- +-bool KeyServer::get_service_secret(uint32_t service_id, +- CryptoKey& secret, uint64_t& secret_id) const +-{ +- Mutex::Locker 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, +@@ -421,12 +414,15 @@ bool KeyServer::get_service_caps(const EntityName& name, uint32_t service_id, + } + + +-int KeyServer::_build_session_auth_info(uint32_t service_id, CephXServiceTicketInfo& auth_ticket_info, +- CephXSessionAuthInfo& info) ++int KeyServer::_build_session_auth_info(uint32_t service_id, ++ const AuthTicket& parent_ticket, ++ CephXSessionAuthInfo& info, ++ double ttl) + { + info.service_id = service_id; +- info.ticket = auth_ticket_info.ticket; +- info.ticket.init_timestamps(ceph_clock_now(), cct->_conf->auth_service_ticket_ttl); ++ info.ticket = parent_ticket; ++ info.ticket.init_timestamps(ceph_clock_now(), ttl); ++ info.validity.set_from_double(ttl); + + generate_secret(info.session_key); + +@@ -440,25 +436,31 @@ int KeyServer::_build_session_auth_info(uint32_t service_id, CephXServiceTicketI + return 0; + } + +-int KeyServer::build_session_auth_info(uint32_t service_id, CephXServiceTicketInfo& auth_ticket_info, ++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; + } + + Mutex::Locker l(lock); +- +- return _build_session_auth_info(service_id, auth_ticket_info, info); ++ return _build_session_auth_info(service_id, parent_ticket, info, ttl); + } + +-int KeyServer::build_session_auth_info(uint32_t service_id, CephXServiceTicketInfo& auth_ticket_info, CephXSessionAuthInfo& info, +- CryptoKey& service_secret, uint64_t secret_id) ++int KeyServer::build_session_auth_info(uint32_t service_id, ++ const AuthTicket& parent_ticket, ++ const CryptoKey& service_secret, ++ uint64_t secret_id, ++ CephXSessionAuthInfo& info) + { + info.service_secret = service_secret; + info.secret_id = secret_id; + + Mutex::Locker l(lock); +- return _build_session_auth_info(service_id, auth_ticket_info, 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 ff91e96d..7da08b1b 100644 +--- a/src/auth/cephx/CephxKeyServer.h ++++ b/src/auth/cephx/CephxKeyServer.h +@@ -89,9 +89,8 @@ struct KeyServerData { + } + + 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; ++ 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; +@@ -193,7 +192,9 @@ class KeyServer : public KeyStore { + bool _check_rotating_secrets(); + void _dump_rotating_secrets(); + int _build_session_auth_info(uint32_t service_id, +- CephXServiceTicketInfo& auth_ticket_info, CephXSessionAuthInfo& info); ++ const AuthTicket& parent_ticket, ++ CephXSessionAuthInfo& info, ++ double ttl); + bool _get_service_caps(const EntityName& name, uint32_t service_id, + AuthCapsInfo& caps) const; + public: +@@ -207,15 +208,18 @@ public: + int start_server(); + void rotate_timeout(double timeout); + +- int build_session_auth_info(uint32_t service_id, CephXServiceTicketInfo& auth_ticket_info, CephXSessionAuthInfo& info); +- int build_session_auth_info(uint32_t service_id, CephXServiceTicketInfo& auth_ticket_info, CephXSessionAuthInfo& info, +- CryptoKey& service_secret, uint64_t secret_id); ++ int build_session_auth_info(uint32_t service_id, ++ const AuthTicket& parent_ticket, ++ CephXSessionAuthInfo& info); ++ int build_session_auth_info(uint32_t service_id, ++ const AuthTicket& parent_ticket, ++ 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, ExpiringCryptoKey& service_key, +- uint64_t& secret_id) const; +- 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/CephxProtocol.cc b/src/auth/cephx/CephxProtocol.cc +index cc5f4496..2905c3c9 100644 +--- a/src/auth/cephx/CephxProtocol.cc ++++ b/src/auth/cephx/CephxProtocol.cc +@@ -349,8 +349,10 @@ void CephXTicketManager::validate_tickets(uint32_t mask, uint32_t& have, uint32_ + << " need " << need << dendl; + } + +-bool cephx_decode_ticket(CephContext *cct, KeyStore *keys, uint32_t service_id, +- CephXTicketBlob& ticket_blob, CephXServiceTicketInfo& ticket_info) ++bool cephx_decode_ticket(CephContext *cct, KeyStore *keys, ++ uint32_t service_id, ++ const CephXTicketBlob& ticket_blob, ++ CephXServiceTicketInfo& ticket_info) + { + uint64_t secret_id = ticket_blob.secret_id; + CryptoKey service_secret; +diff --git a/src/auth/cephx/CephxProtocol.h b/src/auth/cephx/CephxProtocol.h +index b5ec897f..cd20cd43 100644 +--- a/src/auth/cephx/CephxProtocol.h ++++ b/src/auth/cephx/CephxProtocol.h +@@ -168,12 +168,16 @@ struct CephXAuthenticate { + uint64_t key; + CephXTicketBlob old_ticket; + ++ bool old_ticket_may_be_omitted; ++ + void encode(bufferlist& bl) const { +- __u8 struct_v = 1; ++ __u8 struct_v = 3; + ::encode(struct_v, bl); + ::encode(client_challenge, bl); + ::encode(key, bl); + ::encode(old_ticket, bl); ++ uint32_t other_keys = 0; ++ ::encode(other_keys, bl); + } + void decode(bufferlist::iterator& bl) { + __u8 struct_v; +@@ -181,6 +185,13 @@ struct CephXAuthenticate { + ::decode(client_challenge, bl); + ::decode(key, bl); + ::decode(old_ticket, bl); ++ ++ // v2 and v3 encodings are the same, but: ++ // - some clients that send v1 or v2 don't populate old_ticket ++ // on reconnects (but do on renewals) ++ // - any client that sends v3 or later is expected to populate ++ // old_ticket both on reconnects and renewals ++ old_ticket_may_be_omitted = struct_v < 3; + } + }; + WRITE_CLASS_ENCODER(CephXAuthenticate) +@@ -429,7 +440,8 @@ WRITE_CLASS_ENCODER(CephXAuthorize) + * Decode an extract ticket + */ + bool cephx_decode_ticket(CephContext *cct, KeyStore *keys, +- uint32_t service_id, CephXTicketBlob& ticket_blob, ++ uint32_t service_id, ++ const CephXTicketBlob& ticket_blob, + CephXServiceTicketInfo& ticket_info); + + /* +@@ -453,8 +465,8 @@ extern bool cephx_verify_authorizer( + static constexpr uint64_t AUTH_ENC_MAGIC = 0xff009cad8826aa55ull; + + template +-void decode_decrypt_enc_bl(CephContext *cct, T& t, CryptoKey key, bufferlist& bl_enc, +- std::string &error) ++void decode_decrypt_enc_bl(CephContext *cct, T& t, CryptoKey key, ++ const bufferlist& bl_enc, std::string &error) + { + uint64_t magic; + bufferlist bl; +diff --git a/src/auth/cephx/CephxServiceHandler.cc b/src/auth/cephx/CephxServiceHandler.cc +index b06e0080..0a6c3431 100644 +--- a/src/auth/cephx/CephxServiceHandler.cc ++++ b/src/auth/cephx/CephxServiceHandler.cc +@@ -26,9 +26,12 @@ + #undef dout_prefix + #define dout_prefix *_dout << "cephx server " << entity_name << ": " + +-int CephxServiceHandler::start_session(EntityName& name, bufferlist::iterator& indata, bufferlist& result_bl, AuthCapsInfo& caps) ++int CephxServiceHandler::do_start_session(bool is_new_global_id, ++ bufferlist& result_bl, ++ AuthCapsInfo& caps) + { +- entity_name = name; ++ global_id_status = is_new_global_id ? global_id_status_t::NEW_PENDING : ++ global_id_status_t::RECLAIM_PENDING; + + get_random_bytes((char *)&server_challenge, sizeof(server_challenge)); + if (!server_challenge) +@@ -41,7 +44,89 @@ int CephxServiceHandler::start_session(EntityName& name, bufferlist::iterator& i + return CEPH_AUTH_CEPHX; + } + +-int CephxServiceHandler::handle_request(bufferlist::iterator& indata, bufferlist& result_bl, uint64_t& global_id, AuthCapsInfo& caps, uint64_t *auid) ++int CephxServiceHandler::verify_old_ticket(const CephXAuthenticate& req, ++ CephXServiceTicketInfo& old_ticket_info, ++ bool& should_enc_ticket) ++{ ++ ldout(cct, 20) << " checking old_ticket: secret_id=" ++ << req.old_ticket.secret_id ++ << " len=" << req.old_ticket.blob.length() ++ << ", old_ticket_may_be_omitted=" ++ << req.old_ticket_may_be_omitted << dendl; ++ ceph_assert(global_id_status != global_id_status_t::NONE); ++ if (global_id_status == global_id_status_t::NEW_PENDING) { ++ // old ticket is not needed ++ if (req.old_ticket.blob.length()) { ++ ldout(cct, 0) << " superfluous ticket presented" << dendl; ++ return -EINVAL; ++ } ++ if (req.old_ticket_may_be_omitted) { ++ ldout(cct, 10) << " new global_id " << global_id ++ << " (unexposed legacy client)" << dendl; ++ global_id_status = global_id_status_t::NEW_NOT_EXPOSED; ++ } else { ++ ldout(cct, 10) << " new global_id " << global_id << dendl; ++ global_id_status = global_id_status_t::NEW_OK; ++ } ++ return 0; ++ } ++ ++ if (!req.old_ticket.blob.length()) { ++ // old ticket is needed but not presented ++ if (cct->_conf->auth_allow_insecure_global_id_reclaim && ++ req.old_ticket_may_be_omitted) { ++ ldout(cct, 10) << " allowing reclaim of global_id " << global_id ++ << " with no ticket presented (legacy client, auth_allow_insecure_global_id_reclaim=true)" ++ << dendl; ++ global_id_status = global_id_status_t::RECLAIM_INSECURE; ++ return 0; ++ } ++ ldout(cct, 0) << " attempt to reclaim global_id " << global_id ++ << " without presenting ticket" << dendl; ++ return -EACCES; ++ } ++ ++ if (!cephx_decode_ticket(cct, key_server, CEPH_ENTITY_TYPE_AUTH, ++ req.old_ticket, old_ticket_info)) { ++ if (cct->_conf->auth_allow_insecure_global_id_reclaim && ++ req.old_ticket_may_be_omitted) { ++ ldout(cct, 10) << " allowing reclaim of global_id " << global_id ++ << " using bad ticket (legacy client, auth_allow_insecure_global_id_reclaim=true)" ++ << dendl; ++ global_id_status = global_id_status_t::RECLAIM_INSECURE; ++ return 0; ++ } ++ ldout(cct, 0) << " attempt to reclaim global_id " << global_id ++ << " using bad ticket" << dendl; ++ return -EACCES; ++ } ++ ldout(cct, 20) << " decoded old_ticket: global_id=" ++ << old_ticket_info.ticket.global_id << dendl; ++ if (global_id != old_ticket_info.ticket.global_id) { ++ if (cct->_conf->auth_allow_insecure_global_id_reclaim && ++ req.old_ticket_may_be_omitted) { ++ ldout(cct, 10) << " allowing reclaim of global_id " << global_id ++ << " using mismatching ticket (legacy client, auth_allow_insecure_global_id_reclaim=true)" ++ << dendl; ++ global_id_status = global_id_status_t::RECLAIM_INSECURE; ++ return 0; ++ } ++ ldout(cct, 0) << " attempt to reclaim global_id " << global_id ++ << " using mismatching ticket" << dendl; ++ return -EACCES; ++ } ++ ldout(cct, 10) << " allowing reclaim of global_id " << global_id ++ << " (valid ticket presented, will encrypt new ticket)" ++ << dendl; ++ global_id_status = global_id_status_t::RECLAIM_OK; ++ should_enc_ticket = true; ++ return 0; ++} ++ ++int CephxServiceHandler::handle_request(bufferlist::iterator& indata, ++ bufferlist& result_bl, ++ AuthCapsInfo& caps, ++ uint64_t *auid) + { + int ret = 0; + +@@ -60,13 +145,13 @@ int CephxServiceHandler::handle_request(bufferlist::iterator& indata, bufferlist + CryptoKey secret; + if (!key_server->get_secret(entity_name, secret)) { + ldout(cct, 0) << "couldn't find entity name: " << entity_name << dendl; +- ret = -EPERM; +- break; ++ ret = -EPERM; ++ break; + } + + if (!server_challenge) { +- ret = -EPERM; +- break; ++ ret = -EPERM; ++ break; + } + + uint64_t expected_key; +@@ -74,18 +159,18 @@ int CephxServiceHandler::handle_request(bufferlist::iterator& indata, bufferlist + cephx_calc_client_server_challenge(cct, secret, server_challenge, + req.client_challenge, &expected_key, error); + if (!error.empty()) { +- ldout(cct, 0) << " cephx_calc_client_server_challenge error: " << error << dendl; +- ret = -EPERM; +- break; ++ ldout(cct, 0) << " cephx_calc_client_server_challenge error: " << error << dendl; ++ ret = -EPERM; ++ break; + } + + ldout(cct, 20) << " checking key: req.key=" << hex << req.key + << " expected_key=" << expected_key << dec << dendl; + if (req.key != expected_key) { + ldout(cct, 0) << " unexpected key: req.key=" << hex << req.key +- << " expected_key=" << expected_key << dec << dendl; ++ << " expected_key=" << expected_key << dec << dendl; + ret = -EPERM; +- break; ++ break; + } + + CryptoKey session_key; +@@ -94,35 +179,38 @@ int CephxServiceHandler::handle_request(bufferlist::iterator& indata, bufferlist + + EntityAuth eauth; + if (! key_server->get_auth(entity_name, eauth)) { +- ret = -EPERM; +- break; ++ ret = -EPERM; ++ break; + } ++ + CephXServiceTicketInfo old_ticket_info; ++ ret = verify_old_ticket(req, old_ticket_info, should_enc_ticket); ++ if (ret) { ++ ldout(cct, 0) << " could not verify old ticket" << dendl; ++ break; ++ } + +- if (cephx_decode_ticket(cct, key_server, CEPH_ENTITY_TYPE_AUTH, +- req.old_ticket, old_ticket_info)) { +- global_id = old_ticket_info.ticket.global_id; +- ldout(cct, 10) << "decoded old_ticket with global_id=" << global_id << dendl; +- should_enc_ticket = true; ++ 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.ticket.init_timestamps(ceph_clock_now(), cct->_conf->auth_mon_ticket_ttl); ++ info.service_id = CEPH_ENTITY_TYPE_AUTH; + info.ticket.name = entity_name; + info.ticket.global_id = global_id; + info.ticket.auid = eauth.auid; +- info.validity += cct->_conf->auth_mon_ticket_ttl; ++ info.ticket.init_timestamps(ceph_clock_now(), ttl); ++ info.validity.set_from_double(ttl); + + if (auid) *auid = eauth.auid; + + key_server->generate_secret(session_key); + + info.session_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); +@@ -130,7 +218,7 @@ int CephxServiceHandler::handle_request(bufferlist::iterator& indata, bufferlist + build_cephx_response_header(cephx_header.request_type, 0, result_bl); + if (!cephx_build_service_ticket_reply(cct, eauth.key, info_vec, should_enc_ticket, + old_ticket_info.session_key, result_bl)) { +- ret = -EIO; ++ ret = -EIO; + } + + if (!key_server->get_service_caps(entity_name, CEPH_ENTITY_TYPE_MON, caps)) { +@@ -156,7 +244,7 @@ int CephxServiceHandler::handle_request(bufferlist::iterator& indata, bufferlist + if (!cephx_verify_authorizer(cct, key_server, indata, auth_ticket_info, nullptr, + tmp_bl)) { + ret = -EPERM; +- break; ++ break; + } + + CephXServiceTicketRequest ticket_req; +@@ -168,13 +256,18 @@ int CephxServiceHandler::handle_request(bufferlist::iterator& indata, bufferlist + int found_services = 0; + int service_err = 0; + for (uint32_t service_id = 1; service_id <= ticket_req.keys; +- service_id <<= 1) { +- if (ticket_req.keys & service_id) { +- ldout(cct, 10) << " adding key for service " ++ service_id <<= 1) { ++ // skip CEPH_ENTITY_TYPE_AUTH: auth ticket must be obtained with ++ // CEPHX_GET_AUTH_SESSION_KEY ++ if ((ticket_req.keys & service_id) && ++ service_id != CEPH_ENTITY_TYPE_AUTH) { ++ ldout(cct, 10) << " adding key for service " + << ceph_entity_type_name(service_id) << dendl; + CephXSessionAuthInfo info; +- int r = key_server->build_session_auth_info(service_id, +- auth_ticket_info, info); ++ int r = key_server->build_session_auth_info( ++ service_id, ++ auth_ticket_info.ticket, ++ info); + // tolerate missing MGR rotating key for the purposes of upgrades. + if (r < 0) { + ldout(cct, 10) << " missing key for service " +@@ -182,9 +275,8 @@ int CephxServiceHandler::handle_request(bufferlist::iterator& indata, bufferlist + service_err = r; + continue; + } +- info.validity += cct->_conf->auth_service_ticket_ttl; +- info_vec.push_back(info); +- ++found_services; ++ info_vec.push_back(info); ++ ++found_services; + } + } + if (!found_services && service_err) { +diff --git a/src/auth/cephx/CephxServiceHandler.h b/src/auth/cephx/CephxServiceHandler.h +index 390a6dc1..18f87e39 100644 +--- a/src/auth/cephx/CephxServiceHandler.h ++++ b/src/auth/cephx/CephxServiceHandler.h +@@ -19,6 +19,8 @@ + #include "auth/Auth.h" + + class KeyServer; ++struct CephXAuthenticate; ++struct CephXServiceTicketInfo; + + class CephxServiceHandler : public AuthServiceHandler { + KeyServer *key_server; +@@ -29,9 +31,21 @@ public: + : AuthServiceHandler(cct_), key_server(ks), server_challenge(0) {} + ~CephxServiceHandler() override {} + +- int start_session(EntityName& name, bufferlist::iterator& indata, bufferlist& result_bl, AuthCapsInfo& caps) override; +- int handle_request(bufferlist::iterator& indata, bufferlist& result_bl, uint64_t& global_id, AuthCapsInfo& caps, uint64_t *auid = NULL) override; +- void build_cephx_response_header(int request_type, int status, bufferlist& bl); ++ int handle_request(bufferlist::iterator& indata, ++ bufferlist& result_bl, ++ AuthCapsInfo& caps, ++ uint64_t *auid = NULL) override; ++ ++private: ++ int do_start_session(bool is_new_global_id, ++ bufferlist& result_bl, ++ AuthCapsInfo& caps) override; ++ ++ int verify_old_ticket(const CephXAuthenticate& req, ++ CephXServiceTicketInfo& old_ticket_info, ++ bool& should_enc_ticket); ++ void build_cephx_response_header(int request_type, int status, ++ bufferlist& bl); + }; + + #endif +diff --git a/src/auth/none/AuthNoneClientHandler.h b/src/auth/none/AuthNoneClientHandler.h +index 369aa548..2a52f331 100644 +--- a/src/auth/none/AuthNoneClientHandler.h ++++ b/src/auth/none/AuthNoneClientHandler.h +@@ -22,9 +22,13 @@ + + class AuthNoneClientHandler : public AuthClientHandler { + public: +- AuthNoneClientHandler(CephContext *cct_, RotatingKeyRing *rkeys) ++ AuthNoneClientHandler(CephContext *cct_) + : AuthClientHandler(cct_) {} + ++ AuthNoneClientHandler* clone() const override { ++ return new AuthNoneClientHandler(*this); ++ } ++ + void reset() override { } + + void prepare_build_request() override {} +@@ -35,7 +39,6 @@ public: + int get_protocol() const override { return CEPH_AUTH_NONE; } + + AuthAuthorizer *build_authorizer(uint32_t service_id) const override { +- RWLock::RLocker l(lock); + AuthNoneAuthorizer *auth = new AuthNoneAuthorizer(); + if (auth) { + auth->build_authorizer(cct->_conf->name, global_id); +@@ -46,7 +49,6 @@ public: + bool need_tickets() override { return false; } + + void set_global_id(uint64_t id) override { +- RWLock::WLocker l(lock); + global_id = id; + } + private: +diff --git a/src/auth/none/AuthNoneServiceHandler.h b/src/auth/none/AuthNoneServiceHandler.h +index 120a7a98..17ce2f8a 100644 +--- a/src/auth/none/AuthNoneServiceHandler.h ++++ b/src/auth/none/AuthNoneServiceHandler.h +@@ -26,15 +26,20 @@ public: + : AuthServiceHandler(cct_) {} + ~AuthNoneServiceHandler() override {} + +- int start_session(EntityName& name, bufferlist::iterator& indata, bufferlist& result_bl, AuthCapsInfo& caps) override { +- entity_name = name; ++ int handle_request(bufferlist::iterator& indata, ++ bufferlist& result_bl, ++ AuthCapsInfo& caps, ++ uint64_t *auid = NULL) override { ++ return 0; ++ } ++ ++private: ++ int do_start_session(bool is_new_global_id, ++ bufferlist& result_bl, ++ AuthCapsInfo& caps) override { + caps.allow_all = true; + return CEPH_AUTH_NONE; + } +- int handle_request(bufferlist::iterator& indata, bufferlist& result_bl, uint64_t& global_id, AuthCapsInfo& caps, uint64_t *auid = NULL) override { +- return 0; +- } +- void build_cephx_response_header(int request_type, int status, bufferlist& bl) { } + }; + + #endif +diff --git a/src/auth/unknown/AuthUnknownServiceHandler.h b/src/auth/unknown/AuthUnknownServiceHandler.h +index 5c1e511e..61ca6b29 100644 +--- a/src/auth/unknown/AuthUnknownServiceHandler.h ++++ b/src/auth/unknown/AuthUnknownServiceHandler.h +@@ -26,14 +26,18 @@ public: + : AuthServiceHandler(cct_) {} + ~AuthUnknownServiceHandler() {} + +- int start_session(EntityName& name, bufferlist::iterator& indata, bufferlist& result_bl, AuthCapsInfo& caps) { ++ int start_session(EntityName& name, ++ bufferlist& result_bl, ++ AuthCapsInfo& caps) override { + return CEPH_AUTH_UNKNOWN; + } +- int handle_request(bufferlist::iterator& indata, bufferlist& result_bl, uint64_t& global_id, AuthCapsInfo& caps, uint64_t *auid = NULL) { ++ int handle_request(bufferlist::iterator& indata, ++ bufferlist& result_bl, ++ AuthCapsInfo& caps, ++ uint64_t *auid = NULL) { + ceph_abort(); // shouldn't get called + return 0; + } +- void build_cephx_response_header(int request_type, int status, bufferlist& bl) { } + }; + + #endif +diff --git a/src/common/legacy_config_opts.h b/src/common/legacy_config_opts.h +index 38b36a60..cbb4528e 100644 +--- a/src/common/legacy_config_opts.h ++++ b/src/common/legacy_config_opts.h +@@ -340,6 +340,8 @@ OPTION(cephx_service_require_version, OPT_INT) + OPTION(cephx_sign_messages, OPT_BOOL) // Default to signing session messages if supported + OPTION(auth_mon_ticket_ttl, OPT_DOUBLE) + OPTION(auth_service_ticket_ttl, OPT_DOUBLE) ++OPTION(auth_allow_insecure_global_id_reclaim, OPT_BOOL) ++OPTION(auth_expose_insecure_global_id_reclaim, OPT_BOOL) + OPTION(auth_debug, OPT_BOOL) // if true, assert when weird things happen + OPTION(mon_client_hunt_parallel, OPT_U32) // how many mons to try to connect to in parallel during hunt + OPTION(mon_client_hunt_interval, OPT_DOUBLE) // try new mon every N seconds until we connect +diff --git a/src/common/options.cc b/src/common/options.cc +index 1ed027c9..cf8f6bbe 100644 +--- a/src/common/options.cc ++++ b/src/common/options.cc +@@ -1128,6 +1128,22 @@ std::vector