]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/dissect-image.h
Merge pull request #24720 from yuwata/dissect-image-take-reference
[thirdparty/systemd.git] / src / shared / dissect-image.h
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
8c1be37e
LP
2#pragma once
3
8c1be37e
LP
4#include <stdbool.h>
5
dccca82b
LP
6#include "sd-id128.h"
7
49ae9d91 8#include "architecture.h"
18d73705 9#include "list.h"
6aa05ebd 10#include "loop-util.h"
8c1be37e
LP
11#include "macro.h"
12
13typedef struct DissectedImage DissectedImage;
14typedef struct DissectedPartition DissectedPartition;
18b5886e 15typedef struct DecryptedImage DecryptedImage;
18d73705 16typedef struct MountOptions MountOptions;
89e62e0b 17typedef struct VeritySettings VeritySettings;
8c1be37e
LP
18
19struct DissectedPartition {
20 bool found:1;
21 bool rw:1;
de98f631 22 bool growfs:1;
6b41a7b2
LP
23 int partno; /* -1 if there was no partition and the images contains a file system directly */
24 Architecture architecture; /* Intended architecture: either native, secondary or unset ARCHITECTURE_INVALID. */
25 sd_id128_t uuid; /* Partition entry UUID as reported by the GPT */
8c1be37e
LP
26 char *fstype;
27 char *node;
08fe0a53 28 char *label;
18b5886e
LP
29 char *decrypted_node;
30 char *decrypted_fstype;
18d73705 31 char *mount_options;
88b3300f
LP
32 uint64_t size;
33 uint64_t offset;
8c1be37e
LP
34};
35
babd5b08
YW
36#define DISSECTED_PARTITION_NULL \
37 ((DissectedPartition) { \
38 .partno = -1, \
39 .architecture = _ARCHITECTURE_INVALID, \
40 })
41
569a0e42 42typedef enum PartitionDesignator {
8c1be37e
LP
43 PARTITION_ROOT,
44 PARTITION_ROOT_SECONDARY, /* Secondary architecture */
49ae9d91 45 PARTITION_ROOT_OTHER,
aee36b4e
LP
46 PARTITION_USR,
47 PARTITION_USR_SECONDARY,
49ae9d91 48 PARTITION_USR_OTHER,
8c1be37e
LP
49 PARTITION_HOME,
50 PARTITION_SRV,
51 PARTITION_ESP,
a8c47660 52 PARTITION_XBOOTLDR,
8c1be37e 53 PARTITION_SWAP,
4623e8e6
LP
54 PARTITION_ROOT_VERITY, /* verity data for the PARTITION_ROOT partition */
55 PARTITION_ROOT_SECONDARY_VERITY, /* verity data for the PARTITION_ROOT_SECONDARY partition */
49ae9d91 56 PARTITION_ROOT_OTHER_VERITY,
aee36b4e
LP
57 PARTITION_USR_VERITY,
58 PARTITION_USR_SECONDARY_VERITY,
49ae9d91 59 PARTITION_USR_OTHER_VERITY,
8ee9615e
LP
60 PARTITION_ROOT_VERITY_SIG, /* PKCS#7 signature for root hash for the PARTITION_ROOT partition */
61 PARTITION_ROOT_SECONDARY_VERITY_SIG, /* ditto for the PARTITION_ROOT_SECONDARY partition */
49ae9d91 62 PARTITION_ROOT_OTHER_VERITY_SIG,
8ee9615e
LP
63 PARTITION_USR_VERITY_SIG,
64 PARTITION_USR_SECONDARY_VERITY_SIG,
49ae9d91 65 PARTITION_USR_OTHER_VERITY_SIG,
d4dffb85
LP
66 PARTITION_TMP,
67 PARTITION_VAR,
8c1be37e 68 _PARTITION_DESIGNATOR_MAX,
2d93c20e 69 _PARTITION_DESIGNATOR_INVALID = -EINVAL,
569a0e42 70} PartitionDesignator;
8c1be37e 71
08fe0a53
LP
72static inline bool PARTITION_DESIGNATOR_VERSIONED(PartitionDesignator d) {
73 /* Returns true for all designators where we want to support a concept of "versioning", i.e. which
74 * likely contain software binaries (or hashes thereof) that make sense to be versioned as a
75 * whole. We use this check to automatically pick the newest version of these partitions, by version
76 * comparing the partition labels. */
77
78 return IN_SET(d,
79 PARTITION_ROOT,
80 PARTITION_ROOT_SECONDARY,
49ae9d91 81 PARTITION_ROOT_OTHER,
08fe0a53
LP
82 PARTITION_USR,
83 PARTITION_USR_SECONDARY,
49ae9d91 84 PARTITION_USR_OTHER,
08fe0a53
LP
85 PARTITION_ROOT_VERITY,
86 PARTITION_ROOT_SECONDARY_VERITY,
49ae9d91 87 PARTITION_ROOT_OTHER_VERITY,
08fe0a53 88 PARTITION_USR_VERITY,
8ee9615e 89 PARTITION_USR_SECONDARY_VERITY,
49ae9d91 90 PARTITION_USR_OTHER_VERITY,
8ee9615e
LP
91 PARTITION_ROOT_VERITY_SIG,
92 PARTITION_ROOT_SECONDARY_VERITY_SIG,
49ae9d91 93 PARTITION_ROOT_OTHER_VERITY_SIG,
8ee9615e 94 PARTITION_USR_VERITY_SIG,
49ae9d91
DDM
95 PARTITION_USR_SECONDARY_VERITY_SIG,
96 PARTITION_USR_OTHER_VERITY_SIG);
08fe0a53
LP
97}
98
569a0e42 99static inline PartitionDesignator PARTITION_VERITY_OF(PartitionDesignator p) {
aee36b4e
LP
100 switch (p) {
101
102 case PARTITION_ROOT:
4623e8e6 103 return PARTITION_ROOT_VERITY;
aee36b4e
LP
104
105 case PARTITION_ROOT_SECONDARY:
4623e8e6 106 return PARTITION_ROOT_SECONDARY_VERITY;
aee36b4e 107
49ae9d91
DDM
108 case PARTITION_ROOT_OTHER:
109 return PARTITION_ROOT_OTHER_VERITY;
110
aee36b4e
LP
111 case PARTITION_USR:
112 return PARTITION_USR_VERITY;
113
114 case PARTITION_USR_SECONDARY:
115 return PARTITION_USR_SECONDARY_VERITY;
116
49ae9d91
DDM
117 case PARTITION_USR_OTHER:
118 return PARTITION_USR_OTHER_VERITY;
119
aee36b4e
LP
120 default:
121 return _PARTITION_DESIGNATOR_INVALID;
122 }
4623e8e6
LP
123}
124
8ee9615e
LP
125static inline PartitionDesignator PARTITION_VERITY_SIG_OF(PartitionDesignator p) {
126 switch (p) {
127
128 case PARTITION_ROOT:
129 return PARTITION_ROOT_VERITY_SIG;
130
131 case PARTITION_ROOT_SECONDARY:
132 return PARTITION_ROOT_SECONDARY_VERITY_SIG;
133
49ae9d91
DDM
134 case PARTITION_ROOT_OTHER:
135 return PARTITION_ROOT_OTHER_VERITY_SIG;
136
8ee9615e
LP
137 case PARTITION_USR:
138 return PARTITION_USR_VERITY_SIG;
139
140 case PARTITION_USR_SECONDARY:
141 return PARTITION_USR_SECONDARY_VERITY_SIG;
142
49ae9d91
DDM
143 case PARTITION_USR_OTHER:
144 return PARTITION_USR_OTHER_VERITY_SIG;
145
8ee9615e
LP
146 default:
147 return _PARTITION_DESIGNATOR_INVALID;
148 }
149}
150
49ae9d91
DDM
151static inline PartitionDesignator PARTITION_ROOT_OF_ARCH(Architecture arch) {
152 switch (arch) {
153
154 case native_architecture():
155 return PARTITION_ROOT;
156
157#ifdef ARCHITECTURE_SECONDARY
158 case ARCHITECTURE_SECONDARY:
159 return PARTITION_ROOT_SECONDARY;
160#endif
161
162 default:
163 return PARTITION_ROOT_OTHER;
164 }
165}
166
167static inline PartitionDesignator PARTITION_USR_OF_ARCH(Architecture arch) {
168 switch (arch) {
169
170 case native_architecture():
171 return PARTITION_USR;
172
173#ifdef ARCHITECTURE_SECONDARY
174 case ARCHITECTURE_SECONDARY:
175 return PARTITION_USR_SECONDARY;
176#endif
177
178 default:
179 return PARTITION_USR_OTHER;
180 }
181}
182
18b5886e 183typedef enum DissectImageFlags {
ef9c184d 184 DISSECT_IMAGE_DEVICE_READ_ONLY = 1 << 0, /* Make device read-only */
2d3a5a73
LP
185 DISSECT_IMAGE_DISCARD_ON_LOOP = 1 << 1, /* Turn on "discard" if on a loop device and file system supports it */
186 DISSECT_IMAGE_DISCARD = 1 << 2, /* Turn on "discard" if file system supports it, on all block devices */
187 DISSECT_IMAGE_DISCARD_ON_CRYPTO = 1 << 3, /* Turn on "discard" also on crypto devices */
ef9c184d
LP
188 DISSECT_IMAGE_DISCARD_ANY = DISSECT_IMAGE_DISCARD_ON_LOOP |
189 DISSECT_IMAGE_DISCARD |
190 DISSECT_IMAGE_DISCARD_ON_CRYPTO,
2d3a5a73 191 DISSECT_IMAGE_GPT_ONLY = 1 << 4, /* Only recognize images with GPT partition tables */
4b5de5dd 192 DISSECT_IMAGE_GENERIC_ROOT = 1 << 5, /* If no partition table or only single generic partition, assume it's the root fs */
aee36b4e
LP
193 DISSECT_IMAGE_MOUNT_ROOT_ONLY = 1 << 6, /* Mount only the root and /usr partitions */
194 DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY = 1 << 7, /* Mount only the non-root and non-/usr partitions */
5238e957 195 DISSECT_IMAGE_VALIDATE_OS = 1 << 8, /* Refuse mounting images that aren't identifiable as OS images */
9ccb531a 196 DISSECT_IMAGE_VALIDATE_OS_EXT = 1 << 9, /* Refuse mounting images that aren't identifiable as OS extension images */
1b010ae7
LP
197 DISSECT_IMAGE_RELAX_VAR_CHECK = 1 << 10, /* Don't insist that the UUID of /var is hashed from /etc/machine-id */
198 DISSECT_IMAGE_FSCK = 1 << 11, /* File system check the partition before mounting (no effect when combined with DISSECT_IMAGE_READ_ONLY) */
199 DISSECT_IMAGE_NO_PARTITION_TABLE = 1 << 12, /* Only recognize single file system images */
200 DISSECT_IMAGE_VERITY_SHARE = 1 << 13, /* When activating a verity device, reuse existing one if already open */
201 DISSECT_IMAGE_MKDIR = 1 << 14, /* Make top-level directory to mount right before mounting, if missing */
202 DISSECT_IMAGE_USR_NO_ROOT = 1 << 15, /* If no root fs is in the image, but /usr is, then allow this (so that we can mount the rootfs as tmpfs or so */
203 DISSECT_IMAGE_REQUIRE_ROOT = 1 << 16, /* Don't accept disks without root partition (or at least /usr partition if DISSECT_IMAGE_USR_NO_ROOT is set) */
204 DISSECT_IMAGE_MOUNT_READ_ONLY = 1 << 17, /* Make mounts read-only */
ef9c184d
LP
205 DISSECT_IMAGE_READ_ONLY = DISSECT_IMAGE_DEVICE_READ_ONLY |
206 DISSECT_IMAGE_MOUNT_READ_ONLY,
1b010ae7
LP
207 DISSECT_IMAGE_GROWFS = 1 << 18, /* Grow file systems in partitions marked for that to the size of the partitions after mount */
208 DISSECT_IMAGE_MOUNT_IDMAPPED = 1 << 19, /* Mount mounts with kernel 5.12-style userns ID mapping, if file system type doesn't support uid=/gid= */
18b5886e 209} DissectImageFlags;
8c1be37e
LP
210
211struct DissectedImage {
4623e8e6 212 bool encrypted:1;
c3c88d67 213 bool has_verity:1; /* verity available in image, but not necessarily used */
8ee9615e 214 bool has_verity_sig:1; /* pkcs#7 signature embedded in image */
c3c88d67 215 bool verity_ready:1; /* verity available, fully specified and usable */
8ee9615e 216 bool verity_sig_ready:1; /* verity signature logic, fully specified and usable */
e7cbe5cb 217 bool single_file_system:1; /* MBR/GPT or single file system */
3b925504 218
1e63dc4f 219 LoopDevice *loop;
8c1be37e 220 DissectedPartition partitions[_PARTITION_DESIGNATOR_MAX];
ac1e1b5f 221 DecryptedImage *decrypted_image;
3b925504 222
8ee9615e 223 /* Meta information extracted from /etc/os-release and similar */
593fe6c0 224 char *image_name;
3b925504
LP
225 char *hostname;
226 sd_id128_t machine_id;
227 char **machine_info;
228 char **os_release;
7718ac97 229 char **extension_release;
a4e0d617 230 int has_init_system;
8c1be37e
LP
231};
232
18d73705 233struct MountOptions {
569a0e42 234 PartitionDesignator partition_designator;
18d73705
LB
235 char *options;
236 LIST_FIELDS(MountOptions, mount_options);
237};
238
89e62e0b
LP
239struct VeritySettings {
240 /* Binary root hash for the Verity Merkle tree */
241 void *root_hash;
242 size_t root_hash_size;
243
244 /* PKCS#7 signature of the above */
245 void *root_hash_sig;
246 size_t root_hash_sig_size;
247
248 /* Path to the verity data file, if stored externally */
249 char *data_path;
aee36b4e
LP
250
251 /* PARTITION_ROOT or PARTITION_USR, depending on what these Verity settings are for */
252 PartitionDesignator designator;
89e62e0b
LP
253};
254
aee36b4e
LP
255#define VERITY_SETTINGS_DEFAULT { \
256 .designator = _PARTITION_DESIGNATOR_INVALID \
257 }
258
18d73705
LB
259MountOptions* mount_options_free_all(MountOptions *options);
260DEFINE_TRIVIAL_CLEANUP_FUNC(MountOptions*, mount_options_free_all);
569a0e42 261const char* mount_options_from_designator(const MountOptions *options, PartitionDesignator designator);
18d73705 262
c34b75a1 263int probe_filesystem(const char *node, char **ret_fstype);
369de26f
YW
264int dissect_image(
265 int fd,
0b214aa0 266 const char *devname,
369de26f
YW
267 const char *image_path,
268 const VeritySettings *verity,
269 const MountOptions *mount_options,
369de26f
YW
270 DissectImageFlags flags,
271 DissectedImage **ret);
1e63dc4f
YW
272int dissect_loop_device(LoopDevice *loop, const VeritySettings *verity, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret);
273int dissect_loop_device_and_warn(LoopDevice *loop, const VeritySettings *verity, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret);
8c1be37e
LP
274
275DissectedImage* dissected_image_unref(DissectedImage *m);
276DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref);
277
89e62e0b
LP
278int dissected_image_decrypt(DissectedImage *m, const char *passphrase, const VeritySettings *verity, DissectImageFlags flags, DecryptedImage **ret);
279int dissected_image_decrypt_interactively(DissectedImage *m, const char *passphrase, const VeritySettings *verity, DissectImageFlags flags, DecryptedImage **ret);
21b61b1d
LP
280int dissected_image_mount(DissectedImage *m, const char *dest, uid_t uid_shift, uid_t uid_range, DissectImageFlags flags);
281int dissected_image_mount_and_warn(DissectedImage *m, const char *where, uid_t uid_shift, uid_t uid_range, DissectImageFlags flags);
18b5886e 282
22847508 283int dissected_image_acquire_metadata(DissectedImage *m, DissectImageFlags extra_flags);
3b925504 284
9321ad51 285DecryptedImage* decrypted_image_ref(DecryptedImage *p);
18b5886e
LP
286DecryptedImage* decrypted_image_unref(DecryptedImage *p);
287DEFINE_TRIVIAL_CLEANUP_FUNC(DecryptedImage*, decrypted_image_unref);
288int decrypted_image_relinquish(DecryptedImage *d);
8c1be37e 289
569a0e42
LP
290const char* partition_designator_to_string(PartitionDesignator d) _const_;
291PartitionDesignator partition_designator_from_string(const char *name) _pure_;
78ebe980 292
89e62e0b
LP
293int verity_settings_load(VeritySettings *verity, const char *image, const char *root_hash_path, const char *root_hash_sig_path);
294void verity_settings_done(VeritySettings *verity);
295
88b3300f
LP
296int dissected_image_load_verity_sig_partition(DissectedImage *m, int fd, VeritySettings *verity);
297
49536766
LP
298bool dissected_image_verity_candidate(const DissectedImage *image, PartitionDesignator d);
299bool dissected_image_verity_ready(const DissectedImage *image, PartitionDesignator d);
8ee9615e 300bool dissected_image_verity_sig_ready(const DissectedImage *image, PartitionDesignator d);
6aa05ebd
LP
301
302int mount_image_privately_interactively(const char *path, DissectImageFlags flags, char **ret_directory, LoopDevice **ret_loop_device, DecryptedImage **ret_decrypted_image);
4beda316 303
cedf5b1a 304int verity_dissect_and_mount(int src_fd, const char *src, const char *dest, const MountOptions *options, const char *required_host_os_release_id, const char *required_host_os_release_version_id, const char *required_host_os_release_sysext_level, const char *required_sysext_scope);