mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-11 05:17:44 +03:00
dissect-image: Explicitly remove partitions when done with image
When closing a loop device, the kernel will asynchronously remove the probed partitions. This can lead to race conditions where we try to reuse a partition device that still needs to be removed by the kernel. To avoid such issues, let's explicitly try to remove any partitions using BLKPG_DEL_PARTITION when we're done with an image. To make sure we don't try to remove partitions when we want them to remain (e.g. systemd-dissect --mount), we add dissected_image_relinquish() in a similar vein to loop_device_relinquish() and decrypted_image_relinquish().
This commit is contained in:
parent
af72115412
commit
75d7e04eb4
@ -2426,6 +2426,7 @@ int setup_namespace(
|
||||
}
|
||||
}
|
||||
|
||||
dissected_image_relinquish(dissected_image);
|
||||
loop_device_relinquish(loop_device);
|
||||
|
||||
} else if (root_directory) {
|
||||
|
@ -648,6 +648,7 @@ static int action_mount(DissectedImage *m, LoopDevice *d) {
|
||||
return log_error_errno(r, "Failed to relinquish DM devices: %m");
|
||||
}
|
||||
|
||||
dissected_image_relinquish(m);
|
||||
loop_device_relinquish(d);
|
||||
return 0;
|
||||
}
|
||||
@ -700,6 +701,7 @@ static int action_copy(DissectedImage *m, LoopDevice *d) {
|
||||
return log_error_errno(r, "Failed to relinquish DM devices: %m");
|
||||
}
|
||||
|
||||
dissected_image_relinquish(m);
|
||||
loop_device_relinquish(d);
|
||||
|
||||
if (arg_action == ACTION_COPY_FROM) {
|
||||
|
@ -768,6 +768,8 @@ static int enumerate_partitions(dev_t devnum) {
|
||||
r = k;
|
||||
}
|
||||
|
||||
dissected_image_relinquish(m);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -148,11 +148,45 @@ static void check_partition_flags(
|
||||
log_debug("Unexpected partition flag %llu set on %s!", bit, node);
|
||||
}
|
||||
}
|
||||
|
||||
static int ioctl_partition_remove(int fd, const char *name, int nr) {
|
||||
assert(fd >= 0);
|
||||
assert(name);
|
||||
assert(nr > 0);
|
||||
|
||||
struct blkpg_partition bp = {
|
||||
.pno = nr,
|
||||
};
|
||||
|
||||
struct blkpg_ioctl_arg ba = {
|
||||
.op = BLKPG_DEL_PARTITION,
|
||||
.data = &bp,
|
||||
.datalen = sizeof(bp),
|
||||
};
|
||||
|
||||
if (strlen(name) >= sizeof(bp.devname))
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(bp.devname, name);
|
||||
|
||||
return RET_NERRNO(ioctl(fd, BLKPG, &ba));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void dissected_partition_done(DissectedPartition *p) {
|
||||
static void dissected_partition_done(int fd, DissectedPartition *p) {
|
||||
assert(fd >= 0);
|
||||
assert(p);
|
||||
|
||||
#if HAVE_BLKID
|
||||
if (p->node && p->partno > 0 && !p->relinquished) {
|
||||
int r;
|
||||
|
||||
r = ioctl_partition_remove(fd, p->node, p->partno);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "BLKPG_DEL_PARTITION failed, ignoring: %m");
|
||||
}
|
||||
#endif
|
||||
|
||||
free(p->fstype);
|
||||
free(p->node);
|
||||
free(p->label);
|
||||
@ -332,9 +366,14 @@ int dissect_image(
|
||||
return -ENOMEM;
|
||||
|
||||
*m = (DissectedImage) {
|
||||
.fd = -1,
|
||||
.has_init_system = -1,
|
||||
};
|
||||
|
||||
m->fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
|
||||
if (m->fd < 0)
|
||||
return -errno;
|
||||
|
||||
r = sd_device_get_sysname(d, &sysname);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to get device sysname: %m");
|
||||
@ -790,10 +829,14 @@ int dissect_image(
|
||||
* scheme in OS images. */
|
||||
|
||||
if (!PARTITION_DESIGNATOR_VERSIONED(designator) ||
|
||||
strverscmp_improved(m->partitions[designator].label, label) >= 0)
|
||||
strverscmp_improved(m->partitions[designator].label, label) >= 0) {
|
||||
r = ioctl_partition_remove(fd, node, nr);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "BLKPG_DEL_PARTITION failed, ignoring: %m");
|
||||
continue;
|
||||
}
|
||||
|
||||
dissected_partition_done(m->partitions + designator);
|
||||
dissected_partition_done(fd, m->partitions + designator);
|
||||
}
|
||||
|
||||
if (fstype) {
|
||||
@ -863,8 +906,12 @@ int dissect_image(
|
||||
const char *sid, *options = NULL;
|
||||
|
||||
/* First one wins */
|
||||
if (m->partitions[PARTITION_XBOOTLDR].found)
|
||||
if (m->partitions[PARTITION_XBOOTLDR].found) {
|
||||
r = ioctl_partition_remove(fd, node, nr);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "BLKPG_DEL_PARTITION failed, ignoring: %m");
|
||||
continue;
|
||||
}
|
||||
|
||||
sid = blkid_partition_get_uuid(pp);
|
||||
if (sid)
|
||||
@ -1178,8 +1225,9 @@ DissectedImage* dissected_image_unref(DissectedImage *m) {
|
||||
return NULL;
|
||||
|
||||
for (PartitionDesignator i = 0; i < _PARTITION_DESIGNATOR_MAX; i++)
|
||||
dissected_partition_done(m->partitions + i);
|
||||
dissected_partition_done(m->fd, m->partitions + i);
|
||||
|
||||
safe_close(m->fd);
|
||||
free(m->image_name);
|
||||
free(m->hostname);
|
||||
strv_free(m->machine_info);
|
||||
@ -1189,6 +1237,16 @@ DissectedImage* dissected_image_unref(DissectedImage *m) {
|
||||
return mfree(m);
|
||||
}
|
||||
|
||||
void dissected_image_relinquish(DissectedImage *m) {
|
||||
assert(m);
|
||||
|
||||
/* Partitions are automatically removed when the underlying loop device is closed. We just need to
|
||||
* make sure we don't try to remove the partitions early. */
|
||||
|
||||
for (PartitionDesignator i = 0; i < _PARTITION_DESIGNATOR_MAX; i++)
|
||||
m->partitions[i].relinquished = true;
|
||||
}
|
||||
|
||||
static int is_loop_device(const char *path) {
|
||||
char s[SYS_BLOCK_PATH_MAX("/../loop/")];
|
||||
struct stat st;
|
||||
@ -3023,6 +3081,7 @@ int mount_image_privately_interactively(
|
||||
return log_error_errno(r, "Failed to relinquish DM devices: %m");
|
||||
}
|
||||
|
||||
dissected_image_relinquish(dissected_image);
|
||||
loop_device_relinquish(d);
|
||||
|
||||
*ret_directory = TAKE_PTR(created_dir);
|
||||
@ -3183,6 +3242,7 @@ int verity_dissect_and_mount(
|
||||
return log_debug_errno(r, "Failed to relinquish decrypted image: %m");
|
||||
}
|
||||
|
||||
dissected_image_relinquish(dissected_image);
|
||||
loop_device_relinquish(loop_device);
|
||||
|
||||
return 0;
|
||||
|
@ -31,6 +31,7 @@ struct DissectedPartition {
|
||||
char *mount_options;
|
||||
uint64_t size;
|
||||
uint64_t offset;
|
||||
bool relinquished;
|
||||
};
|
||||
|
||||
typedef enum PartitionDesignator {
|
||||
@ -203,6 +204,8 @@ typedef enum DissectImageFlags {
|
||||
} DissectImageFlags;
|
||||
|
||||
struct DissectedImage {
|
||||
int fd; /* Backing fd */
|
||||
|
||||
bool encrypted:1;
|
||||
bool has_verity:1; /* verity available in image, but not necessarily used */
|
||||
bool has_verity_sig:1; /* pkcs#7 signature embedded in image */
|
||||
@ -258,6 +261,7 @@ int dissect_image_and_warn(int fd, const char *name, const VeritySettings *verit
|
||||
|
||||
DissectedImage* dissected_image_unref(DissectedImage *m);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref);
|
||||
void dissected_image_relinquish(DissectedImage *m);
|
||||
|
||||
int dissected_image_decrypt(DissectedImage *m, const char *passphrase, const VeritySettings *verity, DissectImageFlags flags, DecryptedImage **ret);
|
||||
int dissected_image_decrypt_interactively(DissectedImage *m, const char *passphrase, const VeritySettings *verity, DissectImageFlags flags, DecryptedImage **ret);
|
||||
|
@ -584,6 +584,7 @@ static int merge_subprocess(Hashmap *images, const char *workspace) {
|
||||
return log_error_errno(r, "Failed to relinquish DM devices: %m");
|
||||
}
|
||||
|
||||
dissected_image_relinquish(m);
|
||||
loop_device_relinquish(d);
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user