Commit 6136f8f0 authored by Iustin Pop's avatar Iustin Pop
Browse files

Add strict name validation for the LVM backend



Currently we don't enforce name validation for the LVM backend, on the
idea that LVM itself will reject invalid names and we catch those
errors.

However, recent LVM documents the accepted VG/LV name space, so it's
easy to add this in the LVM backend code.

In addition, the patch changes some hardcoded /dev/ constructions with
utils.PathJoin().
Signed-off-by: default avatarIustin Pop <iustin@google.com>
Reviewed-by: default avatarMichael Hanselmann <hansmi@google.com>
parent cb7c0198
...@@ -349,6 +349,10 @@ class LogicalVolume(BlockDev): ...@@ -349,6 +349,10 @@ class LogicalVolume(BlockDev):
"""Logical Volume block device. """Logical Volume block device.
""" """
_VALID_NAME_RE = re.compile("^[a-zA-Z0-9+_.-]*$")
_INVALID_NAMES = frozenset([".", "..", "snapshot", "pvmove"])
_INVALID_SUBSTRINGS = frozenset(["_mlog", "_mimage"])
def __init__(self, unique_id, children, size): def __init__(self, unique_id, children, size):
"""Attaches to a LV device. """Attaches to a LV device.
...@@ -359,7 +363,9 @@ class LogicalVolume(BlockDev): ...@@ -359,7 +363,9 @@ class LogicalVolume(BlockDev):
if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2: if not isinstance(unique_id, (tuple, list)) or len(unique_id) != 2:
raise ValueError("Invalid configuration data %s" % str(unique_id)) raise ValueError("Invalid configuration data %s" % str(unique_id))
self._vg_name, self._lv_name = unique_id self._vg_name, self._lv_name = unique_id
self.dev_path = "/dev/%s/%s" % (self._vg_name, self._lv_name) self._ValidateName(self._vg_name)
self._ValidateName(self._lv_name)
self.dev_path = utils.PathJoin("/dev", self._vg_name, self._lv_name)
self._degraded = True self._degraded = True
self.major = self.minor = self.pe_size = self.stripe_count = None self.major = self.minor = self.pe_size = self.stripe_count = None
self.Attach() self.Attach()
...@@ -373,6 +379,8 @@ class LogicalVolume(BlockDev): ...@@ -373,6 +379,8 @@ class LogicalVolume(BlockDev):
raise errors.ProgrammerError("Invalid configuration data %s" % raise errors.ProgrammerError("Invalid configuration data %s" %
str(unique_id)) str(unique_id))
vg_name, lv_name = unique_id vg_name, lv_name = unique_id
cls._ValidateName(vg_name)
cls._ValidateName(lv_name)
pvs_info = cls.GetPVInfo([vg_name]) pvs_info = cls.GetPVInfo([vg_name])
if not pvs_info: if not pvs_info:
_ThrowError("Can't compute PV info for vg %s", vg_name) _ThrowError("Can't compute PV info for vg %s", vg_name)
...@@ -442,6 +450,20 @@ class LogicalVolume(BlockDev): ...@@ -442,6 +450,20 @@ class LogicalVolume(BlockDev):
return data return data
@classmethod
def _ValidateName(cls, name):
"""Validates that a given name is valid as VG or LV name.
The list of valid characters and restricted names is taken out of
the lvm(8) manpage, with the simplification that we enforce both
VG and LV restrictions on the names.
"""
if (not cls._VALID_NAME_RE.match(name) or
name in cls._INVALID_NAMES or
utils.any(cls._INVALID_SUBSTRINGS, lambda x: x in name)):
_ThrowError("Invalid LVM name '%s'", name)
def Remove(self): def Remove(self):
"""Remove this logical volume. """Remove this logical volume.
...@@ -469,7 +491,7 @@ class LogicalVolume(BlockDev): ...@@ -469,7 +491,7 @@ class LogicalVolume(BlockDev):
if result.failed: if result.failed:
_ThrowError("Failed to rename the logical volume: %s", result.output) _ThrowError("Failed to rename the logical volume: %s", result.output)
self._lv_name = new_name self._lv_name = new_name
self.dev_path = "/dev/%s/%s" % (self._vg_name, self._lv_name) self.dev_path = utils.PathJoin("/dev", self._vg_name, self._lv_name)
def Attach(self): def Attach(self):
"""Attach to an existing LV. """Attach to an existing LV.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment