From dc4d69d6d10cf1748bbdf971cd118db334991697 Mon Sep 17 00:00:00 2001 From: Kotresh HR Date: Sat, 8 Oct 2022 14:56:08 +0800 Subject: [PATCH] fix CVE-2022-0670 Fixes the subvolume discover to use the correct metadata file after an upgrade from legacy subvolume to v1. The fix makes sure, it doesn't use the handcrafted metadata file placed in the subvolume root of legacy subvolume. Co-authored-by: Arthur Outhenin-Chalandre Co-authored-by: Dan van der Ster Co-authored-by: Ramana Raja Signed-off-by: Kotresh HR (cherry picked from commit 7eba9cab6cfb9a13a84062177d7a0fa228311e13) (cherry picked from commit f8c04135150a7fb3c43607b43a8214e0d57547bc) Signed-off-by: Kotresh HR (cherry picked from commit 5bb46ee690591411d4890b613c6380fced9d04b4) --- .../operations/versions/metadata_manager.py | 17 +++++++++++--- .../fs/operations/versions/subvolume_base.py | 23 +++++++++++++++++-- .../fs/operations/versions/subvolume_v1.py | 2 +- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/pybind/mgr/volumes/fs/operations/versions/metadata_manager.py b/src/pybind/mgr/volumes/fs/operations/versions/metadata_manager.py index 1b6c43278..cb3059e56 100644 --- a/src/pybind/mgr/volumes/fs/operations/versions/metadata_manager.py +++ b/src/pybind/mgr/volumes/fs/operations/versions/metadata_manager.py @@ -40,16 +40,17 @@ class MetadataManager(object): def refresh(self): fd = None conf_data = StringIO() + log.debug("opening config {0}".format(self.config_path)) try: - log.debug("opening config {0}".format(self.config_path)) fd = self.fs.open(self.config_path, os.O_RDONLY) while True: data = self.fs.read(fd, -1, MetadataManager.MAX_IO_BYTES) if not len(data): break conf_data.write(data.decode('utf-8')) - conf_data.seek(0) - self.config.readfp(conf_data) + except UnicodeDecodeError: + raise MetadataMgrException(-errno.EINVAL, + "failed to decode, erroneous metadata config '{0}'".format(self.config_path)) except cephfs.ObjectNotFound: raise MetadataMgrException(-errno.ENOENT, "metadata config '{0}' not found".format(self.config_path)) except cephfs.Error as e: @@ -58,6 +59,16 @@ class MetadataManager(object): if fd is not None: self.fs.close(fd) + conf_data.seek(0) + try: + if sys.version_info >= (3, 2): + self.config.read_file(conf_data) + else: + self.config.readfp(conf_data) + except configparser.Error: + raise MetadataMgrException(-errno.EINVAL, "failed to parse, erroneous metadata config " + "'{0}'".format(self.config_path)) + def flush(self): # cull empty sections for section in list(self.config.sections()): diff --git a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_base.py b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_base.py index 2840a9f2e..0d183e612 100644 --- a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_base.py +++ b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_base.py @@ -5,6 +5,7 @@ import errno import logging from hashlib import md5 from typing import Dict, Union +from pathlib import Path import cephfs @@ -16,6 +17,7 @@ from ...fs_util import get_ancestor_xattr from ...exception import MetadataMgrException, VolumeException from .op_sm import SubvolumeOpSm from .auth_metadata import AuthMetadataManager +from .subvolume_attrs import SubvolumeStates log = logging.getLogger(__name__) @@ -111,7 +113,7 @@ class SubvolumeBase(object): @property def state(self): """ Subvolume state, one of SubvolumeStates """ - raise NotImplementedError + raise SubvolumeStates.from_value(self.metadata_mgr.get_global_option(MetadataManager.GLOBAL_META_KEY_STATE)) @property def subvol_type(self): @@ -123,6 +125,15 @@ class SubvolumeBase(object): raise NotImplementedError def load_config(self): + try: + self.fs.stat(self.legacy_config_path) + self.legacy_mode = True + except cephfs.Error as e: + pass + + log.debug("loding config " + "'{0}' [mode: {1}]".format(self.subvolname, "legacy" + if self.legacy_mode else "new")) if self.legacy_mode: self.metadata_mgr = MetadataManager(self.fs, self.legacy_config_path, 0o640) else: @@ -271,8 +282,16 @@ class SubvolumeBase(object): self.fs.stat(self.base_path) self.metadata_mgr.refresh() log.debug("loaded subvolume '{0}'".format(self.subvolname)) + subvolpath = self.metadata_mgr.get_global_option(MetadataManager.GLOBAL_META_KEY_PATH) + # subvolume with retained snapshots has enpty path, don't mistake it for + # fabricated metadata. + if (not self.legacy_mode and self.state != SubvolumeStates.STATE_RETAINED and + self.base_path.decode('utf-8') !=(Path(subvolpath).parent)): + raise MetadataMgrException(-errno.ENOENT, 'fabricated .meta') except MetadataMgrException as me: - if me.errno == -errno.ENOENT and not self.legacy_mode: + if me.errno in (-errno.ENOENT, -errno.EINVAL) and not self.legacy_mode: + log.warn("subvolume '{0}', {1}, " + "assuming legacy_mode".format(self.subvolname, me.error_str)) self.legacy_mode = True self.load_config() self.discover() diff --git a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v1.py b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v1.py index d62effd99..39f256638 100644 --- a/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v1.py +++ b/src/pybind/mgr/volumes/fs/operations/versions/subvolume_v1.py @@ -666,7 +666,7 @@ class SubvolumeV1(SubvolumeBase, SubvolumeTemplate): @property def state(self): - return SubvolumeStates.from_value(self.metadata_mgr.get_global_option(MetadataManager.GLOBAL_META_KEY_STATE)) + return super(SubvolumeV1, self).state @state.setter def state(self, val): -- 2.27.0