mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-08-31 09:50:11 +03:00
dissect-image: optionally, reference dissected partition device nodes by diskseq
This is useful to make the dissection logic at boot a bit safer, as we can reference device nodes by diskseq. This locks down dissection a bit, since it makes it harder to swap out the backing device between the time we dissected and validated it, until we actually mounted it. This is not complete though, as /bin/mount would have to verify the diskseq after opening the diskseq symlink again. See: https://github.com/util-linux/util-linux/issues/1786
This commit is contained in:
@ -322,28 +322,57 @@ static void dissected_partition_done(DissectedPartition *p) {
|
|||||||
#if HAVE_BLKID
|
#if HAVE_BLKID
|
||||||
static int make_partition_devname(
|
static int make_partition_devname(
|
||||||
const char *whole_devname,
|
const char *whole_devname,
|
||||||
|
uint64_t diskseq,
|
||||||
int nr,
|
int nr,
|
||||||
|
DissectImageFlags flags,
|
||||||
char **ret) {
|
char **ret) {
|
||||||
|
|
||||||
bool need_p;
|
_cleanup_free_ char *s = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(whole_devname);
|
assert(whole_devname);
|
||||||
assert(nr > 0);
|
assert(nr != 0); /* zero is not a valid partition nr */
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
/* Given a whole block device node name (e.g. /dev/sda or /dev/loop7) generate a partition device
|
if (!FLAGS_SET(flags, DISSECT_IMAGE_DISKSEQ_DEVNODE) || diskseq == UINT64_MAX) {
|
||||||
* name (e.g. /dev/sda7 or /dev/loop7p5). The rule the kernel uses is simple: if whole block device
|
|
||||||
* node name ends in a digit, then suffix a 'p', followed by the partition number. Otherwise, just
|
|
||||||
* suffix the partition number without any 'p'. */
|
|
||||||
|
|
||||||
if (isempty(whole_devname)) /* Make sure there *is* a last char */
|
/* Given a whole block device node name (e.g. /dev/sda or /dev/loop7) generate a partition
|
||||||
|
* device name (e.g. /dev/sda7 or /dev/loop7p5). The rule the kernel uses is simple: if whole
|
||||||
|
* block device node name ends in a digit, then suffix a 'p', followed by the partition
|
||||||
|
* number. Otherwise, just suffix the partition number without any 'p'. */
|
||||||
|
|
||||||
|
if (nr < 0) { /* whole disk? */
|
||||||
|
s = strdup(whole_devname);
|
||||||
|
if (!s)
|
||||||
|
return -ENOMEM;
|
||||||
|
} else {
|
||||||
|
size_t l = strlen(whole_devname);
|
||||||
|
if (l < 1) /* underflow check for the subtraction below */
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
need_p = ascii_isdigit(whole_devname[strlen(whole_devname)-1]); /* Last char a digit? */
|
bool need_p = ascii_isdigit(whole_devname[l-1]); /* Last char a digit? */
|
||||||
|
|
||||||
return asprintf(ret, "%s%s%i", whole_devname, need_p ? "p" : "", nr);
|
if (asprintf(&s, "%s%s%i", whole_devname, need_p ? "p" : "", nr) < 0)
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (nr < 0) /* whole disk? */
|
||||||
|
r = asprintf(&s, "/dev/disk/by-diskseq/%" PRIu64, diskseq);
|
||||||
|
else
|
||||||
|
r = asprintf(&s, "/dev/disk/by-diskseq/%" PRIu64 "-part%i", diskseq, nr);
|
||||||
|
if (r < 0)
|
||||||
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int open_partition(const char *node, bool is_partition, const LoopDevice *loop) {
|
*ret = TAKE_PTR(s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int open_partition(
|
||||||
|
const char *node,
|
||||||
|
bool is_partition,
|
||||||
|
const LoopDevice *loop) {
|
||||||
|
|
||||||
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
|
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
|
||||||
_cleanup_close_ int fd = -EBADF;
|
_cleanup_close_ int fd = -EBADF;
|
||||||
dev_t devnum;
|
dev_t devnum;
|
||||||
@ -442,6 +471,8 @@ static int dissect_image(
|
|||||||
* Returns -ENXIO if we couldn't find any partition suitable as root or /usr partition
|
* Returns -ENXIO if we couldn't find any partition suitable as root or /usr partition
|
||||||
* Returns -ENOTUNIQ if we only found multiple generic partitions and thus don't know what to do with that */
|
* Returns -ENOTUNIQ if we only found multiple generic partitions and thus don't know what to do with that */
|
||||||
|
|
||||||
|
uint64_t diskseq = m->loop ? m->loop->diskseq : UINT64_MAX;
|
||||||
|
|
||||||
if (verity && verity->root_hash) {
|
if (verity && verity->root_hash) {
|
||||||
sd_id128_t fsuuid, vuuid;
|
sd_id128_t fsuuid, vuuid;
|
||||||
|
|
||||||
@ -537,9 +568,9 @@ static int dissect_image(
|
|||||||
log_debug_errno(r, "Failed to parse file system UUID '%s', ignoring: %m", suuid);
|
log_debug_errno(r, "Failed to parse file system UUID '%s', ignoring: %m", suuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
n = strdup(devname);
|
r = make_partition_devname(devname, diskseq, -1, flags, &n);
|
||||||
if (!n)
|
if (r < 0)
|
||||||
return -ENOMEM;
|
return r;
|
||||||
|
|
||||||
m->single_file_system = true;
|
m->single_file_system = true;
|
||||||
m->encrypted = streq_ptr(fstype, "crypto_LUKS");
|
m->encrypted = streq_ptr(fstype, "crypto_LUKS");
|
||||||
@ -650,7 +681,9 @@ static int dissect_image(
|
|||||||
|
|
||||||
assert((uint64_t) size < UINT64_MAX/512);
|
assert((uint64_t) size < UINT64_MAX/512);
|
||||||
|
|
||||||
r = make_partition_devname(devname, nr, &node);
|
/* While probing we need the non-diskseq device node name to access the thing, hence mask off
|
||||||
|
* DISSECT_IMAGE_DISKSEQ_DEVNODE. */
|
||||||
|
r = make_partition_devname(devname, diskseq, nr, flags & ~DISSECT_IMAGE_DISKSEQ_DEVNODE, &node);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -901,7 +934,7 @@ static int dissect_image(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (type.designator != _PARTITION_DESIGNATOR_INVALID) {
|
if (type.designator != _PARTITION_DESIGNATOR_INVALID) {
|
||||||
_cleanup_free_ char *t = NULL, *o = NULL, *l = NULL;
|
_cleanup_free_ char *t = NULL, *o = NULL, *l = NULL, *n = NULL;
|
||||||
_cleanup_close_ int mount_node_fd = -EBADF;
|
_cleanup_close_ int mount_node_fd = -EBADF;
|
||||||
const char *options = NULL;
|
const char *options = NULL;
|
||||||
|
|
||||||
@ -928,6 +961,10 @@ static int dissect_image(
|
|||||||
return mount_node_fd;
|
return mount_node_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = make_partition_devname(devname, diskseq, nr, flags, &n);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
if (fstype) {
|
if (fstype) {
|
||||||
t = strdup(fstype);
|
t = strdup(fstype);
|
||||||
if (!t)
|
if (!t)
|
||||||
@ -953,7 +990,7 @@ static int dissect_image(
|
|||||||
.rw = rw,
|
.rw = rw,
|
||||||
.growfs = growfs,
|
.growfs = growfs,
|
||||||
.architecture = type.arch,
|
.architecture = type.arch,
|
||||||
.node = TAKE_PTR(node),
|
.node = TAKE_PTR(n),
|
||||||
.fstype = TAKE_PTR(t),
|
.fstype = TAKE_PTR(t),
|
||||||
.label = TAKE_PTR(l),
|
.label = TAKE_PTR(l),
|
||||||
.uuid = id,
|
.uuid = id,
|
||||||
@ -987,7 +1024,7 @@ static int dissect_image(
|
|||||||
|
|
||||||
case 0xEA: { /* Boot Loader Spec extended $BOOT partition */
|
case 0xEA: { /* Boot Loader Spec extended $BOOT partition */
|
||||||
_cleanup_close_ int mount_node_fd = -EBADF;
|
_cleanup_close_ int mount_node_fd = -EBADF;
|
||||||
_cleanup_free_ char *o = NULL;
|
_cleanup_free_ char *o = NULL, *n = NULL;
|
||||||
sd_id128_t id = SD_ID128_NULL;
|
sd_id128_t id = SD_ID128_NULL;
|
||||||
const char *options = NULL;
|
const char *options = NULL;
|
||||||
|
|
||||||
@ -1003,6 +1040,10 @@ static int dissect_image(
|
|||||||
|
|
||||||
(void) blkid_partition_get_uuid_id128(pp, &id);
|
(void) blkid_partition_get_uuid_id128(pp, &id);
|
||||||
|
|
||||||
|
r = make_partition_devname(devname, diskseq, nr, flags, &n);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
options = mount_options_from_designator(mount_options, PARTITION_XBOOTLDR);
|
options = mount_options_from_designator(mount_options, PARTITION_XBOOTLDR);
|
||||||
if (options) {
|
if (options) {
|
||||||
o = strdup(options);
|
o = strdup(options);
|
||||||
@ -1016,7 +1057,7 @@ static int dissect_image(
|
|||||||
.rw = true,
|
.rw = true,
|
||||||
.growfs = false,
|
.growfs = false,
|
||||||
.architecture = _ARCHITECTURE_INVALID,
|
.architecture = _ARCHITECTURE_INVALID,
|
||||||
.node = TAKE_PTR(node),
|
.node = TAKE_PTR(n),
|
||||||
.uuid = id,
|
.uuid = id,
|
||||||
.mount_options = TAKE_PTR(o),
|
.mount_options = TAKE_PTR(o),
|
||||||
.mount_node_fd = TAKE_FD(mount_node_fd),
|
.mount_node_fd = TAKE_FD(mount_node_fd),
|
||||||
@ -1072,7 +1113,7 @@ static int dissect_image(
|
|||||||
/* If we didn't find a generic node, then we can't fix this up either */
|
/* If we didn't find a generic node, then we can't fix this up either */
|
||||||
if (generic_node) {
|
if (generic_node) {
|
||||||
_cleanup_close_ int mount_node_fd = -EBADF;
|
_cleanup_close_ int mount_node_fd = -EBADF;
|
||||||
_cleanup_free_ char *o = NULL;
|
_cleanup_free_ char *o = NULL, *n = NULL;
|
||||||
const char *options;
|
const char *options;
|
||||||
|
|
||||||
if (FLAGS_SET(flags, DISSECT_IMAGE_PIN_PARTITION_DEVICES)) {
|
if (FLAGS_SET(flags, DISSECT_IMAGE_PIN_PARTITION_DEVICES)) {
|
||||||
@ -1081,6 +1122,10 @@ static int dissect_image(
|
|||||||
return mount_node_fd;
|
return mount_node_fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = make_partition_devname(devname, diskseq, generic_nr, flags, &n);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
options = mount_options_from_designator(mount_options, PARTITION_ROOT);
|
options = mount_options_from_designator(mount_options, PARTITION_ROOT);
|
||||||
if (options) {
|
if (options) {
|
||||||
o = strdup(options);
|
o = strdup(options);
|
||||||
@ -1095,7 +1140,7 @@ static int dissect_image(
|
|||||||
.growfs = generic_growfs,
|
.growfs = generic_growfs,
|
||||||
.partno = generic_nr,
|
.partno = generic_nr,
|
||||||
.architecture = _ARCHITECTURE_INVALID,
|
.architecture = _ARCHITECTURE_INVALID,
|
||||||
.node = TAKE_PTR(generic_node),
|
.node = TAKE_PTR(n),
|
||||||
.uuid = generic_uuid,
|
.uuid = generic_uuid,
|
||||||
.mount_options = TAKE_PTR(o),
|
.mount_options = TAKE_PTR(o),
|
||||||
.mount_node_fd = TAKE_FD(mount_node_fd),
|
.mount_node_fd = TAKE_FD(mount_node_fd),
|
||||||
|
@ -78,6 +78,7 @@ typedef enum DissectImageFlags {
|
|||||||
DISSECT_IMAGE_ADD_PARTITION_DEVICES = 1 << 20, /* Create partition devices via BLKPG_ADD_PARTITION */
|
DISSECT_IMAGE_ADD_PARTITION_DEVICES = 1 << 20, /* Create partition devices via BLKPG_ADD_PARTITION */
|
||||||
DISSECT_IMAGE_PIN_PARTITION_DEVICES = 1 << 21, /* Open dissected partitions and decrypted partitions and pin them by fd */
|
DISSECT_IMAGE_PIN_PARTITION_DEVICES = 1 << 21, /* Open dissected partitions and decrypted partitions and pin them by fd */
|
||||||
DISSECT_IMAGE_RELAX_SYSEXT_CHECK = 1 << 22, /* Don't insist that the extension-release file name matches the image name */
|
DISSECT_IMAGE_RELAX_SYSEXT_CHECK = 1 << 22, /* Don't insist that the extension-release file name matches the image name */
|
||||||
|
DISSECT_IMAGE_DISKSEQ_DEVNODE = 1 << 23, /* Prefer /dev/disk/by-diskseq/… device nodes */
|
||||||
} DissectImageFlags;
|
} DissectImageFlags;
|
||||||
|
|
||||||
struct DissectedImage {
|
struct DissectedImage {
|
||||||
|
Reference in New Issue
Block a user