summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaan De Meyer <daan.j.demeyer@gmail.com>2022-10-09 20:46:59 +0200
committerDaan De Meyer <daan.j.demeyer@gmail.com>2022-11-15 20:07:54 +0100
commit48a09a8fff480aab9a68e95e95cc37f6b1438751 (patch)
treee6fcc7e9f49fd5c37ed9b73f2e885415336234c3
parent98e0456ec04c2b210291f41f6d8f8527263e0c67 (diff)
downloadsystemd-48a09a8fff480aab9a68e95e95cc37f6b1438751.tar.gz
repart: Do offline encryption instead of online
Offline encryption can be done without mounting the luks device. For now we still use loop devices to split out the partition we want to write to but in a later commit we'll replace this with a regular file. For offline encryption, we need to keep 2x the luks header size space free at the end of the partition, so this means our encrypted partitions will be 16M larger than before.
-rw-r--r--meson.build5
-rw-r--r--src/partition/repart.c266
-rw-r--r--src/shared/cryptsetup-util.c26
-rw-r--r--src/shared/cryptsetup-util.h12
4 files changed, 165 insertions, 144 deletions
diff --git a/meson.build b/meson.build
index 2d41ff8799..55ed968798 100644
--- a/meson.build
+++ b/meson.build
@@ -1325,7 +1325,10 @@ if want_libcryptsetup != 'false' and not skip_deps
foreach ident : ['crypt_set_metadata_size',
'crypt_activate_by_signed_key',
- 'crypt_token_max']
+ 'crypt_token_max',
+ 'crypt_reencrypt_init_by_passphrase',
+ 'crypt_reencrypt',
+ 'crypt_set_data_offset']
have_ident = have and cc.has_function(
ident,
prefix : '#include <libcryptsetup.h>',
diff --git a/src/partition/repart.c b/src/partition/repart.c
index edc085dc15..1ecfc6b8fd 100644
--- a/src/partition/repart.c
+++ b/src/partition/repart.c
@@ -90,6 +90,9 @@
/* LUKS2 takes off 16M of the partition size with its metadata by default */
#define LUKS2_METADATA_SIZE (16ULL*1024ULL*1024ULL)
+/* To do LUKS2 offline encryption, we need to keep some extra free space at the end of the partition. */
+#define LUKS2_METADATA_KEEP_FREE (LUKS2_METADATA_SIZE*2ULL)
+
/* LUKS2 volume key size. */
#define VOLUME_KEY_SIZE (512ULL/8ULL)
@@ -274,12 +277,7 @@ static const char *verity_mode_table[_VERITY_MODE_MAX] = {
[VERITY_SIG] = "signature",
};
-#if HAVE_LIBCRYPTSETUP
-DEFINE_PRIVATE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(encrypt_mode, EncryptMode, ENCRYPT_KEY_FILE);
-#else
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(encrypt_mode, EncryptMode, ENCRYPT_KEY_FILE);
-#endif
-
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(verity_mode, VerityMode);
static uint64_t round_down_size(uint64_t v, uint64_t p) {
@@ -566,7 +564,7 @@ static uint64_t partition_min_size(const Context *context, const Partition *p) {
uint64_t d = 0;
if (p->encrypt != ENCRYPT_OFF)
- d += round_up_size(LUKS2_METADATA_SIZE, context->grain_size);
+ d += round_up_size(LUKS2_METADATA_KEEP_FREE, context->grain_size);
if (p->copy_blocks_size != UINT64_MAX)
d += round_up_size(p->copy_blocks_size, context->grain_size);
@@ -2985,16 +2983,27 @@ static int context_wipe_and_discard(Context *context, bool from_scratch) {
return 0;
}
-static int partition_encrypt(
- Context *context,
- Partition *p,
- const char *node,
- struct crypt_device **ret_cd,
- char **ret_volume,
- int *ret_fd) {
-#if HAVE_LIBCRYPTSETUP
+static int partition_encrypt(Context *context, Partition *p, const char *node) {
+#if HAVE_LIBCRYPTSETUP && HAVE_CRYPT_SET_DATA_OFFSET && HAVE_CRYPT_REENCRYPT_INIT_BY_PASSPHRASE && HAVE_CRYPT_REENCRYPT
+ struct crypt_params_luks2 luks_params = {
+ .label = strempty(p->new_label),
+ .sector_size = context->sector_size,
+ .data_device = node,
+ };
+ struct crypt_params_reencrypt reencrypt_params = {
+ .mode = CRYPT_REENCRYPT_ENCRYPT,
+ .direction = CRYPT_REENCRYPT_BACKWARD,
+ .resilience = "datashift",
+ .data_shift = LUKS2_METADATA_SIZE / 512,
+ .luks2 = &luks_params,
+ .flags = CRYPT_REENCRYPT_INITIALIZE_ONLY|CRYPT_REENCRYPT_MOVE_FIRST_SEGMENT,
+ };
_cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
- _cleanup_free_ char *dm_name = NULL, *vol = NULL;
+ _cleanup_(erase_and_freep) char *base64_encoded = NULL;
+ _cleanup_fclose_ FILE *h = NULL;
+ _cleanup_free_ char *hp = NULL;
+ const char *passphrase = NULL;
+ size_t passphrase_size = 0;
sd_id128_t uuid;
int r;
@@ -3002,33 +3011,46 @@ static int partition_encrypt(
assert(p);
assert(p->encrypt != ENCRYPT_OFF);
- log_debug("Encryption mode for partition %" PRIu64 ": %s", p->partno, encrypt_mode_to_string(p->encrypt));
-
r = dlopen_cryptsetup();
if (r < 0)
return log_error_errno(r, "libcryptsetup not found, cannot encrypt: %m");
- if (asprintf(&dm_name, "luks-repart-%08" PRIx64, random_u64()) < 0)
- return log_oom();
-
- if (ret_volume) {
- vol = path_join("/dev/mapper/", dm_name);
- if (!vol)
- return log_oom();
- }
-
r = derive_uuid(p->new_uuid, "luks-uuid", &uuid);
if (r < 0)
return r;
log_info("Encrypting future partition %" PRIu64 "...", p->partno);
- r = sym_crypt_init(&cd, node);
+ r = fopen_temporary(NULL, &h, &hp);
if (r < 0)
- return log_error_errno(r, "Failed to allocate libcryptsetup context: %m");
+ return log_error_errno(r, "Failed to create temporary LUKS header file: %m");
+
+ /* Weird cryptsetup requirement which requires the header file to be the size of at least one sector. */
+ r = posix_fallocate(fileno(h), 0, context->sector_size);
+ if (r < 0)
+ return log_error_errno(r, "Failed to grow temporary LUKS header file: %m");
+
+ r = sym_crypt_init(&cd, hp);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate libcryptsetup context for %s: %m", hp);
cryptsetup_enable_logging(cd);
+ /* Disable kernel keyring usage by libcryptsetup as a workaround for
+ * https://gitlab.com/cryptsetup/cryptsetup/-/merge_requests/273. This makes sure that we can do
+ * offline encryption even when repart is running in a container. */
+ r = sym_crypt_volume_key_keyring(cd, false);
+ if (r < 0)
+ return log_error_errno(r, "Failed to disable kernel keyring: %m");
+
+ r = sym_crypt_metadata_locking(cd, false);
+ if (r < 0)
+ return log_error_errno(r, "Failed to disable metadata locking: %m");
+
+ r = sym_crypt_set_data_offset(cd, LUKS2_METADATA_SIZE / 512);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set data offset: %m");
+
r = sym_crypt_format(cd,
CRYPT_LUKS2,
"aes",
@@ -3036,10 +3058,7 @@ static int partition_encrypt(
SD_ID128_TO_UUID_STRING(uuid),
NULL,
VOLUME_KEY_SIZE,
- &(struct crypt_params_luks2) {
- .label = strempty(p->new_label),
- .sector_size = context->sector_size,
- });
+ &luks_params);
if (r < 0)
return log_error_errno(r, "Failed to LUKS2 format future partition: %m");
@@ -3053,11 +3072,13 @@ static int partition_encrypt(
arg_key_size);
if (r < 0)
return log_error_errno(r, "Failed to add LUKS2 key: %m");
+
+ passphrase = strempty(arg_key);
+ passphrase_size = arg_key_size;
}
if (IN_SET(p->encrypt, ENCRYPT_TPM2, ENCRYPT_KEY_FILE_TPM2)) {
#if HAVE_TPM2
- _cleanup_(erase_and_freep) char *base64_encoded = NULL;
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
_cleanup_(erase_and_freep) void *secret = NULL;
_cleanup_free_ void *pubkey = NULL;
@@ -3106,7 +3127,7 @@ static int partition_encrypt(
base64_encoded,
strlen(base64_encoded));
if (keyslot < 0)
- return log_error_errno(keyslot, "Failed to add new TPM2 key to %s: %m", node);
+ return log_error_errno(keyslot, "Failed to add new TPM2 key: %m");
r = tpm2_make_luks2_json(
keyslot,
@@ -3125,63 +3146,67 @@ static int partition_encrypt(
r = cryptsetup_add_token_json(cd, v);
if (r < 0)
return log_error_errno(r, "Failed to add TPM2 JSON token to LUKS2 header: %m");
+
+ passphrase = base64_encoded;
+ passphrase_size = strlen(base64_encoded);
#else
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
"Support for TPM2 enrollment not enabled.");
#endif
}
- r = sym_crypt_activate_by_volume_key(
+ r = sym_crypt_reencrypt_init_by_passphrase(
cd,
- dm_name,
NULL,
- VOLUME_KEY_SIZE,
- arg_discard ? CRYPT_ACTIVATE_ALLOW_DISCARDS : 0);
+ passphrase,
+ passphrase_size,
+ CRYPT_ANY_SLOT,
+ 0,
+ sym_crypt_get_cipher(cd),
+ sym_crypt_get_cipher_mode(cd),
+ &reencrypt_params);
if (r < 0)
- return log_error_errno(r, "Failed to activate LUKS superblock: %m");
+ return log_error_errno(r, "Failed to prepare for reencryption: %m");
- log_info("Successfully encrypted future partition %" PRIu64 ".", p->partno);
+ /* crypt_reencrypt_init_by_passphrase() doesn't actually put the LUKS header at the front, we have
+ * to do that ourselves. */
- if (ret_fd) {
- _cleanup_close_ int dev_fd = -1;
+ sym_crypt_free(cd);
+ cd = NULL;
- dev_fd = open(vol, O_RDWR|O_CLOEXEC|O_NOCTTY);
- if (dev_fd < 0)
- return log_error_errno(errno, "Failed to open LUKS volume '%s': %m", vol);
-
- *ret_fd = TAKE_FD(dev_fd);
- }
-
- if (ret_cd)
- *ret_cd = TAKE_PTR(cd);
- if (ret_volume)
- *ret_volume = TAKE_PTR(vol);
-
- return 0;
-#else
- return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "libcryptsetup is not supported, cannot encrypt: %m");
-#endif
-}
-
-static int deactivate_luks(struct crypt_device *cd, const char *node) {
-#if HAVE_LIBCRYPTSETUP
- int r;
+ r = sym_crypt_init(&cd, node);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate libcryptsetup context for %s: %m", node);
- if (!cd)
- return 0;
+ r = sym_crypt_header_restore(cd, CRYPT_LUKS2, hp);
+ if (r < 0)
+ return log_error_errno(r, "Failed to place new LUKS header at head of %s: %m", node);
- assert(node);
+ reencrypt_params.flags &= ~CRYPT_REENCRYPT_INITIALIZE_ONLY;
- /* udev or so might access out block device in the background while we are done. Let's hence force
- * detach the volume. We sync'ed before, hence this should be safe. */
+ r = sym_crypt_reencrypt_init_by_passphrase(
+ cd,
+ NULL,
+ passphrase,
+ passphrase_size,
+ CRYPT_ANY_SLOT,
+ 0,
+ NULL,
+ NULL,
+ &reencrypt_params);
+ if (r < 0)
+ return log_error_errno(r, "Failed to load reencryption context: %m");
- r = sym_crypt_deactivate_by_name(cd, basename(node), CRYPT_DEACTIVATE_FORCE);
+ r = sym_crypt_reencrypt(cd, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to deactivate LUKS device: %m");
+ return log_error_errno(r, "Failed to encrypt %s: %m", node);
+
+ log_info("Successfully encrypted future partition %" PRIu64 ".", p->partno);
- return 1;
-#else
return 0;
+#else
+ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+ "libcryptsetup is not supported or is missing required symbols, cannot encrypt: %m");
#endif
}
@@ -3193,10 +3218,7 @@ static int context_copy_blocks(Context *context) {
/* Copy in file systems on the block level */
LIST_FOREACH(partitions, p, context->partitions) {
- _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
- _cleanup_free_ char *encrypted = NULL;
- _cleanup_close_ int encrypted_dev_fd = -1;
int target_fd;
if (p->copy_blocks_fd < 0)
@@ -3213,7 +3235,7 @@ static int context_copy_blocks(Context *context) {
assert(p->new_size != UINT64_MAX);
assert(p->copy_blocks_size != UINT64_MAX);
- assert(p->new_size >= p->copy_blocks_size);
+ assert(p->new_size >= p->copy_blocks_size + (p->encrypt != ENCRYPT_OFF ? LUKS2_METADATA_KEEP_FREE : 0));
if (whole_fd < 0)
assert_se((whole_fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
@@ -3223,14 +3245,7 @@ static int context_copy_blocks(Context *context) {
if (r < 0)
return log_error_errno(r, "Failed to make loopback device of future partition %" PRIu64 ": %m", p->partno);
- r = partition_encrypt(context, p, d->node, &cd, &encrypted, &encrypted_dev_fd);
- if (r < 0)
- return log_error_errno(r, "Failed to encrypt device: %m");
-
- if (flock(encrypted_dev_fd, LOCK_EX) < 0)
- return log_error_errno(errno, "Failed to lock LUKS device: %m");
-
- target_fd = encrypted_dev_fd;
+ target_fd = d->fd;
} else {
if (lseek(whole_fd, p->offset, SEEK_SET) == (off_t) -1)
return log_error_errno(errno, "Failed to seek to partition offset: %m");
@@ -3245,24 +3260,15 @@ static int context_copy_blocks(Context *context) {
if (r < 0)
return log_error_errno(r, "Failed to copy in data from '%s': %m", p->copy_blocks_path);
- if (fsync(target_fd) < 0)
- return log_error_errno(errno, "Failed to synchronize copied data blocks: %m");
-
if (p->encrypt != ENCRYPT_OFF) {
- encrypted_dev_fd = safe_close(encrypted_dev_fd);
-
- r = deactivate_luks(cd, encrypted);
+ r = partition_encrypt(context, p, d->node);
if (r < 0)
return r;
-
- sym_crypt_free(cd);
- cd = NULL;
-
- r = loop_device_sync(d);
- if (r < 0)
- return log_error_errno(r, "Failed to sync loopback device: %m");
}
+ if (fsync(target_fd) < 0)
+ return log_error_errno(errno, "Failed to synchronize copied data blocks: %m");
+
log_info("Copying in of '%s' on block level completed.", p->copy_blocks_path);
}
@@ -3541,12 +3547,9 @@ static int context_mkfs(Context *context) {
return r;
LIST_FOREACH(partitions, p, context->partitions) {
- _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
_cleanup_(rm_rf_physical_and_freep) char *tmp_root = NULL;
- _cleanup_free_ char *encrypted = NULL, *root = NULL;
- _cleanup_close_ int encrypted_dev_fd = -1;
- const char *fsdev;
+ _cleanup_free_ char *root = NULL;
if (p->dropped)
continue;
@@ -3566,29 +3569,22 @@ static int context_mkfs(Context *context) {
assert(p->offset != UINT64_MAX);
assert(p->new_size != UINT64_MAX);
+ assert(p->new_size >= (p->encrypt != ENCRYPT_OFF ? LUKS2_METADATA_KEEP_FREE : 0));
if (fd < 0)
assert_se((fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
/* Loopback block devices are not only useful to turn regular files into block devices, but
- * also to cut out sections of block devices into new block devices. */
+ * also to cut out sections of block devices into new block devices. If we're doing
+ * encryption, we make sure we keep free space at the end which is required for cryptsetup's
+ * offline encryption. */
- r = loop_device_make(fd, O_RDWR, p->offset, p->new_size, 0, 0, LOCK_EX, &d);
+ r = loop_device_make(fd, O_RDWR, p->offset,
+ p->new_size - (p->encrypt != ENCRYPT_OFF ? LUKS2_METADATA_KEEP_FREE : 0),
+ 0, 0, LOCK_EX, &d);
if (r < 0)
return log_error_errno(r, "Failed to make loopback device of future partition %" PRIu64 ": %m", p->partno);
- if (p->encrypt != ENCRYPT_OFF) {
- r = partition_encrypt(context, p, d->node, &cd, &encrypted, &encrypted_dev_fd);
- if (r < 0)
- return log_error_errno(r, "Failed to encrypt device: %m");
-
- if (flock(encrypted_dev_fd, LOCK_EX) < 0)
- return log_error_errno(errno, "Failed to lock LUKS device: %m");
-
- fsdev = encrypted;
- } else
- fsdev = d->node;
-
log_info("Formatting future partition %" PRIu64 ".", p->partno);
/* Ideally, we populate filesystems using our own code after creating the filesystem to
@@ -3603,47 +3599,33 @@ static int context_mkfs(Context *context) {
return r;
}
- r = make_filesystem(fsdev, p->format, strempty(p->new_label), root ?: tmp_root, p->fs_uuid, arg_discard);
- if (r < 0) {
- encrypted_dev_fd = safe_close(encrypted_dev_fd);
- (void) deactivate_luks(cd, encrypted);
+ r = make_filesystem(d->node, p->format, strempty(p->new_label), root ?: tmp_root, p->fs_uuid, arg_discard);
+ if (r < 0)
return r;
- }
log_info("Successfully formatted future partition %" PRIu64 ".", p->partno);
- /* The file system is now created, no need to delay udev further */
- if (p->encrypt != ENCRYPT_OFF)
- if (flock(encrypted_dev_fd, LOCK_UN) < 0)
- return log_error_errno(errno, "Failed to unlock LUKS device: %m");
-
/* Now, we can populate all the other filesystems that aren't read-only. */
if (!mkfs_supports_root_option(p->format)) {
- r = partition_populate_filesystem(p, fsdev, denylist);
- if (r < 0) {
- encrypted_dev_fd = safe_close(encrypted_dev_fd);
- (void) deactivate_luks(cd, encrypted);
+ r = partition_populate_filesystem(p, d->node, denylist);
+ if (r < 0)
return r;
- }
}
- /* Note that we always sync explicitly here, since mkfs.fat doesn't do that on its own, and
- * if we don't sync before detaching a block device the in-flight sectors possibly won't hit
- * the disk. */
-
if (p->encrypt != ENCRYPT_OFF) {
- if (fsync(encrypted_dev_fd) < 0)
- return log_error_errno(errno, "Failed to synchronize LUKS volume: %m");
- encrypted_dev_fd = safe_close(encrypted_dev_fd);
-
- r = deactivate_luks(cd, encrypted);
+ r = loop_device_refresh_size(d, UINT64_MAX, p->new_size);
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to refresh loopback device size: %m");
- sym_crypt_free(cd);
- cd = NULL;
+ r = partition_encrypt(context, p, d->node);
+ if (r < 0)
+ return log_error_errno(r, "Failed to encrypt device: %m");
}
+ /* Note that we always sync explicitly here, since mkfs.fat doesn't do that on its own, and
+ * if we don't sync before detaching a block device the in-flight sectors possibly won't hit
+ * the disk. */
+
r = loop_device_sync(d);
if (r < 0)
return log_error_errno(r, "Failed to sync loopback device: %m");
diff --git a/src/shared/cryptsetup-util.c b/src/shared/cryptsetup-util.c
index 401e7a3f9c..7437cbed6b 100644
--- a/src/shared/cryptsetup-util.c
+++ b/src/shared/cryptsetup-util.c
@@ -49,6 +49,18 @@ int (*sym_crypt_token_max)(const char *type);
#endif
crypt_token_info (*sym_crypt_token_status)(struct crypt_device *cd, int token, const char **type);
int (*sym_crypt_volume_key_get)(struct crypt_device *cd, int keyslot, char *volume_key, size_t *volume_key_size, const char *passphrase, size_t passphrase_size);
+#if HAVE_CRYPT_REENCRYPT_INIT_BY_PASSPHRASE
+int (*sym_crypt_reencrypt_init_by_passphrase)(struct crypt_device *cd, const char *name, const char *passphrase, size_t passphrase_size, int keyslot_old, int keyslot_new, const char *cipher, const char *cipher_mode, const struct crypt_params_reencrypt *params);
+#endif
+#if HAVE_CRYPT_REENCRYPT
+int (*sym_crypt_reencrypt)(struct crypt_device *cd, int (*progress)(uint64_t size, uint64_t offset, void *usrptr));
+#endif
+int (*sym_crypt_metadata_locking)(struct crypt_device *cd, int enable);
+#if HAVE_CRYPT_SET_DATA_OFFSET
+int (*sym_crypt_set_data_offset)(struct crypt_device *cd, uint64_t data_offset);
+#endif
+int (*sym_crypt_header_restore)(struct crypt_device *cd, const char *requested_type, const char *backup_file);
+int (*sym_crypt_volume_key_keyring)(struct crypt_device *cd, int enable);
static void cryptsetup_log_glue(int level, const char *msg, void *usrptr) {
@@ -234,7 +246,19 @@ int dlopen_cryptsetup(void) {
DLSYM_ARG(crypt_token_max),
#endif
DLSYM_ARG(crypt_token_status),
- DLSYM_ARG(crypt_volume_key_get));
+ DLSYM_ARG(crypt_volume_key_get),
+#if HAVE_CRYPT_REENCRYPT_INIT_BY_PASSPHRASE
+ DLSYM_ARG(crypt_reencrypt_init_by_passphrase),
+#endif
+#if HAVE_CRYPT_REENCRYPT
+ DLSYM_ARG(crypt_reencrypt),
+#endif
+ DLSYM_ARG(crypt_metadata_locking),
+#if HAVE_CRYPT_SET_DATA_OFFSET
+ DLSYM_ARG(crypt_set_data_offset),
+#endif
+ DLSYM_ARG(crypt_header_restore),
+ DLSYM_ARG(crypt_volume_key_keyring));
if (r <= 0)
return r;
diff --git a/src/shared/cryptsetup-util.h b/src/shared/cryptsetup-util.h
index b390dc9a5c..5ff439d9c2 100644
--- a/src/shared/cryptsetup-util.h
+++ b/src/shared/cryptsetup-util.h
@@ -64,6 +64,18 @@ static inline int crypt_token_max(_unused_ const char *type) {
#endif
extern crypt_token_info (*sym_crypt_token_status)(struct crypt_device *cd, int token, const char **type);
extern int (*sym_crypt_volume_key_get)(struct crypt_device *cd, int keyslot, char *volume_key, size_t *volume_key_size, const char *passphrase, size_t passphrase_size);
+#if HAVE_CRYPT_REENCRYPT_INIT_BY_PASSPHRASE
+extern int (*sym_crypt_reencrypt_init_by_passphrase)(struct crypt_device *cd, const char *name, const char *passphrase, size_t passphrase_size, int keyslot_old, int keyslot_new, const char *cipher, const char *cipher_mode, const struct crypt_params_reencrypt *params);
+#endif
+#if HAVE_CRYPT_REENCRYPT
+extern int (*sym_crypt_reencrypt)(struct crypt_device *cd, int (*progress)(uint64_t size, uint64_t offset, void *usrptr));
+#endif
+extern int (*sym_crypt_metadata_locking)(struct crypt_device *cd, int enable);
+#if HAVE_CRYPT_SET_DATA_OFFSET
+extern int (*sym_crypt_set_data_offset)(struct crypt_device *cd, uint64_t data_offset);
+#endif
+extern int (*sym_crypt_header_restore)(struct crypt_device *cd, const char *requested_type, const char *backup_file);
+extern int (*sym_crypt_volume_key_keyring)(struct crypt_device *cd, int enable);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct crypt_device *, crypt_free, NULL);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct crypt_device *, sym_crypt_free, NULL);