#include "blkid-util.h"
#include "blockdev-util.h"
#include "copy.h"
-#include "crypt-util.h"
+#include "cryptsetup-util.h"
#include "def.h"
#include "device-nodes.h"
#include "device-util.h"
#include "user-util.h"
#include "xattr-util.h"
+/* how many times to wait for the device nodes to appear */
+#define N_DEVICE_NODE_LIST_ATTEMPTS 10
+
int probe_filesystem(const char *node, char **ret_fstype) {
/* Try to find device content type and return it in *ret_fstype. If nothing is found,
* 0/NULL will be returned. -EUCLEAN will be returned for ambiguous results, and an
return 0;
}
-/* how many times to wait for the device nodes to appear */
-#define N_DEVICE_NODE_LIST_ATTEMPTS 10
-
static int wait_for_partitions_to_appear(
int fd,
sd_device *d,
m->verity = root_hash && verity_data;
m->can_verity = !!verity_data;
- options = mount_options_from_part(mount_options, 0);
+ options = mount_options_from_designator(mount_options, PARTITION_ROOT);
if (options) {
o = strdup(options);
if (!o)
if (!n)
return -ENOMEM;
- options = mount_options_from_part(mount_options, nr);
+ options = mount_options_from_designator(mount_options, designator);
if (options) {
o = strdup(options);
if (!o)
if (!n)
return -ENOMEM;
- options = mount_options_from_part(mount_options, nr);
+ options = mount_options_from_designator(mount_options, PARTITION_XBOOTLDR);
if (options) {
o = strdup(options);
if (!o)
_cleanup_free_ char *o = NULL;
const char *options = NULL;
- /* If the root has was set, then we won't fallback to a generic node, because the root hash
- * decides */
+ /* If the root hash was set, then we won't fall back to a generic node, because the
+ * root hash decides. */
if (root_hash)
return -EADDRNOTAVAIL;
if (multiple_generic)
return -ENOTUNIQ;
- options = mount_options_from_part(mount_options, generic_nr);
+ options = mount_options_from_designator(mount_options, PARTITION_ROOT);
if (options) {
o = strdup(options);
if (!o)
assert(m);
assert(where);
+ /* Use decrypted node and matching fstype if available, otherwise use the original device */
node = m->decrypted_node ?: m->node;
- fstype = m->decrypted_fstype ?: m->fstype;
+ fstype = m->decrypted_node ? m->decrypted_fstype: m->fstype;
- if (!m->found || !node || !fstype)
+ if (!m->found || !node)
return 0;
+ if (!fstype)
+ return -EAFNOSUPPORT;
/* We are looking at an encrypted partition? This either means stacked encryption, or the caller didn't call dissected_image_decrypt() beforehand. Let's return a recognizable error for this case. */
- if (streq_ptr(fstype, "crypto_LUKS"))
+ if (streq(fstype, "crypto_LUKS"))
return -EUNATCH;
rw = m->rw && !(flags & DISSECT_IMAGE_READ_ONLY);
}
if (directory) {
+ if (!FLAGS_SET(flags, DISSECT_IMAGE_READ_ONLY)) {
+ /* Automatically create missing mount points, if necessary. */
+ r = mkdir_p_root(where, directory, uid_shift, (gid_t) uid_shift, 0755);
+ if (r < 0)
+ return r;
+ }
+
r = chase_symlinks(directory, where, CHASE_PREFIX_ROOT, &chased, NULL);
if (r < 0)
return r;
}
int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift, DissectImageFlags flags) {
- int r, boot_mounted;
+ int r, xbootldr_mounted;
assert(m);
assert(where);
* -EUNATCH → Encrypted partition found for which no dm-crypt was set up yet
* -EUCLEAN → fsck for file system failed
* -EBUSY → File system already mounted/used elsewhere (kernel)
+ * -EAFNOSUPPORT → File system type not supported or not known
*/
if (!m->partitions[PARTITION_ROOT].found)
if (r < 0)
return r;
- boot_mounted = mount_partition(m->partitions + PARTITION_XBOOTLDR, where, "/boot", uid_shift, flags);
- if (boot_mounted < 0)
- return boot_mounted;
+ xbootldr_mounted = mount_partition(m->partitions + PARTITION_XBOOTLDR, where, "/boot", uid_shift, flags);
+ if (xbootldr_mounted < 0)
+ return xbootldr_mounted;
if (m->partitions[PARTITION_ESP].found) {
+ int esp_done = false;
+
/* Mount the ESP to /efi if it exists. If it doesn't exist, use /boot instead, but only if it
* exists and is empty, and we didn't already mount the XBOOTLDR partition into it. */
r = chase_symlinks("/efi", where, CHASE_PREFIX_ROOT, NULL, NULL);
- if (r >= 0) {
- r = mount_partition(m->partitions + PARTITION_ESP, where, "/efi", uid_shift, flags);
- if (r < 0)
+ if (r < 0) {
+ if (r != -ENOENT)
return r;
- } else if (boot_mounted <= 0) {
- _cleanup_free_ char *p = NULL;
+ /* /efi doesn't exist. Let's see if /boot is suitable then */
- r = chase_symlinks("/boot", where, CHASE_PREFIX_ROOT, &p, NULL);
- if (r >= 0 && dir_is_empty(p) > 0) {
- r = mount_partition(m->partitions + PARTITION_ESP, where, "/boot", uid_shift, flags);
- if (r < 0)
- return r;
+ if (!xbootldr_mounted) {
+ _cleanup_free_ char *p = NULL;
+
+ r = chase_symlinks("/boot", where, CHASE_PREFIX_ROOT, &p, NULL);
+ if (r < 0) {
+ if (r != -ENOENT)
+ return r;
+ } else if (dir_is_empty(p) > 0) {
+ /* It exists and is an empty directory. Let's mount the ESP there. */
+ r = mount_partition(m->partitions + PARTITION_ESP, where, "/boot", uid_shift, flags);
+ if (r < 0)
+ return r;
+
+ esp_done = true;
+ }
}
}
+
+ if (!esp_done) {
+ /* OK, let's mount the ESP now to /efi (possibly creating the dir if missing) */
+
+ r = mount_partition(m->partitions + PARTITION_ESP, where, "/efi", uid_shift, flags);
+ if (r < 0)
+ return r;
+ }
}
return 0;
return log_error_errno(r, "File system check on image failed.");
if (r == -EBUSY)
return log_error_errno(r, "File system already mounted elsewhere.");
+ if (r == -EAFNOSUPPORT)
+ return log_error_errno(r, "File system type not supported or not known.");
if (r < 0)
return log_error_errno(r, "Failed to mount image: %m");
DecryptedPartition *p = d->decrypted + i;
if (p->device && p->name && !p->relinquished) {
- r = crypt_deactivate(p->device, p->name);
+ r = sym_crypt_deactivate_by_name(p->device, p->name, 0);
if (r < 0)
log_debug_errno(r, "Failed to deactivate encrypted partition %s", p->name);
}
if (p->device)
- crypt_free(p->device);
+ sym_crypt_free(p->device);
free(p->name);
}
if (!filename_is_valid(name))
return -EINVAL;
- node = path_join(crypt_get_dir(), name);
+ node = path_join(sym_crypt_get_dir(), name);
if (!node)
return -ENOMEM;
DecryptedImage *d) {
_cleanup_free_ char *node = NULL, *name = NULL;
- _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
+ _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
int r;
assert(m);
if (!passphrase)
return -ENOKEY;
+ r = dlopen_cryptsetup();
+ if (r < 0)
+ return r;
+
r = make_dm_name_and_node(m->node, "-decrypted", &name, &node);
if (r < 0)
return r;
if (!GREEDY_REALLOC0(d->decrypted, d->n_allocated, d->n_decrypted + 1))
return -ENOMEM;
- r = crypt_init(&cd, m->node);
+ r = sym_crypt_init(&cd, m->node);
if (r < 0)
return log_debug_errno(r, "Failed to initialize dm-crypt: %m");
cryptsetup_enable_logging(cd);
- r = crypt_load(cd, CRYPT_LUKS, NULL);
+ r = sym_crypt_load(cd, CRYPT_LUKS, NULL);
if (r < 0)
return log_debug_errno(r, "Failed to load LUKS metadata: %m");
- r = crypt_activate_by_passphrase(cd, name, CRYPT_ANY_SLOT, passphrase, strlen(passphrase),
- ((flags & DISSECT_IMAGE_READ_ONLY) ? CRYPT_ACTIVATE_READONLY : 0) |
- ((flags & DISSECT_IMAGE_DISCARD_ON_CRYPTO) ? CRYPT_ACTIVATE_ALLOW_DISCARDS : 0));
+ r = sym_crypt_activate_by_passphrase(cd, name, CRYPT_ANY_SLOT, passphrase, strlen(passphrase),
+ ((flags & DISSECT_IMAGE_READ_ONLY) ? CRYPT_ACTIVATE_READONLY : 0) |
+ ((flags & DISSECT_IMAGE_DISCARD_ON_CRYPTO) ? CRYPT_ACTIVATE_ALLOW_DISCARDS : 0));
if (r < 0) {
log_debug_errno(r, "Failed to activate LUKS device: %m");
return r == -EPERM ? -EKEYREJECTED : r;
static int verity_can_reuse(const void *root_hash, size_t root_hash_size, bool has_sig, const char *name, struct crypt_device **ret_cd) {
/* If the same volume was already open, check that the root hashes match, and reuse it if they do */
_cleanup_free_ char *root_hash_existing = NULL;
- _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
+ _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
struct crypt_params_verity crypt_params = {};
size_t root_hash_existing_size = root_hash_size;
int r;
assert(ret_cd);
- r = crypt_init_by_name(&cd, name);
+ r = sym_crypt_init_by_name(&cd, name);
if (r < 0)
return log_debug_errno(r, "Error opening verity device, crypt_init_by_name failed: %m");
- r = crypt_get_verity_info(cd, &crypt_params);
+
+ r = sym_crypt_get_verity_info(cd, &crypt_params);
if (r < 0)
return log_debug_errno(r, "Error opening verity device, crypt_get_verity_info failed: %m");
+
root_hash_existing = malloc0(root_hash_size);
if (!root_hash_existing)
return -ENOMEM;
- r = crypt_volume_key_get(cd, CRYPT_ANY_SLOT, root_hash_existing, &root_hash_existing_size, NULL, 0);
+
+ r = sym_crypt_volume_key_get(cd, CRYPT_ANY_SLOT, root_hash_existing, &root_hash_existing_size, NULL, 0);
if (r < 0)
return log_debug_errno(r, "Error opening verity device, crypt_volume_key_get failed: %m");
if (root_hash_size != root_hash_existing_size || memcmp(root_hash_existing, root_hash, root_hash_size) != 0)
static inline void dm_deferred_remove_clean(char *name) {
if (!name)
return;
- (void) crypt_deactivate_by_name(NULL, name, CRYPT_DEACTIVATE_DEFERRED);
+
+ (void) sym_crypt_deactivate_by_name(NULL, name, CRYPT_DEACTIVATE_DEFERRED);
free(name);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(char *, dm_deferred_remove_clean);
DecryptedImage *d) {
_cleanup_free_ char *node = NULL, *name = NULL, *hash_sig_from_file = NULL;
- _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
+ _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(dm_deferred_remove_cleanp) char *restore_deferred_remove = NULL;
int r;
return 0;
}
+ r = dlopen_cryptsetup();
+ if (r < 0)
+ return r;
+
if (FLAGS_SET(flags, DISSECT_IMAGE_VERITY_SHARE)) {
/* Use the roothash, which is unique per volume, as the device node name, so that it can be reused */
_cleanup_free_ char *root_hash_encoded = NULL;
+
root_hash_encoded = hexmem(root_hash, root_hash_size);
if (!root_hash_encoded)
+
return -ENOMEM;
r = make_dm_name_and_node(root_hash_encoded, "-verity", &name, &node);
} else
return r;
}
- r = crypt_init(&cd, verity_data ?: v->node);
+ r = sym_crypt_init(&cd, verity_data ?: v->node);
if (r < 0)
return r;
cryptsetup_enable_logging(cd);
- r = crypt_load(cd, CRYPT_VERITY, NULL);
+ r = sym_crypt_load(cd, CRYPT_VERITY, NULL);
if (r < 0)
return r;
- r = crypt_set_data_device(cd, m->node);
+ r = sym_crypt_set_data_device(cd, m->node);
if (r < 0)
return r;
for (unsigned i = 0; i < N_DEVICE_NODE_LIST_ATTEMPTS; i++) {
if (root_hash_sig || hash_sig_from_file) {
#if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY
- r = crypt_activate_by_signed_key(cd, name, root_hash, root_hash_size, root_hash_sig ?: hash_sig_from_file, root_hash_sig_size, CRYPT_ACTIVATE_READONLY);
+ r = sym_crypt_activate_by_signed_key(cd, name, root_hash, root_hash_size, root_hash_sig ?: hash_sig_from_file, root_hash_sig_size, CRYPT_ACTIVATE_READONLY);
#else
r = log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "activation of verity device with signature requested, but not supported by cryptsetup due to missing crypt_activate_by_signed_key()");
#endif
} else
- r = crypt_activate_by_volume_key(cd, name, root_hash, root_hash_size, CRYPT_ACTIVATE_READONLY);
+ r = sym_crypt_activate_by_volume_key(cd, name, root_hash, root_hash_size, CRYPT_ACTIVATE_READONLY);
/* libdevmapper can return EINVAL when the device is already in the activation stage.
* There's no way to distinguish this situation from a genuine error due to invalid
- * parameters, so immediately fallback to activating the device with a unique name.
+ * parameters, so immediately fall back to activating the device with a unique name.
* Improvements in libcrypsetup can ensure this never happens: https://gitlab.com/cryptsetup/cryptsetup/-/merge_requests/96 */
if (r == -EINVAL && FLAGS_SET(flags, DISSECT_IMAGE_VERITY_SHARE))
return verity_partition(m, v, root_hash, root_hash_size, verity_data, NULL, root_hash_sig ?: hash_sig_from_file, root_hash_sig_size, flags & ~DISSECT_IMAGE_VERITY_SHARE, d);
return r;
if (cd)
- crypt_free(cd);
+ sym_crypt_free(cd);
cd = existing_cd;
}
}
if (p->relinquished)
continue;
- r = crypt_deactivate_by_name(NULL, p->name, CRYPT_DEACTIVATE_DEFERRED);
+ r = sym_crypt_deactivate_by_name(NULL, p->name, CRYPT_DEACTIVATE_DEFERRED);
if (r < 0)
return log_debug_errno(r, "Failed to mark %s for auto-removal: %m", p->name);
return NULL;
}
-const char* mount_options_from_part(const MountOptions *options, unsigned int partition_number) {
- MountOptions *m;
+const char* mount_options_from_designator(const MountOptions *options, int designator) {
+ const MountOptions *m;
- LIST_FOREACH(mount_options, m, (MountOptions *)options)
- if (partition_number == m->partition_number && !isempty(m->options))
+ LIST_FOREACH(mount_options, m, options)
+ if (designator == m->partition_designator && !isempty(m->options))
return m->options;
return NULL;