#if defined(HAVE_CRYPTSETUP)
+#ifdef CRYPTSETUP_VIA_DLOPEN
+#include <dlfcn.h>
+#endif
#include <libcryptsetup.h>
#include "path.h"
+#ifdef CRYPTSETUP_VIA_DLOPEN
+static void *get_symbol(struct libmnt_context *cxt, void *dl, const char *name, int *rc)
+{
+ char *dl_error = NULL;
+ void *sym = dlsym(dl, name);
+
+ *rc = 0;
+ if ((dl_error = dlerror()) == NULL)
+ return sym;
+
+ DBG(VERITY, ul_debugobj(cxt, "veritydev specific options detected but cannot dlopen symbol %s: %s", name, dl_error));
+ *rc = -ENOTSUP;
+
+ return NULL;
+}
+#endif
+
/* Taken from https://gitlab.com/cryptsetup/cryptsetup/blob/master/lib/utils_crypt.c#L225 */
static size_t crypt_hex_to_bytes(const char *hex, char **result)
{
/* Use the same default for FEC parity bytes as cryptsetup uses */
uint64_t offset = 0, fec_offset = 0, fec_roots = 2;
struct stat hash_sig_st;
+#ifdef CRYPTSETUP_VIA_DLOPEN
+ /* To avoid linking libmount to libcryptsetup, and keep the default dependencies list down, use dlopen */
+ void *dl = NULL;
+ int (*sym_crypt_init_data_device)(struct crypt_device **, const char *, const char *) = NULL;
+ int (*sym_crypt_load)(struct crypt_device *, const char *, void *) = NULL;
+ int (*sym_crypt_get_volume_key_size)(struct crypt_device *) = NULL;
+#ifdef HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
+ int (*sym_crypt_activate_by_signed_key)(struct crypt_device *, const char *, const char *, size_t, const char *, size_t, uint32_t) = NULL;
+#endif
+ int (*sym_crypt_activate_by_volume_key)(struct crypt_device *, const char *, const char *, size_t, uint32_t) = NULL;
+ void (*sym_crypt_free)(struct crypt_device *) = NULL;
+ int (*sym_crypt_init_by_name)(struct crypt_device **, const char *) = NULL;
+ int (*sym_crypt_get_verity_info)(struct crypt_device *, struct crypt_params_verity *) = NULL;
+ int (*sym_crypt_volume_key_get)(struct crypt_device *, int, char *, size_t *, const char *, size_t) = NULL;
+#else
+ int (*sym_crypt_init_data_device)(struct crypt_device **, const char *, const char *) = &crypt_init_data_device;
+ int (*sym_crypt_load)(struct crypt_device *, const char *, void *) = &crypt_load;
+ int (*sym_crypt_get_volume_key_size)(struct crypt_device *) = &crypt_get_volume_key_size;
+#ifdef HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
+ int (*sym_crypt_activate_by_signed_key)(struct crypt_device *, const char *, const char *, size_t, const char *, size_t, uint32_t) = &crypt_activate_by_signed_key;
+#endif
+ int (*sym_crypt_activate_by_volume_key)(struct crypt_device *, const char *, const char *, size_t, uint32_t) = &crypt_activate_by_volume_key;
+ void (*sym_crypt_free)(struct crypt_device *) = &crypt_free;
+ int (*sym_crypt_init_by_name)(struct crypt_device **, const char *) = &crypt_init_by_name;
+ int (*sym_crypt_get_verity_info)(struct crypt_device *, struct crypt_params_verity *) = &crypt_get_verity_info;
+ int (*sym_crypt_volume_key_get)(struct crypt_device *, int, char *, size_t *, const char *, size_t) = &crypt_volume_key_get;
+#endif
assert(cxt);
assert(cxt->fs);
rc = -EINVAL;
}
+#ifdef CRYPTSETUP_VIA_DLOPEN
+ if (rc == 0) {
+ int dl_flags = RTLD_LAZY | RTLD_LOCAL;
+ /* glibc extension: mnt_context_deferred_delete_veritydev is called immediately after, don't unload on dl_close */
+#ifdef RTLD_NODELETE
+ dl_flags |= RTLD_NODELETE;
+#endif
+ /* glibc extension: might help to avoid further symbols clashes */
+#ifdef RTLD_DEEPBIND
+ dl_flags |= RTLD_DEEPBIND;
+#endif
+ dl = dlopen("libcryptsetup.so.12", dl_flags);
+ if (!dl) {
+ DBG(VERITY, ul_debugobj(cxt, "veritydev specific options detected but cannot dlopen libcryptsetup"));
+ rc = -ENOTSUP;
+ }
+ }
+
+ /* clear errors first, then load all the libcryptsetup symbols */
+ dlerror();
+
+ if (rc == 0)
+ *(void **)(&sym_crypt_init_data_device) = get_symbol(cxt, dl, "crypt_init_data_device", &rc);
+
+ if (rc == 0)
+ *(void **)(&sym_crypt_load) = get_symbol(cxt, dl, "crypt_load", &rc);
+
+ if (rc == 0)
+ *(void **)(&sym_crypt_get_volume_key_size) = get_symbol(cxt, dl, "crypt_get_volume_key_size", &rc);
+
+#ifdef HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
+ if (rc == 0)
+ *(void **)(&sym_crypt_activate_by_signed_key) = get_symbol(cxt, dl, "crypt_activate_by_signed_key", &rc);
+#endif
+
+ if (rc == 0)
+ *(void **)(&sym_crypt_activate_by_volume_key) = get_symbol(cxt, dl, "crypt_activate_by_volume_key", &rc);
+
+ if (rc == 0)
+ *(void **)(&sym_crypt_free) = get_symbol(cxt, dl, "crypt_free", &rc);
+
+ if (rc == 0)
+ *(void **)(&sym_crypt_init_by_name) = get_symbol(cxt, dl, "crypt_init_by_name", &rc);
+
+ if (rc == 0)
+ *(void **)(&sym_crypt_get_verity_info) = get_symbol(cxt, dl, "crypt_get_verity_info", &rc);
+
+ if (rc == 0)
+ *(void **)(&sym_crypt_volume_key_get) = get_symbol(cxt, dl, "crypt_volume_key_get", &rc);
+#endif
+
if (rc)
goto done;
- rc = crypt_init_data_device(&crypt_dev, hash_device, backing_file);
+ rc = (*sym_crypt_init_data_device)(&crypt_dev, hash_device, backing_file);
if (rc)
goto done;
crypt_params.fec_roots = fec_roots;
crypt_params.fec_device = fec_device;
crypt_params.flags = 0;
- rc = crypt_load(crypt_dev, CRYPT_VERITY, &crypt_params);
+ rc = (*sym_crypt_load)(crypt_dev, CRYPT_VERITY, &crypt_params);
if (rc < 0)
goto done;
- hash_size = crypt_get_volume_key_size(crypt_dev);
+ hash_size = (*sym_crypt_get_volume_key_size)(crypt_dev);
if (crypt_hex_to_bytes(root_hash, &root_hash_binary) != hash_size) {
DBG(VERITY, ul_debugobj(cxt, "root hash %s is not of length %zu", root_hash, hash_size));
rc = -EINVAL;
}
if (hash_sig) {
#ifdef HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
- rc = crypt_activate_by_signed_key(crypt_dev, mapper_device, root_hash_binary, hash_size,
+ rc = (*sym_crypt_activate_by_signed_key)(crypt_dev, mapper_device, root_hash_binary, hash_size,
hash_sig, hash_sig_size, CRYPT_ACTIVATE_READONLY);
#else
rc = -EINVAL;
DBG(VERITY, ul_debugobj(cxt, "verity.roothashsig=%s passed but libcryptsetup does not provide crypt_activate_by_signed_key()", hash_sig));
#endif
} else
- rc = crypt_activate_by_volume_key(crypt_dev, mapper_device, root_hash_binary, hash_size,
+ rc = (*sym_crypt_activate_by_volume_key)(crypt_dev, mapper_device, root_hash_binary, hash_size,
CRYPT_ACTIVATE_READONLY);
/*
* If the mapper device already exists, and if libcryptsetup supports it, get the root
*/
if (rc == -EEXIST) {
DBG(VERITY, ul_debugobj(cxt, "%s already in use as /dev/mapper/%s", backing_file, mapper_device));
- crypt_free(crypt_dev);
- rc = crypt_init_by_name(&crypt_dev, mapper_device);
+ (*sym_crypt_free)(crypt_dev);
+ rc = (*sym_crypt_init_by_name)(&crypt_dev, mapper_device);
if (!rc) {
- rc = crypt_get_verity_info(crypt_dev, &crypt_params);
+ rc = (*sym_crypt_get_verity_info)(crypt_dev, &crypt_params);
if (!rc) {
key = calloc(hash_size, 1);
if (!key) {
}
if (!rc) {
keysize = hash_size;
- rc = crypt_volume_key_get(crypt_dev, CRYPT_ANY_SLOT, key, &keysize, NULL, 0);
+ rc = (*sym_crypt_volume_key_get)(crypt_dev, CRYPT_ANY_SLOT, key, &keysize, NULL, 0);
}
if (!rc) {
DBG(VERITY, ul_debugobj(cxt, "comparing root hash of existing device with %s", root_hash));
}
done:
- crypt_free(crypt_dev);
+ if (sym_crypt_free)
+ (*sym_crypt_free)(crypt_dev);
+#ifdef CRYPTSETUP_VIA_DLOPEN
+ if (dl)
+ dlclose(dl);
+#endif
free(root_hash_binary);
free(mapper_device_full);
free(mapper_device);
struct crypt_device *crypt_dev = NULL;
/* If mounting failed delete immediately, otherwise setup auto cleanup for user umount */
uint32_t flags = mnt_context_get_status(cxt) ? CRYPT_DEACTIVATE_DEFERRED : 0;
- int rc;
+#ifdef CRYPTSETUP_VIA_DLOPEN
+ void *dl = NULL;
+ int dl_flags = RTLD_LAZY | RTLD_LOCAL;
+ /* glibc extension: might help to avoid further symbols clashes */
+#ifdef RTLD_DEEPBIND
+ dl_flags |= RTLD_DEEPBIND;
+#endif
+ int (*sym_crypt_init_by_name)(struct crypt_device **, const char *) = NULL;
+ int (*sym_crypt_deactivate_by_name)(struct crypt_device *, const char *, uint32_t) = NULL;
+ void (*sym_crypt_free)(struct crypt_device *) = NULL;
+#else
+ int (*sym_crypt_init_by_name)(struct crypt_device **, const char *) = &crypt_init_by_name;
+ int (*sym_crypt_deactivate_by_name)(struct crypt_device *, const char *, uint32_t) = &crypt_deactivate_by_name;
+ void (*sym_crypt_free)(struct crypt_device *) = &crypt_free;
+#endif
+ int rc = 0;
assert(cxt);
assert(cxt->fs);
if (!src)
return -EINVAL;
- rc = crypt_init_by_name(&crypt_dev, src);
+#ifdef CRYPTSETUP_VIA_DLOPEN
+ dl = dlopen("libcryptsetup.so.12", dl_flags);
+ if (!dl) {
+ DBG(VERITY, ul_debugobj(cxt, "veritydev specific options detected but cannot dlopen libcryptsetup"));
+ return -ENOTSUP;
+ }
+
+ /* clear errors first */
+ dlerror();
+
+ if (!rc)
+ *(void **)(&sym_crypt_init_by_name) = get_symbol(cxt, dl, "crypt_init_by_name", &rc);
+ if (!rc)
+ *(void **)(&sym_crypt_deactivate_by_name) = get_symbol(cxt, dl, "crypt_deactivate_by_name", &rc);
+ if (!rc)
+ *(void **)(&sym_crypt_free) = get_symbol(cxt, dl, "crypt_free", &rc);
+#endif
+
if (!rc) {
- rc = crypt_deactivate_by_name(crypt_dev, src, flags);
- if (!rc)
- cxt->flags &= ~MNT_FL_VERITYDEV_READY;
+ rc = (*sym_crypt_init_by_name)(&crypt_dev, src);
+ if (!rc) {
+ rc = (*sym_crypt_deactivate_by_name)(crypt_dev, src, flags);
+ if (!rc)
+ cxt->flags &= ~MNT_FL_VERITYDEV_READY;
+ }
+
+ (*sym_crypt_free)(crypt_dev);
}
- crypt_free(crypt_dev);
+#ifdef CRYPTSETUP_VIA_DLOPEN
+ dlclose(dl);
+#endif
DBG(VERITY, ul_debugobj(cxt, "deleted [rc=%d]", rc));