Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core: Add Encrypted.Convert method #1270

Merged
merged 1 commit into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions data/org.freedesktop.UDisks2.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2975,6 +2975,21 @@
<arg name="options" direction="in" type="a{sv}"/>
</method>


<!--
Convert:
@target_version: The LUKS version to convert to. Either 'luks1' or 'luks2'.
@options: Options (currently unused except for <link linkend="udisks-std-options">standard options</link>).
@since: 2.11.0

Converts the encrypted device to a different version of LUKS. Other encryption formats are not supported.
The device must be locked.
-->
<method name="Convert">
<arg name="target_version" direction="in" type="s"/>
<arg name="options" direction="in" type="a{sv}"/>
</method>

</interface>

<!-- ********************************************************************** -->
Expand Down Expand Up @@ -3396,6 +3411,8 @@
<listitem><para>Modifying encrypted device.</para></listitem></varlistentry>
<varlistentry><term>encrypted-resize</term>
<listitem><para>Resizing encrypted device.</para></listitem></varlistentry>
<varlistentry><term>encrypted-convert</term>
<listitem><para>Converting encrypted device.</para></listitem></varlistentry>
<varlistentry><term>swapspace-start</term>
<listitem><para>Starting swapspace.</para></listitem></varlistentry>
<varlistentry><term>swapspace-stop</term>
Expand Down
4 changes: 4 additions & 0 deletions doc/udisks2-sections.txt.in.in
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,10 @@ udisks_encrypted_call_resize
udisks_encrypted_call_resize_finish
udisks_encrypted_call_resize_sync
udisks_encrypted_complete_resize
udisks_encrypted_call_convert
udisks_encrypted_call_convert_finish
udisks_encrypted_call_convert_sync
udisks_encrypted_complete_convert
UDisksEncryptedProxy
UDisksEncryptedProxyClass
udisks_encrypted_proxy_new
Expand Down
50 changes: 50 additions & 0 deletions src/tests/dbus-tests/test_70_encrypted.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ def _get_blkid_version():
raise RuntimeError('Failed to determine blkid version from: %s' % out)
return Version(m.groups()[0])

def _get_luks_version(disk):
ret, out = udiskstestcase.UdisksTestCase.run_command("cryptsetup luksDump %s" % disk)
m = re.search(r'Version:\s*([1-2])', out)
if not m or len(m.groups()) != 1:
raise RuntimeError('Failed to determine LUKS version of device: %s.' % disk)
return int(m.groups()[0])


class UdisksEncryptedTest(udiskstestcase.UdisksTestCase):
'''This is an encrypted device test suite'''
Expand Down Expand Up @@ -449,6 +456,24 @@ def _get_metadata_size_from_dump(self, disk):
# offset value is in 512B blocks; we need to multiply to get the real metadata size
return int(m.group(1)) * 512

def test_convert(self):
disk = self.vdevs[0]
device = self.get_device(disk)
self._create_luks(device, self.PASSPHRASE)
self.assertEqual(1, _get_luks_version(disk))

self.addCleanup(self._remove_luks, device)
self.udev_settle()
device.Lock(self.no_options, dbus_interface=self.iface_prefix + '.Encrypted')

device.Convert("luks2", self.no_options,
dbus_interface=self.iface_prefix + '.Encrypted')
self.assertEqual(2, _get_luks_version(disk))

device.Convert("luks1", self.no_options,
dbus_interface=self.iface_prefix + '.Encrypted')
self.assertEqual(1, _get_luks_version(disk))

class UdisksEncryptedTestLUKS2(UdisksEncryptedTest):
'''This is a LUKS2 encrypted device test suite'''

Expand Down Expand Up @@ -559,6 +584,31 @@ def test_resize(self):
clear_size3 = self.get_block_size(clear_dev)
self.assertEqual(clear_size3, clear_size)

def test_convert_xfail(self):
disk = self.vdevs[0]
device = self.get_device(disk)
self._create_luks(device, self.PASSPHRASE)
self.assertEqual(2, _get_luks_version(disk))

self.addCleanup(self._remove_luks, device)
self.udev_settle()
device.Lock(self.no_options, dbus_interface=self.iface_prefix + '.Encrypted')

# check that the device is not LUKS1 compatible
ret, out = udiskstestcase.UdisksTestCase.run_command("cryptsetup luksDump %s" % disk)
m = re.search(r'PBKDF:\s*(.*)', out)
if not m or len(m.groups()) != 1:
raise RuntimeError('Failed to determine PBKDF of LUKS device: %s.' % disk)
self.assertEqual("argon2id", m.groups()[0])

# check that conversion fails
msg = 'org.freedesktop.UDisks2.Error.Failed: Error converting encrypted device /dev/.+: Conversion failed: Invalid argument'
with self.assertRaisesRegex(dbus.exceptions.DBusException, msg):
device.Convert("luks1", self.no_options,
dbus_interface=self.iface_prefix + '.Encrypted')

self.assertEqual(2, _get_luks_version(disk))

def _get_default_luks_version(self):
manager = self.get_object('/Manager')
default_encryption_type = self.get_property(manager, '.Manager', 'DefaultEncryptionType')
Expand Down
137 changes: 137 additions & 0 deletions src/udiskslinuxencrypted.c
Original file line number Diff line number Diff line change
Expand Up @@ -1194,11 +1194,148 @@ handle_resize (UDisksEncrypted *encrypted,

/* ---------------------------------------------------------------------------------------------------- */

/* runs in thread dedicated to handling method call */
static gboolean
handle_convert (UDisksEncrypted *encrypted,
GDBusMethodInvocation *invocation,
const gchar *target_version,
GVariant *options)
{
UDisksObject *object = NULL;
UDisksBlock *block;
UDisksDaemon *daemon;
UDisksState *state = NULL;
uid_t caller_uid;
const gchar *action_id = NULL;
const gchar *message = NULL;
GError *error = NULL;
UDisksBaseJob *job = NULL;
BDCryptoLUKSVersion bd_target_version;

object = udisks_daemon_util_dup_object (encrypted, &error);
if (object == NULL)
{
g_dbus_method_invocation_return_gerror (invocation, error);
goto out;
}

block = udisks_object_peek_block (object);
daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
state = udisks_daemon_get_state (daemon);

udisks_linux_block_object_lock_for_cleanup (UDISKS_LINUX_BLOCK_OBJECT (object));
udisks_state_check_block (state, udisks_linux_block_object_get_device_number (UDISKS_LINUX_BLOCK_OBJECT (object)));

/* Fail if the device is not a LUKS device */
if (!(g_strcmp0 (udisks_block_get_id_usage (block), "crypto") == 0 &&
g_strcmp0 (udisks_block_get_id_type (block), "crypto_LUKS") == 0))
{
g_dbus_method_invocation_return_error (invocation,
UDISKS_ERROR,
UDISKS_ERROR_FAILED,
"Device %s does not appear to be a LUKS device",
udisks_block_get_device (block));
goto out;
}

if (!udisks_daemon_util_get_caller_uid_sync (daemon, invocation, NULL /* GCancellable */, &caller_uid, &error))
{
g_dbus_method_invocation_return_gerror (invocation, error);
goto out;
}

action_id = "org.freedesktop.udisks2.modify-device";
/* Translators: Shown in authentication dialog when the user
* requests conversion of an encrypted block device.
*
* Do not translate $(drive), it's a placeholder and
* will be replaced by the name of the drive/device in question
*/
message = N_("Authentication is required to convert device $(drive) to a different LUKS version.");
if (! udisks_daemon_util_setup_by_user (daemon, object, caller_uid))
{
if (udisks_block_get_hint_system (block))
{
action_id = "org.freedesktop.udisks2.modify-device-system";
}
else if (! udisks_daemon_util_on_user_seat (daemon, UDISKS_OBJECT (object), caller_uid))
{
action_id = "org.freedesktop.udisks2.modify-device-other-seat";
}
}

/* Check that the user is actually authorized to convert the device. */
if (! udisks_daemon_util_check_authorization_sync (daemon,
object,
action_id,
options,
message,
invocation))
goto out;

if (g_strcmp0 (target_version, "luks1") == 0) {
bd_target_version = BD_CRYPTO_LUKS_VERSION_LUKS1;
} else if (g_strcmp0 (target_version, "luks2") == 0) {
bd_target_version = BD_CRYPTO_LUKS_VERSION_LUKS2;
} else {
g_dbus_method_invocation_return_error (invocation, UDISKS_ERROR, UDISKS_ERROR_FAILED,
"Unsupported target LUKS version: '%s'. Only 'luks1' and 'luks2' are supported.",
target_version);
goto out;
}

job = udisks_daemon_launch_simple_job (daemon,
UDISKS_OBJECT (object),
"encrypted-convert",
caller_uid,
NULL);
if (job == NULL)
{
g_dbus_method_invocation_return_error (invocation, UDISKS_ERROR, UDISKS_ERROR_FAILED,
"Failed to create a job object");
goto out;
}

udisks_linux_block_encrypted_lock (block);

if (! bd_crypto_luks_convert (udisks_block_get_device (block),
bd_target_version,
&error))
{
g_dbus_method_invocation_return_error (invocation,
UDISKS_ERROR,
UDISKS_ERROR_FAILED,
"Error converting encrypted device %s: %s",
udisks_block_get_device (block),
error->message);
udisks_simple_job_complete (UDISKS_SIMPLE_JOB (job), FALSE, error->message);
udisks_linux_block_encrypted_unlock (block);
goto out;
}

udisks_linux_block_encrypted_unlock (block);

udisks_encrypted_complete_convert (encrypted, invocation);
udisks_simple_job_complete (UDISKS_SIMPLE_JOB (job), TRUE, NULL);

out:
if (object != NULL)
udisks_linux_block_object_release_cleanup_lock (UDISKS_LINUX_BLOCK_OBJECT (object));
if (state != NULL)
udisks_state_check (state);
g_clear_object (&object);
g_clear_error (&error);
return TRUE; /* returning TRUE means that we handled the method invocation */
}

/* ---------------------------------------------------------------------------------------------------- */

static void
encrypted_iface_init (UDisksEncryptedIface *iface)
{
iface->handle_unlock = handle_unlock;
iface->handle_lock = handle_lock;
iface->handle_change_passphrase = handle_change_passphrase;
iface->handle_resize = handle_resize;
iface->handle_convert = handle_convert;
}
1 change: 1 addition & 0 deletions udisks/udisksclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -2734,6 +2734,7 @@ udisks_client_get_job_description_from_operation (const gchar *operation)
g_hash_table_insert (hash, (gpointer) "encrypted-lock", (gpointer) C_("job", "Locking Device"));
g_hash_table_insert (hash, (gpointer) "encrypted-modify", (gpointer) C_("job", "Modifying Encrypted Device"));
g_hash_table_insert (hash, (gpointer) "encrypted-resize", (gpointer) C_("job", "Resizing Encrypted Device"));
g_hash_table_insert (hash, (gpointer) "encrypted-convert", (gpointer) C_("job", "Converting Encrypted Device"));
g_hash_table_insert (hash, (gpointer) "swapspace-start", (gpointer) C_("job", "Starting Swap Device"));
g_hash_table_insert (hash, (gpointer) "swapspace-stop", (gpointer) C_("job", "Stopping Swap Device"));
g_hash_table_insert (hash, (gpointer) "swapspace-modify", (gpointer) C_("job", "Modifying Swap Device"));
Expand Down