]>
Commit | Line | Data |
---|---|---|
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 | ||
13 | typedef struct DissectedImage DissectedImage; | |
14 | typedef struct DissectedPartition DissectedPartition; | |
18b5886e | 15 | typedef struct DecryptedImage DecryptedImage; |
18d73705 | 16 | typedef struct MountOptions MountOptions; |
89e62e0b | 17 | typedef struct VeritySettings VeritySettings; |
8c1be37e LP |
18 | |
19 | struct 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 | 42 | typedef 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 |
72 | static 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 | 99 | static 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 |
125 | static 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 |
151 | static 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 | ||
167 | static 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 | 183 | typedef 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 | |
211 | struct 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 | 233 | struct MountOptions { |
569a0e42 | 234 | PartitionDesignator partition_designator; |
18d73705 LB |
235 | char *options; |
236 | LIST_FIELDS(MountOptions, mount_options); | |
237 | }; | |
238 | ||
89e62e0b LP |
239 | struct 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 |
259 | MountOptions* mount_options_free_all(MountOptions *options); |
260 | DEFINE_TRIVIAL_CLEANUP_FUNC(MountOptions*, mount_options_free_all); | |
569a0e42 | 261 | const char* mount_options_from_designator(const MountOptions *options, PartitionDesignator designator); |
18d73705 | 262 | |
c34b75a1 | 263 | int probe_filesystem(const char *node, char **ret_fstype); |
369de26f YW |
264 | int 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 |
272 | int dissect_loop_device(LoopDevice *loop, const VeritySettings *verity, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret); |
273 | int dissect_loop_device_and_warn(LoopDevice *loop, const VeritySettings *verity, const MountOptions *mount_options, DissectImageFlags flags, DissectedImage **ret); | |
8c1be37e LP |
274 | |
275 | DissectedImage* dissected_image_unref(DissectedImage *m); | |
276 | DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref); | |
277 | ||
89e62e0b LP |
278 | int dissected_image_decrypt(DissectedImage *m, const char *passphrase, const VeritySettings *verity, DissectImageFlags flags, DecryptedImage **ret); |
279 | int dissected_image_decrypt_interactively(DissectedImage *m, const char *passphrase, const VeritySettings *verity, DissectImageFlags flags, DecryptedImage **ret); | |
21b61b1d LP |
280 | int dissected_image_mount(DissectedImage *m, const char *dest, uid_t uid_shift, uid_t uid_range, DissectImageFlags flags); |
281 | int dissected_image_mount_and_warn(DissectedImage *m, const char *where, uid_t uid_shift, uid_t uid_range, DissectImageFlags flags); | |
18b5886e | 282 | |
22847508 | 283 | int dissected_image_acquire_metadata(DissectedImage *m, DissectImageFlags extra_flags); |
3b925504 | 284 | |
9321ad51 | 285 | DecryptedImage* decrypted_image_ref(DecryptedImage *p); |
18b5886e LP |
286 | DecryptedImage* decrypted_image_unref(DecryptedImage *p); |
287 | DEFINE_TRIVIAL_CLEANUP_FUNC(DecryptedImage*, decrypted_image_unref); | |
288 | int decrypted_image_relinquish(DecryptedImage *d); | |
8c1be37e | 289 | |
569a0e42 LP |
290 | const char* partition_designator_to_string(PartitionDesignator d) _const_; |
291 | PartitionDesignator partition_designator_from_string(const char *name) _pure_; | |
78ebe980 | 292 | |
89e62e0b LP |
293 | int verity_settings_load(VeritySettings *verity, const char *image, const char *root_hash_path, const char *root_hash_sig_path); |
294 | void verity_settings_done(VeritySettings *verity); | |
295 | ||
88b3300f LP |
296 | int dissected_image_load_verity_sig_partition(DissectedImage *m, int fd, VeritySettings *verity); |
297 | ||
49536766 LP |
298 | bool dissected_image_verity_candidate(const DissectedImage *image, PartitionDesignator d); |
299 | bool dissected_image_verity_ready(const DissectedImage *image, PartitionDesignator d); | |
8ee9615e | 300 | bool dissected_image_verity_sig_ready(const DissectedImage *image, PartitionDesignator d); |
6aa05ebd LP |
301 | |
302 | int mount_image_privately_interactively(const char *path, DissectImageFlags flags, char **ret_directory, LoopDevice **ret_loop_device, DecryptedImage **ret_decrypted_image); | |
4beda316 | 303 | |
cedf5b1a | 304 | int 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); |