(root)/
util-linux-2.39/
libmount/
src/
hook_veritydev.c
       1  /* SPDX-License-Identifier: LGPL-2.1-or-later */
       2  /*
       3   * This file is part of libmount from util-linux project.
       4   *
       5   * Copyright (C) 2019 Microsoft Corporation
       6   * Copyright (C) 2022 Karel Zak <kzak@redhat.com>
       7   *
       8   * libmount is free software; you can redistribute it and/or modify it
       9   * under the terms of the GNU Lesser General Public License as published by
      10   * the Free Software Foundation; either version 2.1 of the License, or
      11   * (at your option) any later version.
      12   *
      13   *
      14   * Please, see comment in libmount/src/hooks.c to understand how hooks work.
      15   */
      16  #include "mountP.h"
      17  
      18  #ifdef HAVE_CRYPTSETUP
      19  
      20  #include <libcryptsetup.h>
      21  #include "path.h"
      22  #include "strutils.h"
      23  #include "fileutils.h"
      24  #include "pathnames.h"
      25  
      26  #ifdef CRYPTSETUP_VIA_DLOPEN
      27  # include <dlfcn.h>
      28  
      29  /* Pointers to libcryptsetup functions (initiliazed by dlsym()) */
      30  struct verity_opers {
      31  	void (*crypt_set_debug_level)(int);
      32  	void (*crypt_set_log_callback)(struct crypt_device *, void (*log)(int, const char *, void *), void *);
      33  	int (*crypt_init_data_device)(struct crypt_device **, const char *, const char *);
      34  	int (*crypt_load)(struct crypt_device *, const char *, void *);
      35  	int (*crypt_get_volume_key_size)(struct crypt_device *);
      36  # ifdef HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
      37  	int (*crypt_activate_by_signed_key)(struct crypt_device *, const char *, const char *, size_t, const char *, size_t, uint32_t);
      38  # endif
      39  	int (*crypt_activate_by_volume_key)(struct crypt_device *, const char *, const char *, size_t, uint32_t);
      40  	void (*crypt_free)(struct crypt_device *);
      41  	int (*crypt_init_by_name)(struct crypt_device **, const char *);
      42  	int (*crypt_get_verity_info)(struct crypt_device *, struct crypt_params_verity *);
      43  	int (*crypt_volume_key_get)(struct crypt_device *, int, char *, size_t *, const char *, size_t);
      44  
      45  	int (*crypt_deactivate_by_name)(struct crypt_device *, const char *, uint32_t);
      46  };
      47  
      48  /* libcryptsetup functions names and offsets in 'struct verity_opers' */
      49  struct verity_sym {
      50  	const char *name;
      51  	size_t offset;		/* offset of the symbol in verity_opers */
      52  };
      53  
      54  # define DEF_VERITY_SYM(_name) \
      55  	{ \
      56  		.name = # _name, \
      57  		.offset = offsetof(struct verity_opers, _name), \
      58  	}
      59  
      60  /* All required symbols */
      61  static const struct verity_sym verity_symbols[] =
      62  {
      63  	DEF_VERITY_SYM( crypt_set_debug_level ),
      64  	DEF_VERITY_SYM( crypt_set_log_callback ),
      65  	DEF_VERITY_SYM( crypt_init_data_device ),
      66  	DEF_VERITY_SYM( crypt_load ),
      67  	DEF_VERITY_SYM( crypt_get_volume_key_size ),
      68  # ifdef HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
      69  	DEF_VERITY_SYM( crypt_activate_by_signed_key ),
      70  # endif
      71  	DEF_VERITY_SYM( crypt_activate_by_volume_key ),
      72  	DEF_VERITY_SYM( crypt_free ),
      73  	DEF_VERITY_SYM( crypt_init_by_name ),
      74  	DEF_VERITY_SYM( crypt_get_verity_info ),
      75  	DEF_VERITY_SYM( crypt_volume_key_get ),
      76  
      77  	DEF_VERITY_SYM( crypt_deactivate_by_name ),
      78  };
      79  #endif /* CRYPTSETUP_VIA_DLOPEN */
      80  
      81  
      82  /* Data used by all verity hooks */
      83  struct hookset_data {
      84  	char *devname;			/* the device */
      85  #ifdef CRYPTSETUP_VIA_DLOPEN
      86  	void *dl;			/* dlopen() */
      87  	struct verity_opers dl_funcs;	/* dlsym() */
      88  #endif
      89  };
      90  
      91  /* libcryptsetup call -- dlopen version requires 'struct hookset_data *hsd' */
      92  #ifdef CRYPTSETUP_VIA_DLOPEN
      93  # define verity_call(_func)	(hsd->dl_funcs._func)
      94  #else
      95  # define verity_call(_func)	(_func)
      96  #endif
      97  
      98  
      99  static void delete_veritydev(struct libmnt_context *cxt,
     100                          const struct libmnt_hookset *hs,
     101                          struct hookset_data *hsd);
     102  
     103  
     104  #ifdef CRYPTSETUP_VIA_DLOPEN
     105  static int load_libcryptsetup_symbols(struct libmnt_context *cxt,
     106  				      const struct libmnt_hookset *hs,
     107  				      struct hookset_data *hsd)
     108  {
     109  	size_t i;
     110  	int flags = RTLD_LAZY | RTLD_LOCAL;
     111  
     112  	assert(cxt);
     113  	assert(hsd);
     114  	assert(hsd->dl == NULL);
     115  
     116  	/* glibc extension: mnt_context_deferred_delete_veritydev is called immediately after, don't unload on dl_close */
     117  #ifdef RTLD_NODELETE
     118  	flags |= RTLD_NODELETE;
     119  #endif
     120  	/* glibc extension: might help to avoid further symbols clashes */
     121  #ifdef RTLD_DEEPBIND
     122  	flags |= RTLD_DEEPBIND;
     123  #endif
     124  	hsd->dl = dlopen("libcryptsetup.so.12", flags);
     125  	if (!hsd->dl) {
     126  		DBG(HOOK, ul_debugobj(hs, "cannot dlopen libcryptsetup"));
     127  		return -ENOTSUP;
     128  	}
     129  
     130  	/* clear errors first, then load all the libcryptsetup symbols */
     131  	dlerror();
     132  
     133  	/* dlsym()  */
     134  	for (i = 0; i < ARRAY_SIZE(verity_symbols); i++) {
     135  		char *errmsg;
     136  		const struct verity_sym *def = &verity_symbols[i];
     137  		void **sym;
     138  
     139  		sym = (void **) ((char *) (&hsd->dl_funcs) + def->offset);
     140  		*sym = dlsym(hsd->dl, def->name);
     141  
     142  		errmsg = dlerror();
     143  		if (errmsg) {
     144  			DBG(HOOK, ul_debugobj(hs, "dlsym failed %s: %s", def->name, errmsg));
     145  			return -ENOTSUP;
     146  		}
     147  	}
     148  	return 0;
     149  }
     150  #endif
     151  
     152  /* libcryptsetup callback */
     153  static void libcryptsetup_log(int level __attribute__((__unused__)),
     154  			      const char *msg, void *data)
     155  {
     156  	const struct libmnt_hookset *hs = (struct libmnt_hookset *) data;
     157  	DBG(HOOK, ul_debugobj(hs, "cryptsetup: %s", msg));
     158  }
     159  
     160  /* free global data */
     161  static void free_hookset_data(	struct libmnt_context *cxt,
     162  				const struct libmnt_hookset *hs)
     163  {
     164  	struct hookset_data *hsd = mnt_context_get_hookset_data(cxt, hs);
     165  
     166  	if (!hsd)
     167  		return;
     168  	if (hsd->devname)
     169  		delete_veritydev(cxt, hs, hsd);
     170  #ifdef CRYPTSETUP_VIA_DLOPEN
     171  	if (hsd->dl)
     172  		dlclose(hsd->dl);
     173  #endif
     174  	free(hsd);
     175  	mnt_context_set_hookset_data(cxt, hs, NULL);
     176  }
     177  
     178  /* global data, used by all callbacks */
     179  static struct hookset_data *new_hookset_data(
     180  				struct libmnt_context *cxt,
     181  				const struct libmnt_hookset *hs)
     182  {
     183  	struct hookset_data *hsd = calloc(1, sizeof(struct hookset_data));
     184  
     185  	if (hsd && mnt_context_set_hookset_data(cxt, hs, hsd) != 0)
     186  		goto failed;
     187  
     188  #ifdef CRYPTSETUP_VIA_DLOPEN
     189  	if (load_libcryptsetup_symbols(cxt, hs, hsd) != 0)
     190  		goto failed;
     191  #endif
     192  	if (mnt_context_is_verbose(cxt))
     193  		verity_call( crypt_set_debug_level(CRYPT_DEBUG_ALL) );
     194  
     195  	verity_call( crypt_set_log_callback(NULL, libcryptsetup_log, (void *) hs) );
     196  
     197  	return hsd;
     198  failed:
     199  	free(hsd);
     200  	return NULL;
     201  }
     202  
     203  /* libmount callback -- cleanup all */
     204  static int hookset_deinit(struct libmnt_context *cxt, const struct libmnt_hookset *hs)
     205  {
     206  	DBG(HOOK, ul_debugobj(hs, "deinit '%s'", hs->name));
     207  
     208  	/* remove all our hooks */
     209  	while (mnt_context_remove_hook(cxt, hs, 0, NULL) == 0);
     210  
     211  	/* free and remove global hookset data */
     212  	free_hookset_data(cxt, hs);
     213  
     214  	return 0;
     215  }
     216  
     217  /* check mount options for verity stuff */
     218  static int is_veritydev_required(struct libmnt_context *cxt,
     219  				 const struct libmnt_hookset *hs,
     220  				 struct libmnt_optlist *ol)
     221  {
     222  	const char *src;
     223  	unsigned long flags = 0;
     224  
     225  	assert(cxt);
     226  	assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
     227  
     228  	if (cxt->action != MNT_ACT_MOUNT)
     229  		return 0;
     230  	if (!cxt->fs)
     231  		return 0;
     232  	src = mnt_fs_get_srcpath(cxt->fs);
     233  	if (!src)
     234  		return 0;		/* backing file not set */
     235  
     236  	ol = mnt_context_get_optlist(cxt);
     237  	if (!ol)
     238  		return 0;
     239  	if (mnt_optlist_is_bind(ol)
     240  	    || mnt_optlist_is_move(ol)
     241  	    || mnt_context_propagation_only(cxt))
     242  		return 0;
     243  
     244  	if (mnt_context_get_user_mflags(cxt, &flags))
     245  		return 0;
     246  
     247  	if (flags & (MNT_MS_HASH_DEVICE | MNT_MS_ROOT_HASH | MNT_MS_HASH_OFFSET)) {
     248  		DBG(HOOK, ul_debugobj(hs, "verity options detected"));
     249  		return 1;
     250  	}
     251  
     252  	return 0;
     253  }
     254  
     255  static void delete_veritydev(struct libmnt_context *cxt,
     256  			const struct libmnt_hookset *hs,
     257  			struct hookset_data *hsd)
     258  {
     259  	uint32_t flags = 0;
     260  	int rc;
     261  
     262  	if (!hsd || !hsd->devname)
     263  		return;
     264  
     265  	if (mnt_context_get_status(cxt) != 0)
     266  		/*
     267  		 * mount(2) success, use deferred deactivation
     268  		 */
     269  		flags |= CRYPT_DEACTIVATE_DEFERRED;
     270  
     271  	rc = verity_call( crypt_deactivate_by_name(NULL, hsd->devname, flags) );
     272  
     273  	DBG(HOOK, ul_debugobj(hs, "deleted %s [rc=%d%s]",
     274  				hsd->devname, rc,
     275  				flags & CRYPT_DEACTIVATE_DEFERRED ? " deferred" : "" ));
     276  	if (rc == 0) {
     277  		free(hsd->devname);
     278  		hsd->devname = NULL;
     279  	}
     280  
     281  	return;
     282  }
     283  
     284  /* Taken from https://gitlab.com/cryptsetup/cryptsetup/blob/master/lib/utils_crypt.c#L225 */
     285  static size_t crypt_hex_to_bytes(const char *hex, char **result)
     286  {
     287  	char buf[3] = "xx\0", *endp, *bytes;
     288  	size_t i, len;
     289  
     290  	len = strlen(hex);
     291  	if (len % 2)
     292  		return -EINVAL;
     293  	len /= 2;
     294  
     295  	bytes = malloc(len);
     296  	if (!bytes)
     297  		return -ENOMEM;
     298  
     299  	for (i = 0; i < len; i++) {
     300  		memcpy(buf, &hex[i * 2], 2);
     301  		errno = 0;
     302  		bytes[i] = strtoul(buf, &endp, 16);
     303  		if (errno || endp != &buf[2]) {
     304  			free(bytes);
     305  			return -EINVAL;
     306  		}
     307  	}
     308  	*result = bytes;
     309  	return i;
     310  }
     311  
     312  
     313  static int setup_veritydev(	struct libmnt_context *cxt,
     314  				const struct libmnt_hookset *hs,
     315  				struct hookset_data *hsd,
     316  				struct libmnt_optlist *ol)
     317  {
     318  	struct libmnt_opt *opt;
     319  	const char	*backing_file,
     320  			*hash_device = NULL,
     321  			*root_hash_file = NULL,
     322  			*fec_device = NULL,
     323  			*root_hash_sig_file = NULL;
     324  	char		*key = NULL,
     325  			*root_hash_binary = NULL,
     326  			*mapper_device = NULL,
     327  			*root_hash = NULL,
     328  			*hash_sig = NULL;
     329  
     330  	size_t hash_size, hash_sig_size = 0, keysize = 0;
     331  	struct crypt_params_verity crypt_params = {};
     332  	struct crypt_device *crypt_dev = NULL;
     333  
     334  	int rc = 0;
     335  	/* Use the same default for FEC parity bytes as cryptsetup uses */
     336  	uint64_t offset = 0, fec_offset = 0, fec_roots = 2;
     337  	uint32_t crypt_activate_flags = CRYPT_ACTIVATE_READONLY;
     338  
     339  	struct stat hash_sig_st;
     340  
     341  	assert(cxt);
     342  	assert(cxt->fs);
     343  	assert(hsd);
     344  	assert(hsd->devname == NULL);
     345  
     346  	/* dm-verity volumes are read-only, and mount will fail if not set */
     347  	mnt_optlist_append_flags(ol, MS_RDONLY, cxt->map_linux);
     348  
     349  	backing_file = mnt_fs_get_srcpath(cxt->fs);
     350  	if (!backing_file)
     351  		return -EINVAL;
     352  	else {
     353  		/* To avoid clashes, prefix libmnt_ to all mapper devices */
     354  		char *p, *path = strdup(backing_file);
     355  		if (!path)
     356  			return -ENOMEM;
     357  
     358  		p = stripoff_last_component(path);
     359  		if (p)
     360  			mapper_device = calloc(strlen(p) + sizeof("libmnt_"), sizeof(char));
     361  		if (mapper_device) {
     362  			strcat(mapper_device, "libmnt_");
     363  			strcat(mapper_device, p);
     364  		}
     365  		free(path);
     366  		if (!mapper_device)
     367  			return -ENOMEM;
     368  	}
     369  
     370  	DBG(HOOK, ul_debugobj(hs, "verity: setup for %s [%s]", backing_file, mapper_device));
     371  
     372  	/* verity.hashdevice= */
     373  	if (!rc && (opt = mnt_optlist_get_opt(ol, MNT_MS_HASH_DEVICE, cxt->map_userspace)))
     374  		hash_device = mnt_opt_get_value(opt);
     375  
     376  	/* verity.roothash= */
     377  	if (!rc && (opt = mnt_optlist_get_opt(ol, MNT_MS_ROOT_HASH, cxt->map_userspace))) {
     378  		root_hash = strdup(mnt_opt_get_value(opt));
     379  		rc = root_hash ? 0 : -ENOMEM;
     380  	}
     381  
     382  	/* verity.hashoffset= */
     383  	if (!rc && (opt = mnt_optlist_get_opt(ol, MNT_MS_HASH_OFFSET, cxt->map_userspace))
     384  	    && mnt_opt_has_value(opt)) {
     385  		if (strtosize(mnt_opt_get_value(opt), &offset)) {
     386  			DBG(HOOK, ul_debugobj(hs, "failed to parse verity.hashoffset="));
     387  			rc = -MNT_ERR_MOUNTOPT;
     388  		}
     389  	}
     390  
     391  	/* verity.roothashfile= */
     392  	if (!rc && (opt = mnt_optlist_get_opt(ol, MNT_MS_ROOT_HASH_FILE, cxt->map_userspace)))
     393  		root_hash_file = mnt_opt_get_value(opt);
     394  
     395  	/* verity.fecdevice= */
     396  	if (!rc && (opt = mnt_optlist_get_opt(ol, MNT_MS_FEC_DEVICE, cxt->map_userspace)))
     397  		fec_device = mnt_opt_get_value(opt);
     398  
     399  	/* verity.fecoffset= */
     400  	if (!rc && (opt = mnt_optlist_get_opt(ol, MNT_MS_FEC_OFFSET, cxt->map_userspace))
     401  	    && mnt_opt_has_value(opt)
     402  	    && strtosize(mnt_opt_get_value(opt), &fec_offset)) {
     403  		DBG(HOOK, ul_debugobj(hs, "failed to parse verity.fecoffset="));
     404  		rc = -MNT_ERR_MOUNTOPT;
     405  	}
     406  
     407  	/* verity.fecroots=  */
     408  	if (!rc && (opt = mnt_optlist_get_opt(ol, MNT_MS_FEC_ROOTS, cxt->map_userspace))
     409  	    && mnt_opt_has_value(opt)
     410  	    && strtosize(mnt_opt_get_value(opt), &fec_roots)) {
     411  		DBG(HOOK, ul_debugobj(hs, "failed to parse verity.fecroots="));
     412  		rc = -MNT_ERR_MOUNTOPT;
     413  	}
     414  
     415  	/* verity.roothashsig= */
     416  	if (!rc && (opt = mnt_optlist_get_opt(ol, MNT_MS_ROOT_HASH_SIG, cxt->map_userspace))
     417  	    && mnt_opt_has_value(opt)) {
     418  		root_hash_sig_file = mnt_opt_get_value(opt);
     419  
     420  		DBG(HOOK, ul_debugobj(hs, "verity: checking %s", root_hash_sig_file));
     421  
     422  		rc = ul_path_stat(NULL, &hash_sig_st, 0, root_hash_sig_file);
     423  		if (rc == 0)
     424  			rc = S_ISREG(hash_sig_st.st_mode) && hash_sig_st.st_size ? 0 : -EINVAL;
     425  		if (rc == 0) {
     426  			hash_sig_size = hash_sig_st.st_size;
     427  			hash_sig = malloc(hash_sig_size);
     428  			rc = hash_sig ? 0 : -ENOMEM;
     429  		}
     430  		if (rc == 0) {
     431  			rc = ul_path_read(NULL, hash_sig, hash_sig_size, root_hash_sig_file);
     432  			rc = rc < (int)hash_sig_size ? -1 : 0;
     433  		}
     434  	}
     435  
     436  	/* verity.oncorruption= */
     437  	if (!rc && (opt = mnt_optlist_get_opt(ol, MNT_MS_VERITY_ON_CORRUPTION, cxt->map_userspace))
     438  	    && mnt_opt_has_value(opt)) {
     439  		const char *val =  mnt_opt_get_value(opt);
     440  		if (!strcmp(val, "ignore"))
     441  			crypt_activate_flags |= CRYPT_ACTIVATE_IGNORE_CORRUPTION;
     442  		else if (!strcmp(val, "restart"))
     443  			crypt_activate_flags |= CRYPT_ACTIVATE_RESTART_ON_CORRUPTION;
     444  		else if (!strcmp(val, "panic"))
     445  			/* Added by libcryptsetup v2.3.4 - ignore on lower versions, as with other optional features */
     446  #ifdef CRYPT_ACTIVATE_PANIC_ON_CORRUPTION
     447  			crypt_activate_flags |= CRYPT_ACTIVATE_PANIC_ON_CORRUPTION;
     448  #else
     449  			DBG(HOOK, ul_debugobj(hs, "verity.oncorruption=panic not supported by libcryptsetup, ignoring"));
     450  #endif
     451  		else {
     452  			DBG(HOOK, ul_debugobj(hs, "failed to parse verity.oncorruption="));
     453  			rc = -MNT_ERR_MOUNTOPT;
     454  		}
     455  	}
     456  
     457  	if (!rc && root_hash && root_hash_file) {
     458  		DBG(HOOK, ul_debugobj(hs, "verity.roothash and verity.roothashfile are mutually exclusive"));
     459  		rc = -EINVAL;
     460  	} else if (!rc && root_hash_file) {
     461  		rc = ul_path_read_string(NULL, &root_hash, root_hash_file);
     462  		rc = rc < 1 ? rc : 0;
     463  	}
     464  
     465  	if (!rc && (!hash_device || !root_hash)) {
     466  		DBG(HOOK, ul_debugobj(hs, "verity.hashdevice and one of verity.roothash or verity.roothashfile are mandatory"));
     467  		rc = -EINVAL;
     468  	}
     469  
     470  	if (!rc)
     471  		rc = verity_call( crypt_init_data_device(&crypt_dev, hash_device, backing_file) );
     472  	if (rc)
     473  		goto done;
     474  
     475  	memset(&crypt_params, 0, sizeof(struct crypt_params_verity));
     476  	crypt_params.hash_area_offset = offset;
     477  	crypt_params.fec_area_offset = fec_offset;
     478  	crypt_params.fec_roots = fec_roots;
     479  	crypt_params.fec_device = fec_device;
     480  	crypt_params.flags = 0;
     481  
     482  	rc = verity_call( crypt_load(crypt_dev, CRYPT_VERITY, &crypt_params) );
     483  	if (rc < 0)
     484  		goto done;
     485  
     486  	hash_size = verity_call( crypt_get_volume_key_size(crypt_dev) );
     487  	if (crypt_hex_to_bytes(root_hash, &root_hash_binary) != hash_size) {
     488  		DBG(HOOK, ul_debugobj(hs, "root hash %s is not of length %zu", root_hash, hash_size));
     489  		rc = -EINVAL;
     490  		goto done;
     491  	}
     492  
     493  	if (hash_sig) {
     494  #ifdef HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
     495  		rc = verity_call( crypt_activate_by_signed_key(crypt_dev, mapper_device, root_hash_binary, hash_size,
     496  				hash_sig, hash_sig_size, crypt_activate_flags) );
     497  #else
     498  		rc = -EINVAL;
     499  		DBG(HOOK, ul_debugobj(hs, "verity.roothashsig=%s passed but libcryptsetup does not provide crypt_activate_by_signed_key()", hash_sig));
     500  #endif
     501  	} else
     502  		rc = verity_call( crypt_activate_by_volume_key(crypt_dev, mapper_device, root_hash_binary, hash_size,
     503  				crypt_activate_flags) );
     504  
     505  	/*
     506  	 * If the mapper device already exists, and if libcryptsetup supports it, get the root
     507  	 * hash associated with the existing one and compare it with the parameter passed by
     508  	 * the user. If they match, then we can be sure the user intended to mount the exact
     509  	 * same device, and simply reuse it and return success.
     510  	 * The kernel does the refcounting for us.
     511  	 * If libcryptsetup does not support getting the root hash out of an existing device,
     512  	 * then return an error and tell the user that the device is already in use.
     513  	 * Pass through only OOM errors or mismatching root hash errors.
     514  	 */
     515  	if (rc == -EEXIST) {
     516  		DBG(HOOK, ul_debugobj(hs, "%s already in use as /dev/mapper/%s", backing_file, mapper_device));
     517  
     518  		verity_call( crypt_free(crypt_dev) );
     519  
     520  		rc = verity_call( crypt_init_by_name(&crypt_dev, mapper_device) );
     521  		if (!rc) {
     522  			rc = verity_call( crypt_get_verity_info(crypt_dev, &crypt_params) );
     523  			if (!rc) {
     524  				key = calloc(hash_size, 1);
     525  				if (!key) {
     526  					rc = -ENOMEM;
     527  					goto done;
     528  				}
     529  			}
     530  			if (!rc) {
     531  				keysize = hash_size;
     532  				rc = verity_call( crypt_volume_key_get(crypt_dev, CRYPT_ANY_SLOT, key, &keysize, NULL, 0) );
     533  			}
     534  			if (!rc) {
     535  				DBG(HOOK, ul_debugobj(hs, "comparing root hash of existing device with %s", root_hash));
     536  				if (memcmp(key, root_hash_binary, hash_size)) {
     537  					DBG(HOOK, ul_debugobj(hs, "existing device's hash does not match with %s", root_hash));
     538  					rc = -EINVAL;
     539  					goto done;
     540  				}
     541  			} else {
     542  				DBG(HOOK, ul_debugobj(hs, "libcryptsetup does not support extracting root hash of existing device"));
     543  			}
     544  		}
     545  		if (rc) {
     546  			rc = -EEXIST;
     547  		} else {
     548  			/*
     549  			 * Ensure that, if signatures are supported, we only reuse the device if the previous mount
     550  			 * used the same settings, so that a previous unsigned mount will not be reused if the user
     551  			 * asks to use signing for the new one, and viceversa.
     552  			 */
     553  #ifdef HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
     554  			if (!!hash_sig != !!(crypt_params.flags & CRYPT_VERITY_ROOT_HASH_SIGNATURE)) {
     555  				rc = -EINVAL;
     556  				DBG(HOOK, ul_debugobj(hs, "existing device and new mount have to either be both opened with signature or both without"));
     557  				goto done;
     558  			}
     559  #endif
     560  			DBG(HOOK, ul_debugobj(hs, "root hash of %s matches %s, reusing device", mapper_device, root_hash));
     561  		}
     562  	}
     563  
     564  	if (!rc) {
     565  		hsd->devname = calloc(strlen(mapper_device)
     566  					+ sizeof(_PATH_DEV_MAPPER) + 2, sizeof(char));
     567  		if (!hsd->devname)
     568  			rc = -ENOMEM;
     569  		else {
     570  			strcat(hsd->devname, _PATH_DEV_MAPPER "/");
     571  			strcat(hsd->devname, mapper_device);
     572  			rc = mnt_fs_set_source(cxt->fs, hsd->devname);
     573  		}
     574  	}
     575  
     576  done:
     577  	verity_call( crypt_free(crypt_dev) );
     578  
     579  	free(root_hash_binary);
     580  	free(mapper_device);
     581  	free(root_hash);
     582  	free(hash_sig);
     583  	free(key);
     584  	return rc;
     585  }
     586  /* call after mount(2) */
     587  static int hook_mount_post(
     588  			struct libmnt_context *cxt,
     589  			const struct libmnt_hookset *hs,
     590  			void *data __attribute__((__unused__)))
     591  {
     592  
     593  	delete_veritydev(cxt, hs, mnt_context_get_hookset_data(cxt, hs));
     594  	return 0;
     595  }
     596  
     597  /*
     598   * first call (first callback in this hookset)
     599   */
     600  static int hook_prepare_source(
     601                          struct libmnt_context *cxt,
     602                          const struct libmnt_hookset *hs,
     603                          void *data __attribute__((__unused__)))
     604  {
     605  	struct libmnt_optlist *ol;
     606  	struct hookset_data *hsd;
     607  	int rc;
     608  
     609  	assert(cxt);
     610  
     611  	ol = mnt_context_get_optlist(cxt);
     612  	if (!ol)
     613  		return -ENOMEM;
     614  
     615  	if (!is_veritydev_required(cxt, hs, ol))
     616  		return 0;
     617  
     618  	hsd = new_hookset_data(cxt, hs);
     619  	if (!hsd)
     620  		return -ENOMEM;
     621  
     622  	rc = setup_veritydev(cxt, hs, hsd, ol);
     623  	if (!rc) {
     624  		rc = mnt_context_append_hook(cxt, hs,
     625  				MNT_STAGE_MOUNT_POST,
     626  				NULL, hook_mount_post);
     627  		if (rc)
     628  			delete_veritydev(cxt, hs, hsd);
     629  	}
     630  	return rc;
     631  }
     632  
     633  
     634  const struct libmnt_hookset hookset_veritydev =
     635  {
     636  	.name = "__veritydev",
     637  
     638  	.firststage = MNT_STAGE_PREP_SOURCE,
     639  	.firstcall = hook_prepare_source,
     640  
     641  	.deinit = hookset_deinit
     642  };
     643  #endif /*HAVE_CRYPTSETUP*/
     644  
     645  
     646