#include "mountP.h"
-#if defined(HAVE_CRYPTSETUP)
+#ifdef HAVE_CRYPTSETUP
-#ifdef CRYPTSETUP_VIA_DLOPEN
-#include <dlfcn.h>
-#endif
#include <libcryptsetup.h>
#include "path.h"
#include "strutils.h"
+#include "fileutils.h"
+#include "pathnames.h"
#ifdef CRYPTSETUP_VIA_DLOPEN
+# include <dlfcn.h>
+
+/* Pointers to libcryptsetup functions (initiliazed by dlsym()) */
struct verity_opers {
void (*crypt_set_debug_level)(int);
void (*crypt_set_log_callback)(struct crypt_device *, void (*log)(int, const char *, void *), void *);
int (*crypt_deactivate_by_name)(struct crypt_device *, const char *, uint32_t);
};
-/* symbols for dlopen() */
+/* libcryptsetup functions names and offsets in 'struct verity_opers' */
struct verity_sym {
const char *name;
size_t offset; /* offset of the symbol in verity_opers */
.offset = offsetof(struct verity_opers, _name), \
}
+/* All required symbols */
static const struct verity_sym verity_symbols[] =
{
DEF_VERITY_SYM( crypt_set_debug_level ),
DEF_VERITY_SYM( crypt_deactivate_by_name ),
};
+#endif /* CRYPTSETUP_VIA_DLOPEN */
+
+
+/* Data used by all verity hooks */
+struct hookset_data {
+ char *devname; /* the device */
+#ifdef CRYPTSETUP_VIA_DLOPEN
+ void *dl; /* dlopen() */
+ struct verity_opers dl_funcs; /* dlsym() */
+#endif
+};
+
+/* libcryptsetup call -- dlopen version requires 'struct hookset_data *hsd' */
+#ifdef CRYPTSETUP_VIA_DLOPEN
+# define verity_call(_func) (hsd->dl_funcs._func)
+#else
+# define verity_call(_func) (_func)
+#endif
-static int verity_load_symbols(struct libmnt_context *cxt, void **dl, struct verity_opers *oprs)
+
+static void delete_veritydev(struct libmnt_context *cxt,
+ const struct libmnt_hookset *hs,
+ struct hookset_data *hsd);
+
+
+#ifdef CRYPTSETUP_VIA_DLOPEN
+static int load_libcryptsetup_symbols(struct libmnt_context *cxt,
+ const struct libmnt_hookset *hs,
+ struct hookset_data *hsd)
{
size_t i;
+ int flags = RTLD_LAZY | RTLD_LOCAL;
- if (!dl)
- return -EINVAL;
- /*
- * dlopen()
- */
- if (!*dl) {
- int flags = RTLD_LAZY | RTLD_LOCAL;
+ assert(cxt);
+ assert(hsd);
+ assert(hsd->dl == NULL);
- /* glibc extension: mnt_context_deferred_delete_veritydev is called immediately after, don't unload on dl_close */
+ /* glibc extension: mnt_context_deferred_delete_veritydev is called immediately after, don't unload on dl_close */
#ifdef RTLD_NODELETE
- flags |= RTLD_NODELETE;
+ flags |= RTLD_NODELETE;
#endif
- /* glibc extension: might help to avoid further symbols clashes */
+ /* glibc extension: might help to avoid further symbols clashes */
#ifdef RTLD_DEEPBIND
- flags |= RTLD_DEEPBIND;
+ flags |= RTLD_DEEPBIND;
#endif
- *dl = dlopen("libcryptsetup.so.12", flags);
- if (!*dl) {
- DBG(VERITY, ul_debugobj(cxt, "veritydev specific options detected but cannot dlopen libcryptsetup"));
- return -ENOTSUP;
- }
+ hsd->dl = dlopen("libcryptsetup.so.12", flags);
+ if (!hsd->dl) {
+ DBG(HOOK, ul_debugobj(hs, "cannot dlopen libcryptsetup"));
+ return -ENOTSUP;
}
/* clear errors first, then load all the libcryptsetup symbols */
dlerror();
- /*
- * dlsym()
- */
+ /* dlsym() */
for (i = 0; i < ARRAY_SIZE(verity_symbols); i++) {
char *errmsg;
const struct verity_sym *def = &verity_symbols[i];
void **sym;
- sym = (void **) ((char *) oprs + def->offset);
- *sym = dlsym(*dl, def->name);
+ sym = (void **) ((char *) (&hsd->dl_funcs) + def->offset);
+ *sym = dlsym(hsd->dl, def->name);
errmsg = dlerror();
if (errmsg) {
- DBG(VERITY, ul_debugobj(cxt, "cannot obtain address of a '%s' symbol: %s", def->name, errmsg));
+ DBG(HOOK, ul_debugobj(hs, "dlsym failed %s: %s", def->name, errmsg));
return -ENOTSUP;
}
}
return 0;
}
+#endif
-/*
- * with dlopen -- call pointer to libcryptsetup function, the pointer is
- * stored in __verity_opers and initialized by dlsym() in
- * verity_load_symbols().
- */
-# define verity_call(_func) ( __verity_opers._func )
+/* libcryptsetup callback */
+static void libcryptsetup_log(int level __attribute__((__unused__)),
+ const char *msg, void *data)
+{
+ const struct libmnt_hookset *hs = (struct libmnt_hookset *) data;
+ DBG(HOOK, ul_debugobj(hs, "cryptsetup: %s", msg));
+}
-#else /* !CRYPTSETUP_VIA_DLOPEN */
+/* free global data */
+static void free_hookset_data( struct libmnt_context *cxt,
+ const struct libmnt_hookset *hs)
+{
+ struct hookset_data *hsd = mnt_context_get_hookset_data(cxt, hs);
-/*
- * without dlopen -- call linked libcryptsetup function
- */
-# define verity_call(_func) (_func)
+ if (!hsd)
+ return;
+ if (hsd->devname)
+ delete_veritydev(cxt, hs, hsd);
+#ifdef CRYPTSETUP_VIA_DLOPEN
+ if (hsd->dl)
+ dlclose(hsd->dl);
+#endif
+ free(hsd);
+ mnt_context_set_hookset_data(cxt, hs, NULL);
+}
-#endif /* CRYPTSETUP_VIA_DLOPEN */
+/* global data, used by all callbacks */
+static struct hookset_data *new_hookset_data(
+ struct libmnt_context *cxt,
+ const struct libmnt_hookset *hs)
+{
+ struct hookset_data *hsd = calloc(1, sizeof(struct hookset_data));
+
+ if (hsd && mnt_context_set_hookset_data(cxt, hs, hsd) != 0)
+ goto failed;
+
+#ifdef CRYPTSETUP_VIA_DLOPEN
+ if (load_libcryptsetup_symbols(cxt, hs, hsd) != 0)
+ goto failed;
+#endif
+ if (mnt_context_is_verbose(cxt))
+ verity_call( crypt_set_debug_level(CRYPT_DEBUG_ALL) );
+
+ verity_call( crypt_set_log_callback(NULL, libcryptsetup_log, (void *) hs) );
+
+ return hsd;
+failed:
+ free(hsd);
+ return NULL;
+}
+
+/* libmount callback -- cleanup all */
+static int hookset_deinit(struct libmnt_context *cxt, const struct libmnt_hookset *hs)
+{
+ DBG(HOOK, ul_debugobj(hs, "deinit '%s'", hs->name));
+
+ /* remove all our hooks */
+ while (mnt_context_remove_hook(cxt, hs, 0, NULL) == 0);
+
+ /* free and remove global hookset data */
+ free_hookset_data(cxt, hs);
+
+ return 0;
+}
+
+/* check mount options for verity stuff */
+static int is_veritydev_required(struct libmnt_context *cxt,
+ const struct libmnt_hookset *hs,
+ struct libmnt_optlist *ol)
+{
+ const char *src;
+ unsigned long flags = 0;
+
+ assert(cxt);
+ assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
+
+ if (cxt->action != MNT_ACT_MOUNT)
+ return 0;
+ if (!cxt->fs)
+ return 0;
+ src = mnt_fs_get_srcpath(cxt->fs);
+ if (!src)
+ return 0; /* backing file not set */
+
+ ol = mnt_context_get_optlist(cxt);
+ if (!ol)
+ return 0;
+ if (mnt_optlist_is_bind(ol)
+ || mnt_optlist_is_move(ol)
+ || mnt_context_propagation_only(cxt))
+ return 0;
+ if (mnt_context_get_user_mflags(cxt, &flags))
+ return 0;
-static void libcryptsetup_log(int level __attribute__((__unused__)), const char *msg, void *data)
+ if (flags & (MNT_MS_HASH_DEVICE | MNT_MS_ROOT_HASH | MNT_MS_HASH_OFFSET)) {
+ DBG(HOOK, ul_debugobj(hs, "verity options detected"));
+ return 1;
+ }
+
+ return 0;
+}
+
+static void delete_veritydev(struct libmnt_context *cxt,
+ const struct libmnt_hookset *hs,
+ struct hookset_data *hsd)
{
- struct libmnt_context *cxt = (struct libmnt_context *)data;
+ uint32_t flags = 0;
+ int rc;
+
+ if (!hsd || !hsd->devname)
+ return;
+
+ if (mnt_context_get_status(cxt) != 0)
+ /*
+ * mount(2) success, use deferred deactivation
+ */
+ flags |= CRYPT_DEACTIVATE_DEFERRED;
+
+ rc = verity_call( crypt_deactivate_by_name(NULL, hsd->devname, flags) );
+
+ DBG(HOOK, ul_debugobj(hs, "deleted %s [rc=%d%s]",
+ hsd->devname, rc,
+ flags & CRYPT_DEACTIVATE_DEFERRED ? " deferred" : "" ));
+ if (rc == 0) {
+ free(hsd->devname);
+ hsd->devname = NULL;
+ }
- DBG(VERITY, ul_debugobj(cxt, "cryptsetup: %s", msg));
+ return;
}
/* Taken from https://gitlab.com/cryptsetup/cryptsetup/blob/master/lib/utils_crypt.c#L225 */
}
-int mnt_context_setup_veritydev(struct libmnt_context *cxt)
+static int setup_veritydev( struct libmnt_context *cxt,
+ const struct libmnt_hookset *hs,
+ struct hookset_data *hsd,
+ struct libmnt_optlist *ol)
{
- struct libmnt_optlist *ol;
struct libmnt_opt *opt;
- const char *backing_file, *hash_device = NULL, *root_hash_file = NULL, *fec_device = NULL,
- *root_hash_sig_file = NULL;
- char *key = NULL, *root_hash_binary = NULL, *mapper_device = NULL,
- *mapper_device_full = NULL, *backing_file_basename = NULL, *root_hash = NULL,
- *hash_sig = NULL;
+ const char *backing_file,
+ *hash_device = NULL,
+ *root_hash_file = NULL,
+ *fec_device = NULL,
+ *root_hash_sig_file = NULL;
+ char *key = NULL,
+ *root_hash_binary = NULL,
+ *mapper_device = NULL,
+ *root_hash = NULL,
+ *hash_sig = NULL;
+
size_t hash_size, hash_sig_size = 0, keysize = 0;
struct crypt_params_verity crypt_params = {};
struct crypt_device *crypt_dev = NULL;
+
int rc = 0;
/* Use the same default for FEC parity bytes as cryptsetup uses */
uint64_t offset = 0, fec_offset = 0, fec_roots = 2;
uint32_t crypt_activate_flags = CRYPT_ACTIVATE_READONLY;
+
struct stat hash_sig_st;
-#ifdef CRYPTSETUP_VIA_DLOPEN
- void *dl = NULL;
- struct verity_opers __verity_opers = { NULL } ; /* see verity_call() macro */
-#endif
+
assert(cxt);
assert(cxt->fs);
- assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
-
- ol = mnt_context_get_optlist(cxt);
- if (!ol)
- return -ENOMEM;
+ assert(hsd);
+ assert(hsd->devname == NULL);
/* dm-verity volumes are read-only, and mount will fail if not set */
mnt_optlist_append_flags(ol, MS_RDONLY, cxt->map_linux);
backing_file = mnt_fs_get_srcpath(cxt->fs);
if (!backing_file)
return -EINVAL;
+ else {
+ /* To avoid clashes, prefix libmnt_ to all mapper devices */
+ char *p, *path = strdup(backing_file);
+ if (!path)
+ return -ENOMEM;
+
+ p = stripoff_last_component(path);
+ if (p)
+ mapper_device = calloc(strlen(p) + sizeof("libmnt_"), sizeof(char));
+ if (mapper_device) {
+ strcat(mapper_device, "libmnt_");
+ strcat(mapper_device, p);
+ }
+ free(path);
+ if (!mapper_device)
+ return -ENOMEM;
+ }
- /* To avoid clashes, prefix libmnt_ to all mapper devices */
- backing_file_basename = basename(backing_file);
- mapper_device = calloc(strlen(backing_file_basename) + strlen("libmnt_") + 1, sizeof(char));
- if (!mapper_device)
- return -ENOMEM;
- strcat(mapper_device, "libmnt_");
- strcat(mapper_device, backing_file_basename);
-
- DBG(VERITY, ul_debugobj(cxt, "trying to setup verity device for %s", backing_file));
+ DBG(HOOK, ul_debugobj(hs, "verity: setup for %s [%s]", backing_file, mapper_device));
- /*
- * verity.hashdevice=
- */
+ /* verity.hashdevice= */
if (!rc && (opt = mnt_optlist_get_opt(ol, MNT_MS_HASH_DEVICE, cxt->map_userspace)))
hash_device = mnt_opt_get_value(opt);
- /*
- * verity.roothash=
- */
+ /* verity.roothash= */
if (!rc && (opt = mnt_optlist_get_opt(ol, MNT_MS_ROOT_HASH, cxt->map_userspace))) {
root_hash = strdup(mnt_opt_get_value(opt));
rc = root_hash ? 0 : -ENOMEM;
}
- /*
- * verity.hashoffset=
- */
+ /* verity.hashoffset= */
if (!rc && (opt = mnt_optlist_get_opt(ol, MNT_MS_HASH_OFFSET, cxt->map_userspace))
&& mnt_opt_has_value(opt)) {
if (strtosize(mnt_opt_get_value(opt), &offset)) {
- DBG(VERITY, ul_debugobj(cxt, "failed to parse verity.hashoffset="));
+ DBG(HOOK, ul_debugobj(hs, "failed to parse verity.hashoffset="));
rc = -MNT_ERR_MOUNTOPT;
}
}
- /*
- * verity.roothashfile=
- */
+ /* verity.roothashfile= */
if (!rc && (opt = mnt_optlist_get_opt(ol, MNT_MS_ROOT_HASH_FILE, cxt->map_userspace)))
root_hash_file = mnt_opt_get_value(opt);
- /*
- * verity.fecdevice=
- */
+ /* verity.fecdevice= */
if (!rc && (opt = mnt_optlist_get_opt(ol, MNT_MS_FEC_DEVICE, cxt->map_userspace)))
fec_device = mnt_opt_get_value(opt);
- /*
- * verity.fecoffset=
- */
+ /* verity.fecoffset= */
if (!rc && (opt = mnt_optlist_get_opt(ol, MNT_MS_FEC_OFFSET, cxt->map_userspace))
- && mnt_opt_has_value(opt)) {
- if (strtosize(mnt_opt_get_value(opt), &fec_offset)) {
- DBG(VERITY, ul_debugobj(cxt, "failed to parse verity.fecoffset="));
- rc = -MNT_ERR_MOUNTOPT;
- }
+ && mnt_opt_has_value(opt)
+ && strtosize(mnt_opt_get_value(opt), &fec_offset)) {
+ DBG(HOOK, ul_debugobj(hs, "failed to parse verity.fecoffset="));
+ rc = -MNT_ERR_MOUNTOPT;
}
- /*
- * verity.fecroots=
- */
+ /* verity.fecroots= */
if (!rc && (opt = mnt_optlist_get_opt(ol, MNT_MS_FEC_ROOTS, cxt->map_userspace))
- && mnt_opt_has_value(opt)) {
- if (strtosize(mnt_opt_get_value(opt), &fec_roots)) {
- DBG(VERITY, ul_debugobj(cxt, "failed to parse verity.fecroots="));
- rc = -MNT_ERR_MOUNTOPT;
- }
+ && mnt_opt_has_value(opt)
+ && strtosize(mnt_opt_get_value(opt), &fec_roots)) {
+ DBG(HOOK, ul_debugobj(hs, "failed to parse verity.fecroots="));
+ rc = -MNT_ERR_MOUNTOPT;
}
- /*
- * verity.roothashsig=
- */
+ /* verity.roothashsig= */
if (!rc && (opt = mnt_optlist_get_opt(ol, MNT_MS_ROOT_HASH_SIG, cxt->map_userspace))
&& mnt_opt_has_value(opt)) {
root_hash_sig_file = mnt_opt_get_value(opt);
- DBG(VERITY, ul_debugobj(cxt, "checking %s", root_hash_sig_file));
+ DBG(HOOK, ul_debugobj(hs, "verity: checking %s", root_hash_sig_file));
rc = ul_path_stat(NULL, &hash_sig_st, 0, root_hash_sig_file);
if (rc == 0)
rc = S_ISREG(hash_sig_st.st_mode) && hash_sig_st.st_size ? 0 : -EINVAL;
-
if (rc == 0) {
hash_sig_size = hash_sig_st.st_size;
hash_sig = malloc(hash_sig_size);
rc = hash_sig ? 0 : -ENOMEM;
}
-
if (rc == 0) {
rc = ul_path_read(NULL, hash_sig, hash_sig_size, root_hash_sig_file);
rc = rc < (int)hash_sig_size ? -1 : 0;
}
}
- /*
- * verity.oncorruption=
- */
+ /* verity.oncorruption= */
if (!rc && (opt = mnt_optlist_get_opt(ol, MNT_MS_VERITY_ON_CORRUPTION, cxt->map_userspace))
&& mnt_opt_has_value(opt)) {
const char *val = mnt_opt_get_value(opt);
#ifdef CRYPT_ACTIVATE_PANIC_ON_CORRUPTION
crypt_activate_flags |= CRYPT_ACTIVATE_PANIC_ON_CORRUPTION;
#else
- DBG(VERITY, ul_debugobj(cxt, "verity.oncorruption=panic not supported by libcryptsetup, ignoring"));
+ DBG(HOOK, ul_debugobj(hs, "verity.oncorruption=panic not supported by libcryptsetup, ignoring"));
#endif
else {
- DBG(VERITY, ul_debugobj(cxt, "failed to parse verity.oncorruption="));
+ DBG(HOOK, ul_debugobj(hs, "failed to parse verity.oncorruption="));
rc = -MNT_ERR_MOUNTOPT;
}
}
if (!rc && root_hash && root_hash_file) {
- DBG(VERITY, ul_debugobj(cxt, "verity.roothash and verity.roothashfile are mutually exclusive"));
+ DBG(HOOK, ul_debugobj(hs, "verity.roothash and verity.roothashfile are mutually exclusive"));
rc = -EINVAL;
} else if (!rc && root_hash_file) {
rc = ul_path_read_string(NULL, &root_hash, root_hash_file);
}
if (!rc && (!hash_device || !root_hash)) {
- DBG(VERITY, ul_debugobj(cxt, "verity.hashdevice and one of verity.roothash or verity.roothashfile are mandatory"));
+ DBG(HOOK, ul_debugobj(hs, "verity.hashdevice and one of verity.roothash or verity.roothashfile are mandatory"));
rc = -EINVAL;
}
-#ifdef CRYPTSETUP_VIA_DLOPEN
- if (rc == 0)
- rc = verity_load_symbols(cxt, &dl, &__verity_opers);
-#endif
- if (rc)
- goto done;
-
- if (mnt_context_is_verbose(cxt))
- verity_call( crypt_set_debug_level(CRYPT_DEBUG_ALL) );
-
- verity_call( crypt_set_log_callback(NULL, libcryptsetup_log, cxt) );
-
- rc = verity_call( crypt_init_data_device(&crypt_dev, hash_device, backing_file) );
+ if (!rc)
+ rc = verity_call( crypt_init_data_device(&crypt_dev, hash_device, backing_file) );
if (rc)
goto done;
hash_size = verity_call( 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));
+ DBG(HOOK, ul_debugobj(hs, "root hash %s is not of length %zu", root_hash, hash_size));
rc = -EINVAL;
goto done;
}
hash_sig, hash_sig_size, crypt_activate_flags) );
#else
rc = -EINVAL;
- DBG(VERITY, ul_debugobj(cxt, "verity.roothashsig=%s passed but libcryptsetup does not provide crypt_activate_by_signed_key()", hash_sig));
+ DBG(HOOK, ul_debugobj(hs, "verity.roothashsig=%s passed but libcryptsetup does not provide crypt_activate_by_signed_key()", hash_sig));
#endif
} else
rc = verity_call( crypt_activate_by_volume_key(crypt_dev, mapper_device, root_hash_binary, hash_size,
* Pass through only OOM errors or mismatching root hash errors.
*/
if (rc == -EEXIST) {
- DBG(VERITY, ul_debugobj(cxt, "%s already in use as /dev/mapper/%s", backing_file, mapper_device));
+ DBG(HOOK, ul_debugobj(hs, "%s already in use as /dev/mapper/%s", backing_file, mapper_device));
+
verity_call( crypt_free(crypt_dev) );
+
rc = verity_call( crypt_init_by_name(&crypt_dev, mapper_device) );
if (!rc) {
rc = verity_call( crypt_get_verity_info(crypt_dev, &crypt_params) );
rc = verity_call( 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));
+ DBG(HOOK, ul_debugobj(hs, "comparing root hash of existing device with %s", root_hash));
if (memcmp(key, root_hash_binary, hash_size)) {
- DBG(VERITY, ul_debugobj(cxt, "existing device's hash does not match with %s", root_hash));
+ DBG(HOOK, ul_debugobj(hs, "existing device's hash does not match with %s", root_hash));
rc = -EINVAL;
goto done;
}
} else {
- DBG(VERITY, ul_debugobj(cxt, "libcryptsetup does not support extracting root hash of existing device"));
+ DBG(HOOK, ul_debugobj(hs, "libcryptsetup does not support extracting root hash of existing device"));
}
}
if (rc) {
#ifdef HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
if (!!hash_sig != !!(crypt_params.flags & CRYPT_VERITY_ROOT_HASH_SIGNATURE)) {
rc = -EINVAL;
- DBG(VERITY, ul_debugobj(cxt, "existing device and new mount have to either be both opened with signature or both without"));
+ DBG(HOOK, ul_debugobj(hs, "existing device and new mount have to either be both opened with signature or both without"));
goto done;
}
#endif
- DBG(VERITY, ul_debugobj(cxt, "root hash of %s matches %s, reusing device", mapper_device, root_hash));
+ DBG(HOOK, ul_debugobj(hs, "root hash of %s matches %s, reusing device", mapper_device, root_hash));
}
}
if (!rc) {
- cxt->flags |= MNT_FL_VERITYDEV_READY;
- mapper_device_full = calloc(strlen(mapper_device) + strlen("/dev/mapper/") + 1, sizeof(char));
- if (!mapper_device_full)
+ hsd->devname = calloc(strlen(mapper_device)
+ + sizeof(_PATH_DEV_MAPPER) + 2, sizeof(char));
+ if (!hsd->devname)
rc = -ENOMEM;
else {
- strcat(mapper_device_full, "/dev/mapper/");
- strcat(mapper_device_full, mapper_device);
- rc = mnt_fs_set_source(cxt->fs, mapper_device_full);
+ strcat(hsd->devname, _PATH_DEV_MAPPER "/");
+ strcat(hsd->devname, mapper_device);
+ rc = mnt_fs_set_source(cxt->fs, hsd->devname);
}
}
done:
verity_call( crypt_free(crypt_dev) );
-#ifdef CRYPTSETUP_VIA_DLOPEN
- if (dl)
- dlclose(dl);
-#endif
+
free(root_hash_binary);
- free(mapper_device_full);
free(mapper_device);
free(root_hash);
free(hash_sig);
free(key);
return rc;
}
+/* call after mount(2) */
+static int hook_mount_post(
+ struct libmnt_context *cxt,
+ const struct libmnt_hookset *hs,
+ void *data __attribute__((__unused__)))
+{
-int mnt_context_deferred_delete_veritydev(struct libmnt_context *cxt)
+ delete_veritydev(cxt, hs, mnt_context_get_hookset_data(cxt, hs));
+ return 0;
+}
+
+/*
+ * first call (first callback in this hookset)
+ */
+static int hook_prepare_source(
+ struct libmnt_context *cxt,
+ const struct libmnt_hookset *hs,
+ void *data __attribute__((__unused__)))
{
- const char *src;
- /* If mounting failed delete immediately, otherwise setup auto cleanup for user umount */
- uint32_t flags = mnt_context_get_status(cxt) ? CRYPT_DEACTIVATE_DEFERRED : 0;
-#ifdef CRYPTSETUP_VIA_DLOPEN
- void *dl = NULL;
- struct verity_opers __verity_opers = { NULL } ; /* see verity_call() macro */
-#endif
- int rc = 0;
+ struct libmnt_optlist *ol;
+ struct hookset_data *hsd;
+ int rc;
assert(cxt);
- assert(cxt->fs);
- if (!(cxt->flags & MNT_FL_VERITYDEV_READY))
+ ol = mnt_context_get_optlist(cxt);
+ if (!ol)
+ return -ENOMEM;
+
+ if (!is_veritydev_required(cxt, hs, ol))
return 0;
- src = mnt_fs_get_srcpath(cxt->fs);
- if (!src)
- return -EINVAL;
+ hsd = new_hookset_data(cxt, hs);
+ if (!hsd)
+ return -ENOMEM;
-#ifdef CRYPTSETUP_VIA_DLOPEN
- rc = verity_load_symbols(cxt, &dl, &__verity_opers);
-#endif
+ rc = setup_veritydev(cxt, hs, hsd, ol);
if (!rc) {
- if (mnt_context_is_verbose(cxt))
- verity_call( crypt_set_debug_level(CRYPT_DEBUG_ALL) );
-
- verity_call( crypt_set_log_callback(NULL, libcryptsetup_log, cxt) );
-
- rc = verity_call( crypt_deactivate_by_name(NULL, src, flags) );
- if (!rc)
- cxt->flags &= ~MNT_FL_VERITYDEV_READY;
+ rc = mnt_context_append_hook(cxt, hs,
+ MNT_STAGE_MOUNT_POST,
+ NULL, hook_mount_post);
+ if (rc)
+ delete_veritydev(cxt, hs, hsd);
}
-
-#ifdef CRYPTSETUP_VIA_DLOPEN
- dlclose(dl);
-#endif
- DBG(VERITY, ul_debugobj(cxt, "deleted [rc=%d]", rc));
return rc;
}
-#else
-
-int mnt_context_setup_veritydev(struct libmnt_context *cxt __attribute__ ((__unused__)))
-{
- return 0;
-}
-
-int mnt_context_deferred_delete_veritydev(struct libmnt_context *cxt __attribute__ ((__unused__)))
-{
- return 0;
-}
-#endif
-int mnt_context_is_veritydev(struct libmnt_context *cxt)
+const struct libmnt_hookset hookset_veritydev =
{
- const char *src;
- unsigned long flags = 0;
- struct libmnt_optlist *ol;
+ .name = "__veritydev",
- assert(cxt);
- assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
+ .firststage = MNT_STAGE_PREP_SOURCE,
+ .firstcall = hook_prepare_source,
- if (cxt->action != MNT_ACT_MOUNT)
- return 0;
- if (!cxt->fs)
- return 0;
- src = mnt_fs_get_srcpath(cxt->fs);
- if (!src)
- return 0; /* backing file not set */
+ .deinit = hookset_deinit
+};
+#endif /*HAVE_CRYPTSETUP*/
- ol = mnt_context_get_optlist(cxt);
- if (!ol)
- return 0;
- if (mnt_optlist_is_bind(ol)
- || mnt_optlist_is_move(ol)
- || mnt_context_propagation_only(cxt))
- return 0;
- if (mnt_context_get_user_mflags(cxt, &flags))
- return 0;
- if (flags & (MNT_MS_HASH_DEVICE | MNT_MS_ROOT_HASH | MNT_MS_HASH_OFFSET)) {
-#ifndef HAVE_CRYPTSETUP
- DBG(VERITY, ul_debugobj(cxt, "veritydev specific options detected but libmount built without libcryptsetup"));
- return -ENOTSUP;
-#else
- DBG(VERITY, ul_debugobj(cxt, "veritydev specific options detected"));
- return 1;
-#endif
- }
-
- if (!strncmp(src, "/dev/mapper/libmnt_", strlen("/dev/mapper/libmnt_"))) {
-#ifndef HAVE_CRYPTSETUP
- DBG(VERITY, ul_debugobj(cxt, "veritydev prefix detected in source device but libmount built without libcryptsetup"));
- return -ENOTSUP;
-#else
- DBG(VERITY, ul_debugobj(cxt, "veritydev prefix detected in source device"));
- return 1;
-#endif
- }
-
- return 0;
-}