summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Bungert <[email protected]>2024-03-19 21:40:26 -0600
committerDan Bungert <[email protected]>2024-03-25 10:42:32 -0600
commit204562c277b096229ca20ba546149deef1d85e38 (patch)
tree9b115d546122675e3afe002596a7017e5d9278d2
parent974c0d0c365fa3068fa1c43e38261189e622e17d (diff)
block/zfs: flock for ZFS24.0.0
Add flock calls around encrypted ZFS creation areas LP: #2057661
-rw-r--r--curtin/block/zfs.py49
-rw-r--r--tests/unittests/test_block_zfs.py14
2 files changed, 36 insertions, 27 deletions
diff --git a/curtin/block/zfs.py b/curtin/block/zfs.py
index 767ad304..ccdddbb3 100644
--- a/curtin/block/zfs.py
+++ b/curtin/block/zfs.py
@@ -8,6 +8,7 @@ import os
import tempfile
import secrets
import shutil
+from contextlib import ExitStack
from pathlib import Path
from curtin.config import merge_config
@@ -31,11 +32,12 @@ ZFS_UNSUPPORTED_RELEASES = ['precise', 'trusty']
class ZPoolEncryption:
- def __init__(self, poolname, style, keyfile):
+ def __init__(self, vdevs, poolname, style, keyfile):
self.poolname = poolname
self.style = style
self.keyfile = keyfile
self.system_key = None
+ self.vdevs = vdevs
def get_system_key(self):
if self.system_key is None:
@@ -88,24 +90,31 @@ class ZPoolEncryption:
self.poolname, "keystore", {"encryption": "off"}, keystore_size,
)
- # cryptsetup format and open this keystore
- keystore_volume = f"/dev/zvol/{self.poolname}/keystore"
- cmd = ["cryptsetup", "luksFormat", keystore_volume, self.keyfile]
- util.subp(cmd)
- dm_name = f"keystore-{self.poolname}"
- cmd = [
- "cryptsetup", "open", "--type", "luks", keystore_volume, dm_name,
- "--key-file", self.keyfile,
- ]
- util.subp(cmd)
-
- # format as ext4, mount it, move the previously-generated system key
- dmpath = f"/dev/mapper/{dm_name}"
- cmd = ["mke2fs", "-t", "ext4", dmpath, "-L", dm_name]
- util.subp(cmd, capture=True)
-
- keystore_root = f"/run/keystore/{self.poolname}"
- with util.mount(dmpath, keystore_root):
+ with ExitStack() as es:
+ for vdev in self.vdevs:
+ es.enter_context(util.FlockEx(vdev))
+
+ # cryptsetup format and open this keystore
+ keystore_volume = f"/dev/zvol/{self.poolname}/keystore"
+ cmd = ["cryptsetup", "luksFormat", keystore_volume, self.keyfile]
+ util.subp(cmd)
+ dm_name = f"keystore-{self.poolname}"
+ cmd = [
+ "cryptsetup", "open", "--type", "luks", keystore_volume,
+ dm_name, "--key-file", self.keyfile,
+ ]
+ util.subp(cmd)
+
+ with ExitStack() as es:
+ # format as ext4, mount it, move the previously-generated systemkey
+ dmpath = f"/dev/mapper/{dm_name}"
+ es.enter_context(util.FlockEx(dmpath))
+ cmd = ["mke2fs", "-t", "ext4", dmpath, "-L", dm_name]
+ util.subp(cmd, capture=True)
+
+ keystore_root = f"/run/keystore/{self.poolname}"
+
+ es.enter_context(util.mount(dmpath, keystore_root))
ks_system_key = f"{keystore_root}/system.key"
shutil.move(self.system_key, ks_system_key)
Path(ks_system_key).chmod(0o400)
@@ -256,7 +265,7 @@ def zpool_create(poolname, vdevs, storage_config=None, context=None,
if zfs_properties:
merge_config(zfs_cfg, zfs_properties)
- encryption = ZPoolEncryption(poolname, encryption_style, keyfile)
+ encryption = ZPoolEncryption(vdevs, poolname, encryption_style, keyfile)
encryption.validate()
if encryption.in_use():
merge_config(zfs_cfg, encryption.dataset_properties())
diff --git a/tests/unittests/test_block_zfs.py b/tests/unittests/test_block_zfs.py
index ef24b5d3..23dba50f 100644
--- a/tests/unittests/test_block_zfs.py
+++ b/tests/unittests/test_block_zfs.py
@@ -614,7 +614,7 @@ class TestZfsKeystore(CiTestCase):
def test_create_system_key(self, m_token_bytes):
m_token_bytes.return_value = key = self.random_string()
m_open = mock.mock_open()
- zpe = zfs.ZPoolEncryption(None, None, None)
+ zpe = zfs.ZPoolEncryption(None, None, None, None)
with mock.patch("builtins.open", m_open):
system_key = zpe.get_system_key()
self.assertIsNotNone(system_key)
@@ -622,7 +622,7 @@ class TestZfsKeystore(CiTestCase):
m_open.return_value.write.assert_called_with(key)
def test_validate_good(self):
- zpe = zfs.ZPoolEncryption("pool1", "luks_keystore", self.keyfile)
+ zpe = zfs.ZPoolEncryption(None, "pool1", "luks_keystore", self.keyfile)
try:
zpe.validate()
except Exception:
@@ -630,22 +630,22 @@ class TestZfsKeystore(CiTestCase):
self.assertTrue(zpe.in_use())
def test_validate_missing_pool(self):
- zpe = zfs.ZPoolEncryption(None, "luks_keystore", self.keyfile)
+ zpe = zfs.ZPoolEncryption(None, None, "luks_keystore", self.keyfile)
with self.assertRaises(ValueError):
zpe.validate()
def test_validate_missing_key(self):
- zpe = zfs.ZPoolEncryption("pool1", "luks_keystore", None)
+ zpe = zfs.ZPoolEncryption(None, "pool1", "luks_keystore", None)
with self.assertRaises(ValueError):
zpe.validate()
def test_validate_missing_key_file(self):
- zpe = zfs.ZPoolEncryption("pool1", "luks_keystore", "not-exist")
+ zpe = zfs.ZPoolEncryption(None, "pool1", "luks_keystore", "not-exist")
with self.assertRaises(ValueError):
zpe.validate()
def test_validate_unencrypted_ok(self):
- zpe = zfs.ZPoolEncryption("pool1", None, None)
+ zpe = zfs.ZPoolEncryption(None, "pool1", None, None)
try:
zpe.validate()
except Exception:
@@ -653,7 +653,7 @@ class TestZfsKeystore(CiTestCase):
self.assertFalse(zpe.in_use())
def test_dataset_properties(self):
- zpe = zfs.ZPoolEncryption("pool1", "luks_keystore", self.keyfile)
+ zpe = zfs.ZPoolEncryption(None, "pool1", "luks_keystore", self.keyfile)
keyloc = self.random_string()
with mock.patch.object(zpe, "get_system_key", return_value=keyloc):
props = zpe.dataset_properties()