From a0f99ca404218f1da0820e55000531fe0c67f270 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Thu, 6 Mar 2025 14:41:16 +0100 Subject: [PATCH] crypto: Add a function to set persistent flags for LUKS This will be used to set the allow-discards flag on LUKS devices during installation by Blivet. --- configure.ac | 6 +++ src/lib/plugin_apis/crypto.api | 24 +++++++++++ src/plugins/crypto.c | 76 ++++++++++++++++++++++++++++++++++ src/plugins/crypto.h | 11 +++++ tests/crypto_test.py | 29 +++++++++++++ 5 files changed, 146 insertions(+) diff --git a/configure.ac b/configure.ac index 14d5974c..158b000f 100644 --- a/configure.ac +++ b/configure.ac @@ -226,6 +226,12 @@ AS_IF([test "x$with_crypto" != "xno"], [AC_DEFINE([LIBCRYPTSETUP_23])], []) AS_IF([$PKG_CONFIG --atleast-version=2.4.0 libcryptsetup], [AC_DEFINE([LIBCRYPTSETUP_24])], []) + AS_IF([$PKG_CONFIG --atleast-version=2.6.0 libcryptsetup], + [AC_DEFINE([LIBCRYPTSETUP_26])], []) + AS_IF([$PKG_CONFIG --atleast-version=2.7.0 libcryptsetup], + [AC_DEFINE([LIBCRYPTSETUP_27])], []) + AS_IF([$PKG_CONFIG --atleast-version=2.8.0 libcryptsetup], + [AC_DEFINE([LIBCRYPTSETUP_28])], []) AS_IF([test "x$with_escrow" != "xno"], [LIBBLOCKDEV_PKG_CHECK_MODULES([NSS], [nss >= 3.18.0]) LIBBLOCKDEV_CHECK_HEADER([volume_key/libvolume_key.h], [$GLIB_CFLAGS $NSS_CFLAGS], [libvolume_key.h not available])], diff --git a/src/lib/plugin_apis/crypto.api b/src/lib/plugin_apis/crypto.api index cf87979d..81087ce4 100644 --- a/src/lib/plugin_apis/crypto.api +++ b/src/lib/plugin_apis/crypto.api @@ -353,6 +353,16 @@ typedef enum { #define BD_CRYPTO_TYPE_LUKS_INFO (bd_crypto_luks_info_get_type ()) GType bd_crypto_luks_info_get_type(); +typedef enum { + BD_CRYPTO_LUKS_ACTIVATE_ALLOW_DISCARDS = 1 << 0, + BD_CRYPTO_LUKS_ACTIVATE_SAME_CPU_CRYPT = 1 << 1, + BD_CRYPTO_LUKS_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS = 1 << 2, + BD_CRYPTO_LUKS_ACTIVATE_NO_JOURNAL = 1 << 3, + BD_CRYPTO_LUKS_ACTIVATE_NO_READ_WORKQUEUE = 1 << 4, + BD_CRYPTO_LUKS_ACTIVATE_NO_WRITE_WORKQUEUE = 1 << 5, + BD_CRYPTO_LUKS_ACTIVATE_HIGH_PRIORITY = 1 << 6, +} BDCryptoLUKSPersistentFlags; + /** * BDCryptoLUKSInfo: * @version: LUKS version @@ -940,6 +950,20 @@ gboolean bd_crypto_luks_header_backup (const gchar *device, const gchar *backup_ */ gboolean bd_crypto_luks_header_restore (const gchar *device, const gchar *backup_file, GError **error); +/** + * bd_crypto_luks_set_persistent_flags: + * @device: a LUKS device to set the persistent flags on + * @flags: flags to set + * @error: (out) (optional): place to store error (if any) + * + * Note: This function is valid only for LUKS2. + * + * Returns: whether the given @flags were successfully set or not + * + * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_MODIFY + */ +gboolean bd_crypto_luks_set_persistent_flags (const gchar *device, BDCryptoLUKSPersistentFlags flags, GError **error); + /** * bd_crypto_luks_info: * @luks_device: a device to get information about diff --git a/src/plugins/crypto.c b/src/plugins/crypto.c index 2086209e..ed7c0c5a 100644 --- a/src/plugins/crypto.c +++ b/src/plugins/crypto.c @@ -1978,6 +1978,82 @@ gboolean bd_crypto_luks_header_restore (const gchar *device, const gchar *backup return TRUE; } +/** + * bd_crypto_luks_set_persistent_flags: + * @device: a LUKS device to set the persistent flags on + * @flags: flags to set + * @error: (out) (optional): place to store error (if any) + * + * Note: This function is valid only for LUKS2. + * + * Returns: whether the given @flags were successfully set or not + * + * Tech category: %BD_CRYPTO_TECH_LUKS-%BD_CRYPTO_TECH_MODE_MODIFY + */ +gboolean bd_crypto_luks_set_persistent_flags (const gchar *device, BDCryptoLUKSPersistentFlags flags, GError **error) { + struct crypt_device *cd = NULL; + gint ret = 0; + guint32 crypt_flags = 0; + + ret = crypt_init (&cd, device); + if (ret != 0) { + g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE, + "Failed to initialize device: %s", strerror_l (-ret, c_locale)); + return FALSE; + } + + ret = crypt_load (cd, CRYPT_LUKS, NULL); + if (ret != 0) { + g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE, + "Failed to load device: %s", strerror_l (-ret, c_locale)); + crypt_free (cd); + return FALSE; + } + + if (g_strcmp0 (crypt_get_type (cd), CRYPT_LUKS2) != 0) { + g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE, + "Persistent flags can be set only on LUKS v2"); + crypt_free (cd); + return FALSE; + } + + if (flags & BD_CRYPTO_LUKS_ACTIVATE_ALLOW_DISCARDS) + crypt_flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS; + if (flags & BD_CRYPTO_LUKS_ACTIVATE_SAME_CPU_CRYPT) + crypt_flags |= CRYPT_ACTIVATE_SAME_CPU_CRYPT; + if (flags & BD_CRYPTO_LUKS_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS) + crypt_flags |= CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS; + if (flags & BD_CRYPTO_LUKS_ACTIVATE_NO_JOURNAL) + crypt_flags |= CRYPT_ACTIVATE_NO_JOURNAL; + if (flags & BD_CRYPTO_LUKS_ACTIVATE_NO_READ_WORKQUEUE) + crypt_flags |= CRYPT_ACTIVATE_NO_READ_WORKQUEUE; + if (flags & BD_CRYPTO_LUKS_ACTIVATE_NO_WRITE_WORKQUEUE) + crypt_flags |= CRYPT_ACTIVATE_NO_WRITE_WORKQUEUE; + if (flags & BD_CRYPTO_LUKS_ACTIVATE_HIGH_PRIORITY) { +#ifdef LIBCRYPTSETUP_28 + crypt_flags |= CRYPT_ACTIVATE_HIGH_PRIORITY; +#else + g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_TECH_UNAVAIL, + "Libcryptsetup 2.8 or newer is needed for 'high priority' flag support"); + crypt_free (cd); + return FALSE; +#endif + } + + + ret = crypt_persistent_flags_set (cd, CRYPT_FLAGS_ACTIVATION, crypt_flags); + if (ret != 0) { + g_set_error (error, BD_CRYPTO_ERROR, BD_CRYPTO_ERROR_DEVICE, + "Failed to set flags: %s", strerror_l (-ret, c_locale)); + crypt_free (cd); + return FALSE; + } + + crypt_free (cd); + + return TRUE; +} + /** * bd_crypto_luks_info: * @luks_device: a device to get information about diff --git a/src/plugins/crypto.h b/src/plugins/crypto.h index 536accf9..15acd4e6 100644 --- a/src/plugins/crypto.h +++ b/src/plugins/crypto.h @@ -155,6 +155,16 @@ typedef enum { BD_CRYPTO_INTEGRITY_OPEN_ALLOW_DISCARDS = 1 << 5, } BDCryptoIntegrityOpenFlags; +typedef enum { + BD_CRYPTO_LUKS_ACTIVATE_ALLOW_DISCARDS = 1 << 0, + BD_CRYPTO_LUKS_ACTIVATE_SAME_CPU_CRYPT = 1 << 1, + BD_CRYPTO_LUKS_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS = 1 << 2, + BD_CRYPTO_LUKS_ACTIVATE_NO_JOURNAL = 1 << 3, + BD_CRYPTO_LUKS_ACTIVATE_NO_READ_WORKQUEUE = 1 << 4, + BD_CRYPTO_LUKS_ACTIVATE_NO_WRITE_WORKQUEUE = 1 << 5, + BD_CRYPTO_LUKS_ACTIVATE_HIGH_PRIORITY = 1 << 6, +} BDCryptoLUKSPersistentFlags; + /** * BDCryptoLUKSInfo: * @version: LUKS version @@ -244,6 +254,7 @@ gboolean bd_crypto_luks_resume (const gchar *luks_device, const gchar *passphras gboolean bd_crypto_luks_kill_slot (const gchar *device, gint slot, GError **error); gboolean bd_crypto_luks_header_backup (const gchar *device, const gchar *backup_file, GError **error); gboolean bd_crypto_luks_header_restore (const gchar *device, const gchar *backup_file, GError **error); +gboolean bd_crypto_luks_set_persistent_flags (const gchar *device, BDCryptoLUKSPersistentFlags flags, GError **error); BDCryptoLUKSInfo* bd_crypto_luks_info (const gchar *luks_device, GError **error); BDCryptoIntegrityInfo* bd_crypto_integrity_info (const gchar *device, GError **error); diff --git a/tests/crypto_test.py b/tests/crypto_test.py index 91ea1f35..b16e719d 100644 --- a/tests/crypto_test.py +++ b/tests/crypto_test.py @@ -978,6 +978,35 @@ class CryptoTestInfo(CryptoTestCase): self.assertTrue(succ) +class CryptoTestSetPersistentFlags(CryptoTestCase): + + @tag_test(TestTags.SLOW, TestTags.CORE) + def test_luks_set_persistent_flags(self): + """Verify that we can set flags on a LUKS device""" + + self._luks_format(self.loop_dev, PASSWD, None) + + with self.assertRaisesRegex(GLib.GError, "Persistent flags can be set only on LUKS v2"): + BlockDev.crypto_luks_set_persistent_flags(self.loop_dev, + BlockDev.CryptoLUKSPersistentFlags.ALLOW_DISCARDS) + + @tag_test(TestTags.SLOW, TestTags.CORE) + def test_luks_set_persistent_flags(self): + """Verify that we can set flags on a LUKS 2 device""" + + self._luks2_format(self.loop_dev, PASSWD, None) + + succ = BlockDev.crypto_luks_set_persistent_flags(self.loop_dev, + BlockDev.CryptoLUKSPersistentFlags.ALLOW_DISCARDS) + self.assertTrue(succ) + + _ret, out, err = run_command("cryptsetup luksDump %s" % self.loop_dev) + m = re.search(r"Flags:\s*(\S+)\s*", out) + if not m or len(m.groups()) != 1: + self.fail("Failed to get label information from:\n%s %s" % (out, err)) + self.assertEqual(m.group(1), "allow-discards") + + class CryptoTestLuksSectorSize(CryptoTestCase): def setUp(self): if not check_cryptsetup_version("2.4.0"): -- 2.48.1