Merge ~dbungert/curtin:cryptoswap-dmc-type into curtin:master

Proposed by Dan Bungert
Status: Merged
Merged at revision: e01fe404124d6e03be3960d190dc0278334fb23a
Proposed branch: ~dbungert/curtin:cryptoswap-dmc-type
Merge into: curtin:master
Diff against target: 194 lines (+119/-7)
3 files modified
curtin/commands/block_meta.py (+10/-7)
tests/integration/test_block_meta.py (+7/-0)
tests/unittests/test_commands_block_meta.py (+102/-0)
Reviewer Review Type Date Requested Status
Server Team CI bot continuous-integration Approve
Michael Hudson-Doyle Approve
Review via email: mp+460874@code.launchpad.net

Commit message

dm_crypt: create and use cryptoswap as PLAIN

Previously, cryptoswap was acting strangely, in that at install time it
was considered to be a LUKS2 device and durign actual system use it
would be considered a PLAIN device, in the cryptsetup(8) meanings of
these terms.

This caused problems when attempting to reference the device, as we
would do get_volume_spec(), the returned /dev/disk/by-id/dm-uuid-...
value would be wrong - it would change from dm-uuid-CRYPT-LUKS2-... to
dm-uuid-CRYPT-PLAIN-...

As the real runtime behavior is to be a PLAIN device for cryptoswap,
stop creating it as a LUKS2 device and just use it as a PLAIN device,
which doesn't involve a "create" step at all, you just open it as PLAIN
directly.

To post a comment you must log in.
Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote :

Can you expand the commit message a whole bunch please? This is about the case where /dev/random is used as a keyfile, in which case the dm type of the device would be created as luks in the live system but then be plain in the installed system and changing to a world where it will be plain in both?

Code changes look good but I have a worry about temporary file handling.

review: Needs Fixing
Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Dan Bungert (dbungert) wrote :

> Can you expand the commit message a whole bunch please?

Done, or let me know if you would prefer more.

Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote :

Thanks for the changes. Please remember to update the commit message in the MP if you are going to let jenkins squash merge this!

review: Approve
Revision history for this message
Server Team CI bot (server-team-bot) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/curtin/commands/block_meta.py b/curtin/commands/block_meta.py
2index c7bd0dd..ff72193 100644
3--- a/curtin/commands/block_meta.py
4+++ b/curtin/commands/block_meta.py
5@@ -1633,28 +1633,29 @@ def dm_crypt_handler(info, storage_config, context):
6 volume_path = get_path_to_storage_volume(volume, storage_config)
7 volume_byid_path = block.disk_to_byid_path(volume_path)
8
9+ create_dmcrypt = True
10+ open_dmcrypt = False
11 if 'keyfile' in info:
12 if 'key' in info:
13 raise ValueError("cannot specify both key and keyfile")
14 keyfile = info['keyfile']
15 if keyfile in ("/dev/random", "/dev/urandom"):
16 crypttab_keyfile = keyfile
17- keyfile = tempfile.mkstemp()[1]
18- keyfile_is_tmp = True
19- else:
20- keyfile_is_tmp = False
21+ luks_type = "plain"
22+ open_dmcrypt = True
23+ create_dmcrypt = False
24+ remove_keyfile = False
25 elif 'key' in info:
26 # TODO: this is insecure, find better way to do this
27 key = info.get('key')
28 keyfile = tempfile.mkstemp()[1]
29- keyfile_is_tmp = True
30+ remove_keyfile = True
31 util.write_file(keyfile, key, mode=0o600)
32 else:
33 raise ValueError("encryption key or keyfile must be specified")
34
35 recovery_keyfile = info.get('recovery_keyfile')
36
37- create_dmcrypt = True
38 if preserve:
39 dm_crypt_verify(dmcrypt_dev, volume_path)
40 LOG.debug('dm_crypt %s already present, skipping create', dmcrypt_dev)
41@@ -1664,6 +1665,7 @@ def dm_crypt_handler(info, storage_config, context):
42 # if zkey is available, attempt to generate and use it; if it's not
43 # available or fails to setup properly, fallback to normal cryptsetup
44 # passing strict=False downgrades log messages to warnings
45+ open_dmcrypt = True
46 zkey_used = None
47 if block.zkey_supported(strict=False):
48 volume_name = "%s:%s" % (volume_byid_path, dm_name)
49@@ -1710,12 +1712,13 @@ def dm_crypt_handler(info, storage_config, context):
50
51 util.subp(cmd)
52
53+ if open_dmcrypt:
54 cmd = ["cryptsetup", "open", "--type", luks_type, volume_path, dm_name,
55 "--key-file", keyfile]
56
57 util.subp(cmd)
58
59- if keyfile_is_tmp:
60+ if remove_keyfile:
61 os.remove(keyfile)
62
63 wipe_mode = info.get('wipe')
64diff --git a/tests/integration/test_block_meta.py b/tests/integration/test_block_meta.py
65index 568f466..2fc7c7d 100644
66--- a/tests/integration/test_block_meta.py
67+++ b/tests/integration/test_block_meta.py
68@@ -1327,6 +1327,13 @@ table-length: 256'''.encode()
69 self.assertEqual("/dev/urandom", tokens[2])
70 self.assertEqual("swap,initramfs", tokens[3])
71
72+ cmd = ["cryptsetup", "status", cryptoswap]
73+ status = util.subp(cmd, capture=True)[0]
74+ for line in status.splitlines():
75+ key, _, value = line.strip().partition(':')
76+ if key == "type":
77+ self.assertEqual("PLAIN", value.strip())
78+
79 @parameterized.expand(((1,), (2,)))
80 def test_msftres(self, sv):
81 self.img = self.tmp_path('image.img')
82diff --git a/tests/unittests/test_commands_block_meta.py b/tests/unittests/test_commands_block_meta.py
83index c2d592d..727fba5 100644
84--- a/tests/unittests/test_commands_block_meta.py
85+++ b/tests/unittests/test_commands_block_meta.py
86@@ -2413,6 +2413,108 @@ class TestDmCryptHandler(DmCryptCommon):
87 info, self.storage_config, empty_context)
88
89
90+class TestDmCryptKeyfileRemoval(DmCryptCommon):
91+ def setUp(self):
92+ super().setUp()
93+ self.tempkey = self.tmp_path('test_dm_crypt_key')
94+ basepath = 'curtin.commands.block_meta.'
95+ self.add_patch(basepath + 'os.remove', 'm_os_remove')
96+
97+ @patch('curtin.commands.block_meta.tempfile.mkstemp')
98+ def test_dm_crypt_removes_tmpfile_if_key(self, m_mkstemp):
99+ m_mkstemp.return_value = (None, self.tempkey)
100+ self.setUpStorageConfig({
101+ 'storage': {
102+ 'version': 1,
103+ 'config': [
104+ {'grub_device': True,
105+ 'id': 'sda',
106+ 'name': 'sda',
107+ 'path': '/wark/xxx',
108+ 'ptable': 'msdos',
109+ 'type': 'disk',
110+ 'wipe': 'superblock'},
111+ {'device': 'sda',
112+ 'id': 'sda-part1',
113+ 'name': 'sda-part1',
114+ 'number': 1,
115+ 'size': '511705088B',
116+ 'type': 'partition'},
117+ {'id': 'dmcrypt0',
118+ 'type': 'dm_crypt',
119+ 'dm_name': 'cryptroot',
120+ 'volume': 'sda-part1',
121+ 'key': 'passw0rd'},
122+ ],
123+ }
124+ })
125+ info = self.storage_config['dmcrypt0']
126+ block_meta.dm_crypt_handler(info, self.storage_config, empty_context)
127+ self.m_os_remove.assert_called_once_with(self.tempkey)
128+
129+ @patch('curtin.commands.block_meta.os.remove')
130+ def test_dm_crypt_not_remove_keyfile(self, m_os_remove):
131+ self.setUpStorageConfig({
132+ 'storage': {
133+ 'version': 1,
134+ 'config': [
135+ {'grub_device': True,
136+ 'id': 'sda',
137+ 'name': 'sda',
138+ 'path': '/wark/xxx',
139+ 'ptable': 'msdos',
140+ 'type': 'disk',
141+ 'wipe': 'superblock'},
142+ {'device': 'sda',
143+ 'id': 'sda-part1',
144+ 'name': 'sda-part1',
145+ 'number': 1,
146+ 'size': '511705088B',
147+ 'type': 'partition'},
148+ {'id': 'dmcrypt0',
149+ 'type': 'dm_crypt',
150+ 'dm_name': 'cryptroot',
151+ 'volume': 'sda-part1',
152+ 'keyfile': self.tempkey},
153+ ],
154+ }
155+ })
156+ info = self.storage_config['dmcrypt0']
157+ block_meta.dm_crypt_handler(info, self.storage_config, empty_context)
158+ self.m_os_remove.assert_not_called()
159+
160+ @patch('curtin.commands.block_meta.os.remove')
161+ def test_dm_crypt_not_remove_dev_random(self, m_os_remove):
162+ self.setUpStorageConfig({
163+ 'storage': {
164+ 'version': 1,
165+ 'config': [
166+ {'grub_device': True,
167+ 'id': 'sda',
168+ 'name': 'sda',
169+ 'path': '/wark/xxx',
170+ 'ptable': 'msdos',
171+ 'type': 'disk',
172+ 'wipe': 'superblock'},
173+ {'device': 'sda',
174+ 'id': 'sda-part1',
175+ 'name': 'sda-part1',
176+ 'number': 1,
177+ 'size': '511705088B',
178+ 'type': 'partition'},
179+ {'id': 'dmcrypt0',
180+ 'type': 'dm_crypt',
181+ 'dm_name': 'cryptroot',
182+ 'volume': 'sda-part1',
183+ 'keyfile': '/dev/random'},
184+ ],
185+ }
186+ })
187+ info = self.storage_config['dmcrypt0']
188+ block_meta.dm_crypt_handler(info, self.storage_config, empty_context)
189+ self.m_os_remove.assert_not_called()
190+
191+
192 class TestCrypttab(DmCryptCommon):
193
194 def test_multi_dm_crypt(self):

Subscribers

People subscribed via source and target branches