]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libmount: (verity) rewrite to use hookset API
authorKarel Zak <kzak@redhat.com>
Thu, 8 Sep 2022 10:37:52 +0000 (12:37 +0200)
committerKarel Zak <kzak@redhat.com>
Tue, 3 Jan 2023 11:58:42 +0000 (12:58 +0100)
* initialize only when relevant verity.* options detected

* setup verity device by prepare-source hook

* add post-mount hook to setup deferred deactivation

* deactivate the device on error (when de-initialize the hookset)

* call dlopen/dlclose only once, share symbols between all hooks

* remove verity specific code from rest of libmount

Signed-off-by: Karel Zak <kzak@redhat.com>
libmount/src/Makemodule.am
libmount/src/context.c
libmount/src/context_mount.c
libmount/src/hook_veritydev.c [moved from libmount/src/context_veritydev.c with 56% similarity]
libmount/src/hooks.c
libmount/src/mountP.h

index 7e9ac3ee982c93ac06a9ae28f77782e9b151d215..1d38cc959c87f671e7098ae6ef77a1c090820471 100644 (file)
@@ -29,7 +29,6 @@ libmount_la_SOURCES = \
 if LINUX
 libmount_la_SOURCES += \
        libmount/src/context.c \
-       libmount/src/context_veritydev.c \
        libmount/src/context_mount.c \
        libmount/src/context_umount.c \
        libmount/src/hook_mount_legacy.c \
@@ -38,6 +37,7 @@ libmount_la_SOURCES += \
        libmount/src/hook_owner.c \
        libmount/src/hook_idmap.c \
        libmount/src/hook_loopdev.c \
+       libmount/src/hook_veritydev.c \
        libmount/src/monitor.c
 
 if HAVE_BTRFS
index b846a930356b1ca75db23fc78cedee280a00607c..048c0fa6431a2621aac5f672a41ef8493b05b864 100644 (file)
@@ -1853,21 +1853,6 @@ int mnt_context_prepare_srcpath(struct libmnt_context *cxt)
        if (rc)
                goto end;
 
-       /*
-        * Initialize verity or loop device
-        * ENOTSUP means verity options were requested, but the library is built without
-        * libcryptsetup so integrity cannot be enforced, and this should be an error
-        * rather than a silent fallback to a simple loopdev mount
-        */
-       rc = mnt_context_is_veritydev(cxt);
-       if (rc == -ENOTSUP) {
-                       goto end;
-       } else if (rc) {
-               rc = mnt_context_setup_veritydev(cxt);
-               if (rc)
-                       goto end;
-       }
-
        DBG(CXT, ul_debugobj(cxt, "final srcpath '%s'",
                                mnt_fs_get_source(cxt->fs)));
 
index 743c77a05ac9922740a8501db1cad243c92c1ab1..907cb657119d2b145fba7a3a5cadae9f9b53a901 100644 (file)
@@ -896,10 +896,6 @@ int mnt_context_do_mount(struct libmnt_context *cxt)
        if (rc)
                return rc;
 
-       /* Cleanup will be immediate on failure, and deferred to umount on success */
-       if (mnt_context_is_veritydev(cxt))
-               mnt_context_deferred_delete_veritydev(cxt);
-
        if (!mnt_context_switch_ns(cxt, ns_old))
                return -MNT_ERR_NAMESPACE;
 
similarity index 56%
rename from libmount/src/context_veritydev.c
rename to libmount/src/hook_veritydev.c
index 850f9aeaef9df6f256c069881ab6d5639fea02c0..8f2386539cc1c9efa742e9a3bed6c73a7ac02f5f 100644 (file)
 
 #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 *);
@@ -41,7 +43,7 @@ struct verity_opers {
        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 */
@@ -53,6 +55,7 @@ struct verity_sym {
                .offset = offsetof(struct verity_opers, _name), \
        }
 
+/* All required symbols */
 static const struct verity_sym verity_symbols[] =
 {
        DEF_VERITY_SYM( crypt_set_debug_level ),
@@ -71,79 +74,209 @@ static const struct verity_sym verity_symbols[] =
 
        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 */
@@ -175,34 +308,38 @@ static size_t crypt_hex_to_bytes(const char *hex, char **result)
 }
 
 
-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);
@@ -210,104 +347,91 @@ int mnt_context_setup_veritydev(struct libmnt_context *cxt)
        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);
@@ -320,16 +444,16 @@ int mnt_context_setup_veritydev(struct libmnt_context *cxt)
 #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);
@@ -337,23 +461,12 @@ int mnt_context_setup_veritydev(struct libmnt_context *cxt)
        }
 
        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;
 
@@ -370,7 +483,7 @@ int mnt_context_setup_veritydev(struct libmnt_context *cxt)
 
        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;
        }
@@ -381,7 +494,7 @@ int mnt_context_setup_veritydev(struct libmnt_context *cxt)
                                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,
@@ -398,8 +511,10 @@ int mnt_context_setup_veritydev(struct libmnt_context *cxt)
         * 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) );
@@ -415,14 +530,14 @@ int mnt_context_setup_veritydev(struct libmnt_context *cxt)
                                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) {
@@ -436,143 +551,94 @@ int mnt_context_setup_veritydev(struct libmnt_context *cxt)
 #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;
-}
index 2dc44d9feb965dd778735b9c6918924c5d16e780..4340ac61cac761ba1771223ed41e0825e446c9d1 100644 (file)
@@ -26,6 +26,9 @@ static const struct libmnt_hookset *hooksets[] =
 {
 #ifdef __linux__
        &hookset_loopdev,
+#ifdef HAVE_CRYPTSETUP
+       &hookset_veritydev,
+#endif
        &hookset_mkdir,
        &hookset_subdir,
        &hookset_mount_legacy,
index 799aeb2036ce7ad77117d60154105b4d8cff9666..7f1636d9a9db743c3832d65ef4031d1094100b7d 100644 (file)
@@ -316,6 +316,9 @@ extern const struct libmnt_hookset hookset_subdir;
 extern const struct libmnt_hookset hookset_owner;
 extern const struct libmnt_hookset hookset_idmap;
 extern const struct libmnt_hookset hookset_loopdev;
+#ifdef HAVE_CRYPTSETUP
+extern const struct libmnt_hookset hookset_veritydev;
+#endif
 
 extern int mnt_context_deinit_hooksets(struct libmnt_context *cxt);
 extern const struct libmnt_hookset *mnt_context_get_hookset(struct libmnt_context *cxt, const char *name);
@@ -604,11 +607,6 @@ extern int mnt_context_save_template(struct libmnt_context *cxt);
 
 extern int mnt_context_apply_fs(struct libmnt_context *cxt, struct libmnt_fs *fs);
 
-extern int mnt_context_is_veritydev(struct libmnt_context *cxt)
-                       __attribute__((nonnull));
-extern int mnt_context_setup_veritydev(struct libmnt_context *cxt);
-extern int mnt_context_deferred_delete_veritydev(struct libmnt_context *cxt);
-
 extern struct libmnt_optlist *mnt_context_get_optlist(struct libmnt_context *cxt);
 
 /* tab_update.c */