diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index a0eac0f24c..eb319a9ff9 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -1130,9 +1130,18 @@ DissectedImage* dissected_image_unref(DissectedImage *m) { if (!m) return NULL; + /* First, clear dissected partitions. */ for (PartitionDesignator i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) dissected_partition_done(m->partitions + i); + /* Second, free decrypted images. This must be after dissected_partition_done(), as freeing + * DecryptedImage may try to deactivate partitions. */ + decrypted_image_unref(m->decrypted_image); + + /* Third, unref LoopDevice. This must be called after the above two, as freeing LoopDevice may try to + * remove existing partitions on the loopback block device. */ + loop_device_unref(m->loop); + free(m->image_name); free(m->hostname); strv_free(m->machine_info); @@ -1562,19 +1571,22 @@ int dissected_image_mount_and_warn( } #if HAVE_LIBCRYPTSETUP -typedef struct DecryptedPartition { +struct DecryptedPartition { struct crypt_device *device; char *name; bool relinquished; -} DecryptedPartition; - -struct DecryptedImage { - DecryptedPartition *decrypted; - size_t n_decrypted; }; #endif -DecryptedImage* decrypted_image_unref(DecryptedImage* d) { +typedef struct DecryptedPartition DecryptedPartition; + +struct DecryptedImage { + unsigned n_ref; + DecryptedPartition *decrypted; + size_t n_decrypted; +}; + +static DecryptedImage* decrypted_image_free(DecryptedImage *d) { #if HAVE_LIBCRYPTSETUP int r; @@ -1602,7 +1614,25 @@ DecryptedImage* decrypted_image_unref(DecryptedImage* d) { return NULL; } +DEFINE_TRIVIAL_REF_UNREF_FUNC(DecryptedImage, decrypted_image, decrypted_image_free); + #if HAVE_LIBCRYPTSETUP +static int decrypted_image_new(DecryptedImage **ret) { + _cleanup_(decrypted_image_unrefp) DecryptedImage *d = NULL; + + assert(ret); + + d = new(DecryptedImage, 1); + if (!d) + return -ENOMEM; + + *d = (DecryptedImage) { + .n_ref = 1, + }; + + *ret = TAKE_PTR(d); + return 0; +} static int make_dm_name_and_node(const void *original_node, const char *suffix, char **ret_name, char **ret_node) { _cleanup_free_ char *name = NULL, *node = NULL; @@ -2102,14 +2132,15 @@ int dissected_image_decrypt( return -EINVAL; if (!m->encrypted && !m->verity_ready) { - *ret = NULL; + if (ret) + *ret = NULL; return 0; } #if HAVE_LIBCRYPTSETUP - d = new0(DecryptedImage, 1); - if (!d) - return -ENOMEM; + r = decrypted_image_new(&d); + if (r < 0) + return r; for (PartitionDesignator i = 0; i < _PARTITION_DESIGNATOR_MAX; i++) { DissectedPartition *p = m->partitions + i; @@ -2136,7 +2167,9 @@ int dissected_image_decrypt( } } - *ret = TAKE_PTR(d); + m->decrypted_image = TAKE_PTR(d); + if (ret) + *ret = decrypted_image_ref(m->decrypted_image); return 1; #else @@ -2792,8 +2825,31 @@ finish: return r; } +int dissect_loop_device( + LoopDevice *loop, + const VeritySettings *verity, + const MountOptions *mount_options, + DissectImageFlags flags, + DissectedImage **ret) { + + _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL; + int r; + + assert(loop); + assert(ret); + + r = dissect_image(loop->fd, loop->node, loop->backing_file ?: loop->node, verity, mount_options, flags, &m); + if (r < 0) + return r; + + m->loop = loop_device_ref(loop); + + *ret = TAKE_PTR(m); + return 0; +} + int dissect_loop_device_and_warn( - const LoopDevice *loop, + LoopDevice *loop, const VeritySettings *verity, const MountOptions *mount_options, DissectImageFlags flags, diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h index aee8f1c315..c49bff0e5d 100644 --- a/src/shared/dissect-image.h +++ b/src/shared/dissect-image.h @@ -216,7 +216,9 @@ struct DissectedImage { bool verity_sig_ready:1; /* verity signature logic, fully specified and usable */ bool single_file_system:1; /* MBR/GPT or single file system */ + LoopDevice *loop; DissectedPartition partitions[_PARTITION_DESIGNATOR_MAX]; + DecryptedImage *decrypted_image; /* Meta information extracted from /etc/os-release and similar */ char *image_name; @@ -267,11 +269,8 @@ int dissect_image( const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret); -static inline int dissect_loop_device(const LoopDevice *loop, const VeritySettings *verity, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret) { - assert(loop); - return dissect_image(loop->fd, loop->node, loop->backing_file ?: loop->node, verity, mount_options, flags, ret); -} -int dissect_loop_device_and_warn(const LoopDevice *loop, const VeritySettings *verity, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret); +int dissect_loop_device(LoopDevice *loop, const VeritySettings *verity, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret); +int dissect_loop_device_and_warn(LoopDevice *loop, const VeritySettings *verity, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret); DissectedImage* dissected_image_unref(DissectedImage *m); DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref); @@ -283,6 +282,7 @@ int dissected_image_mount_and_warn(DissectedImage *m, const char *where, uid_t u int dissected_image_acquire_metadata(DissectedImage *m, DissectImageFlags extra_flags); +DecryptedImage* decrypted_image_ref(DecryptedImage *p); DecryptedImage* decrypted_image_unref(DecryptedImage *p); DEFINE_TRIVIAL_CLEANUP_FUNC(DecryptedImage*, decrypted_image_unref); int decrypted_image_relinquish(DecryptedImage *d); diff --git a/src/shared/loop-util.c b/src/shared/loop-util.c index 49f4b2bf6e..54251f0fb7 100644 --- a/src/shared/loop-util.c +++ b/src/shared/loop-util.c @@ -369,6 +369,7 @@ static int loop_configure( return -ENOMEM; *d = (LoopDevice) { + .n_ref = 1, .fd = TAKE_FD(loop_with_fd), .lock_fd = TAKE_FD(lock_fd), .node = TAKE_PTR(node), @@ -624,7 +625,7 @@ int loop_device_make_by_path( return loop_device_make_internal(path, fd, open_flags, 0, 0, loop_flags, lock_op, ret); } -LoopDevice* loop_device_unref(LoopDevice *d) { +static LoopDevice* loop_device_free(LoopDevice *d) { _cleanup_close_ int control = -1; int r; @@ -696,6 +697,8 @@ LoopDevice* loop_device_unref(LoopDevice *d) { return mfree(d); } +DEFINE_TRIVIAL_REF_UNREF_FUNC(LoopDevice, loop_device, loop_device_free); + void loop_device_relinquish(LoopDevice *d) { assert(d); @@ -796,6 +799,7 @@ int loop_device_open_full( return -ENOMEM; *d = (LoopDevice) { + .n_ref = 1, .fd = TAKE_FD(fd), .lock_fd = TAKE_FD(lock_fd), .nr = nr, diff --git a/src/shared/loop-util.h b/src/shared/loop-util.h index cb0183ba07..756041adaa 100644 --- a/src/shared/loop-util.h +++ b/src/shared/loop-util.h @@ -11,6 +11,7 @@ typedef struct LoopDevice LoopDevice; /* Some helpers for setting up loopback block devices */ struct LoopDevice { + unsigned n_ref; int fd; int lock_fd; int nr; /* The loopback device index (i.e. 4 for /dev/loop4); if this object encapsulates a non-loopback block device, set to -1 */ @@ -34,6 +35,7 @@ static inline int loop_device_open(const char *loop_path, int open_flags, int lo return loop_device_open_full(loop_path, -1, open_flags, lock_op, ret); } +LoopDevice* loop_device_ref(LoopDevice *d); LoopDevice* loop_device_unref(LoopDevice *d); DEFINE_TRIVIAL_CLEANUP_FUNC(LoopDevice*, loop_device_unref);