1 | /*! |
2 | * @header |
3 | * Interfaces for manipulating Image4 firmware objects. |
4 | */ |
5 | #ifndef __IMG4_FIRMWARE_H |
6 | #define __IMG4_FIRMWARE_H |
7 | |
8 | #define __IMG4_INDIRECT 1 |
9 | #include <img4/api.h> |
10 | |
11 | /*! |
12 | * @discussion |
13 | * When used from the pmap layer, this header pulls in the types from libsa, |
14 | * which conflict with the BSD sys/types.h header that we need to pull in. But |
15 | * we only need it for the errno_t typedef and the vnode_t typedef. So when |
16 | * building MACH_KERNEL_PRIVATE, we do two things: |
17 | * |
18 | * 1. Explicitly pull in <sys/_types/_errno_t.h>, so we get errno_t and |
19 | * nothing else (no transitive #include's) |
20 | * 2. #define _SYS_TYPES_H_ before #includ'ing <sys/kernel_types.h> so that |
21 | * we don't get the transitive #include of <sys/types.h> but we still get |
22 | * the definitions we need |
23 | */ |
24 | #if IMG4_TARGET_XNU |
25 | #if MACH_KERNEL_PRIVATE |
26 | #define _SYS_TYPES_H_ 1 |
27 | #include <sys/kernel_types.h> |
28 | #include <sys/_types/_errno_t.h> |
29 | #else |
30 | #include <sys/kernel_types.h> |
31 | #include <sys/types.h> |
32 | #endif |
33 | |
34 | #if XNU_KERNEL_PRIVATE |
35 | #include <img4/4xnu.h> |
36 | #endif |
37 | #endif // IMG4_TARGET_XNU |
38 | |
39 | #if IMG4_TARGET_DARWIN |
40 | #include <os/stdio.h> |
41 | #include <sys/types.h> |
42 | #include <img4/4ignition.h> |
43 | #include <img4/4MSU.h> |
44 | #endif |
45 | |
46 | #include <sys/cdefs.h> |
47 | |
48 | __BEGIN_DECLS |
49 | OS_ASSUME_NONNULL_BEGIN |
50 | OS_ASSUME_PTR_ABI_SINGLE_BEGIN |
51 | |
52 | /*! |
53 | * @typedef img4_4cc_t |
54 | * A type which represents a four-character code (4cc) that identifies the |
55 | * firmware. These 4cc's are statically assigned and correspond to long-form tag |
56 | * names -- e.g. the 4cc 'krnl' corresponds to the "KernelCache" tag. |
57 | */ |
58 | IMG4_API_AVAILABLE_20200508 |
59 | typedef uint32_t img4_4cc_t; |
60 | |
61 | /*! |
62 | * @typedef img4_buff_t |
63 | * A structure describing a buffer. See {@link _img4_buff}. |
64 | */ |
65 | IMG4_API_AVAILABLE_20200508 |
66 | typedef struct _img4_buff img4_buff_t; |
67 | |
68 | /*! |
69 | * @const IMG4_DGST_STRUCT_VERSION |
70 | * The version of the {@link img4_dgst_t} structure supported by the |
71 | * implementation. |
72 | */ |
73 | #define IMG4_DGST_STRUCT_VERSION (0u) |
74 | |
75 | /*! |
76 | * @const IMG4_DGST_MAX_LEN |
77 | * The maximum length of a digest representable by an {@link img4_dgst_t}. |
78 | */ |
79 | #define IMG4_DGST_MAX_LEN (48u) |
80 | |
81 | /*! |
82 | * @typedef img4_dgst_t |
83 | * A type representing an Image4 identifier which is a digest. |
84 | * |
85 | * @field i4d_len |
86 | * The version of the structure. Initialize to {@link IMG4_DGST_STRUCT_VERSION}. |
87 | * |
88 | * @field i4d_len |
89 | * The length of the digest. |
90 | * |
91 | * @field i4d_bytes |
92 | * The digest bytes. |
93 | */ |
94 | IMG4_API_AVAILABLE_20200508 |
95 | typedef struct _img4_dgst { |
96 | img4_struct_version_t i4d_version; |
97 | size_t i4d_len; |
98 | uint8_t i4d_bytes[IMG4_DGST_MAX_LEN]; |
99 | } img4_dgst_t; |
100 | |
101 | /*! |
102 | * @const IMG4_DGST_INIT |
103 | * A convenience initializer for an {@link img4_dgst_t} structure. |
104 | */ |
105 | #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L |
106 | #define IMG4_DGST_INIT (img4_dgst_t){ \ |
107 | .i4d_version = IMG4_DGST_STRUCT_VERSION, \ |
108 | .i4d_len = 0, \ |
109 | .i4d_bytes = {0}, \ |
110 | } |
111 | #elif defined(__cplusplus) && __cplusplus >= 201103L |
112 | #define IMG4_DGST_INIT (img4_dgst_t{ \ |
113 | IMG4_DGST_STRUCT_VERSION, \ |
114 | 0, \ |
115 | {0}, \ |
116 | }) |
117 | #elif defined(__cplusplus) |
118 | #define IMG4_DGST_INIT (img4_nonce_t((img4_nonce_t){ \ |
119 | IMG4_DGST_STRUCT_VERSION, \ |
120 | 0, \ |
121 | {0}, \ |
122 | })) |
123 | #else |
124 | #define IMG4_DGST_INIT {IMG4_DGST_STRUCT_VERSION} |
125 | #endif |
126 | |
127 | /*! |
128 | * @struct _img4_cstr |
129 | * A type representing an Image4 identifier which is a C-string. These |
130 | * identifiers can be no more than 64 bytes in length, including the null |
131 | * terminating byte. |
132 | * |
133 | * @field i4b_len |
134 | * The length of the C-string, not including the null terminating byte. |
135 | * |
136 | * @field i4b_cstr |
137 | * The null-terminated C-string. |
138 | * |
139 | * @discussion |
140 | * This structure is intentionally unversioned. It should never evolve into |
141 | * anything more complex than it is. |
142 | */ |
143 | IMG4_API_AVAILABLE_20210113 |
144 | typedef struct _img4_cstr { |
145 | size_t i4cs_len; |
146 | char i4cs_cstr[64]; |
147 | } img4_cstr_t; |
148 | |
149 | /*! |
150 | * @const IMG4_CSTR_INIT |
151 | * A convenience initializer for an {@link img4_cstr_t}. |
152 | */ |
153 | #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L |
154 | #define IMG4_CSTR_INIT (img4_cstr_t){ \ |
155 | .i4cs_len = 0, \ |
156 | .i4cs_cstr = {0}, \ |
157 | } |
158 | #elif defined(__cplusplus) && __cplusplus >= 201103L |
159 | #define IMG4_CSTR_INIT (img4_cstr_t{ \ |
160 | 0, \ |
161 | {0}, \ |
162 | }) |
163 | #elif defined(__cplusplus) |
164 | #define IMG4_CSTR_INIT \ |
165 | (img4_cstr_t((img4_cstr_t){ \ |
166 | 0, \ |
167 | {0}, \ |
168 | })) |
169 | #else |
170 | #define IMG4_CSTR_INIT {0} |
171 | #endif |
172 | |
173 | /*! |
174 | * @typedef img4_chip_t |
175 | * An opaque type describing a destination chip environment for the firmware |
176 | * image. |
177 | */ |
178 | IMG4_API_AVAILABLE_20200508 |
179 | typedef struct _img4_chip img4_chip_t; |
180 | |
181 | /*! |
182 | * @typedef img4_firmware_t |
183 | * An opaque type describing an Image4 firmware object. |
184 | */ |
185 | IMG4_API_AVAILABLE_20200508 |
186 | typedef struct _img4_firmware *img4_firmware_t; |
187 | |
188 | /*! |
189 | * @typedef img4_image_t |
190 | * An opaque type describing an authenticated Image4 firmware image. |
191 | */ |
192 | IMG4_API_AVAILABLE_20200508 |
193 | typedef struct _img4_image *img4_image_t; |
194 | |
195 | /*! |
196 | * @typedef img4_runtime_t |
197 | * A structure describing required primitives in the operating environment's |
198 | * runtime. See {@link _img4_runtime}. |
199 | */ |
200 | IMG4_API_AVAILABLE_20200508 |
201 | typedef struct _img4_runtime img4_runtime_t; |
202 | |
203 | OS_ASSUME_PTR_ABI_SINGLE_END |
204 | OS_ASSUME_NONNULL_END |
205 | |
206 | #include <img4/nonce.h> |
207 | #include <img4/object.h> |
208 | #include <img4/chip.h> |
209 | #include <img4/chip_ap.h> |
210 | #include <img4/chip_ap_category.h> |
211 | #include <img4/chip_ap_software.h> |
212 | #include <img4/chip_cryptex1.h> |
213 | #include <img4/chip_sep.h> |
214 | #include <img4/chip_x86.h> |
215 | #include <img4/image.h> |
216 | #include <img4/runtime.h> |
217 | |
218 | #if TXM |
219 | #include <img4/4txm.h> |
220 | #endif |
221 | |
222 | OS_ASSUME_NONNULL_BEGIN |
223 | OS_ASSUME_PTR_ABI_SINGLE_BEGIN |
224 | |
225 | /*! |
226 | * @typedef img4_firmware_authenticated_execute_t |
227 | * A firmware execution function. This function is called when the firmware has |
228 | * been successfully authenticated and is ready for execution. |
229 | * |
230 | * @param fw |
231 | * The firmware which has been authenticated. |
232 | * |
233 | * @param image |
234 | * The resulting firmware image that may be executed. The implementation will |
235 | * pass NULL if there was a failure. |
236 | * |
237 | * This object is automatically freed by the implementation upon return. |
238 | * |
239 | * @param error |
240 | * An error code describing the result of the authentication. If authentication |
241 | * was successful, the implementation will pass zero. Otherwise, one of the |
242 | * following error codes will be provided: |
243 | * |
244 | * [EILSEQ] The firmware data is not valid Image4 data -- this will not |
245 | * be passed for firmwares created with |
246 | * {@link IMG4_FIRMWARE_FLAG_BARE} |
247 | * [EFTYPE] The attached manifest is not a valid Image4 manifest |
248 | * [ENOENT] The attached manifest does not authenticate this type of |
249 | * firmware |
250 | * [EAUTH] The attached manifest is not authentic (i.e. was not signed |
251 | * by an Apple CA) |
252 | * [EACCES] The given chip does not satisfy the constraints of the |
253 | * attached manifest |
254 | * [ESTALE] The manifest has been invalidated and is no longer valid for |
255 | * the provided chip |
256 | * [ENOEXEC] The firmware has been corrupted, or the given chip does not |
257 | * satisfy the constraints of the corresponding object in the |
258 | * attached manifest |
259 | * |
260 | * @param _ctx |
261 | * The user-provided context pointer. |
262 | */ |
263 | IMG4_API_AVAILABLE_20200508 |
264 | typedef void (*img4_firmware_authenticated_execute_t)( |
265 | const img4_firmware_t fw, |
266 | img4_image_t _Nullable image, |
267 | errno_t error, |
268 | void *_ctx |
269 | ); |
270 | |
271 | #if IMG4_TARGET_EFI |
272 | typedef void (*img4_firmware_authenticated_execute_efi_t)( |
273 | const img4_firmware_t fw, |
274 | img4_image_t _Nullable image, |
275 | EFI_STATUS status, |
276 | void *_ctx |
277 | ); |
278 | #endif |
279 | |
280 | /*! |
281 | * @define IMG4_FIRMWARE_EXECUTION_CONTEXT_STRUCT_VERSION |
282 | * The version of the {@link img4_firmware_execution_context_t} structure |
283 | * supported by the implementation. |
284 | */ |
285 | #define IMG4_FIRMWARE_EXECUTION_CONTEXT_STRUCT_VERSION (1u) |
286 | |
287 | /*! |
288 | * @typedef img4_firmware_execution_context_t |
289 | * A structure describing the context in which a firmware is to be executed. |
290 | * |
291 | * @field i4fex_version |
292 | * The version of the structure supported by the implementation. Initialize to |
293 | * {@link IMG4_FIRMWARE_EXECUTION_CONTEXT_STRUCT_VERSION}. |
294 | * |
295 | * @field i4fex_execute |
296 | * A pointer to the firmware execution function. |
297 | * |
298 | * @field i4fex_execute_efi |
299 | * A pointer to the EFI-specific firmware execution function. This is only |
300 | * available in the EFI environment. If both this field and |
301 | * {@link i4fex_execute} are specified in the execution context, the |
302 | * one which is called by the implementation will be undefined. |
303 | * |
304 | * This field was added in version 1 of the structure. It was not appended to |
305 | * the end of the structure since the non-EFI structure did not change, and the |
306 | * structure did not previously exist in the EFI environment. The version |
307 | * increment was not strictly necessary, but was done for hygienic reasons. |
308 | * |
309 | * @field i4fex_context |
310 | * A caller-provided context pointer that will be passed to functions invoked |
311 | * from the execution context. |
312 | */ |
313 | IMG4_API_AVAILABLE_20200508 |
314 | typedef struct _img4_firmware_execution_context { |
315 | img4_struct_version_t i4fex_version; |
316 | img4_firmware_authenticated_execute_t i4fex_execute; |
317 | #if IMG4_TARGET_EFI |
318 | img4_firmware_authenticated_execute_efi_t i4fex_execute_efi; |
319 | #endif |
320 | void *i4fex_context; |
321 | } img4_firmware_execution_context_t; |
322 | |
323 | /*! |
324 | * @typedef img4_firmware_flags_t |
325 | * A bitfield modifying the behavior of an {@link img4_firmware_t} object. |
326 | * |
327 | * @const IMG4_FIRMWARE_FLAG_INIT |
328 | * No bits set. This value is suitable for initialization purposes. |
329 | * |
330 | * @const IMG4_FIRMWARE_FLAG_ATTACHED_MANIFEST |
331 | * The manifest authenticating the firmware is attached (i.e. the buffer given |
332 | * represents a .img4 file). |
333 | * |
334 | * This flag no longer does anything and probably never did. The implementation |
335 | * assumes that, if {@link img4_firmware_attach_manifest} was not called, then |
336 | * the manifest is attached to the payload. |
337 | * |
338 | * @const IMG4_FIRMWARE_FLAG_BARE |
339 | * The firmware image is not wrapped with an Image4 payload structure. This flag |
340 | * is mutually exclusive with {@link IMG4_FIRMWARE_FLAG_ATTACHED_MANIFEST}, and |
341 | * if both are present, the implementation's behavior is undefined. |
342 | * |
343 | * @const IMG4_FIRMWARE_FLAG_SUBSEQUENT_STAGE |
344 | * The firmware image extends an existing chain of trust. |
345 | * |
346 | * This flag no longer does anything; the implementation is now designed to |
347 | * understand which environments are first-stage or subsequent-stage boots. |
348 | * |
349 | * @const IMG4_FIRMWARE_FLAG_RESPECT_AMNM |
350 | * Forces the implementation to respect the manifest's AMNM entitlement if it is |
351 | * present, even if the validation is creating a new chain of trust. This is |
352 | * technically maybe sort of against the Image4 spec, but it is useful for |
353 | * certain internal workflows (cf. v2.3, ยง2.2.10). |
354 | * |
355 | * This flag has no effect if {@link IMG4_FIRMWARE_FLAG_SUBSEQUENT_STAGE} is |
356 | * also passed. |
357 | * |
358 | * @const IMG4_FIRMWARE_FLAG_PASSTHROUGH |
359 | * Causes the wrapped payload bytes to be delivered to the image execution |
360 | * callback. These bytes do not have the Image4 wrapping stripped. |
361 | * |
362 | * This flag no longer does anything. |
363 | * |
364 | * @const IMG4_FIRMWARE_FLAG_FORCE_ANTI_REPLAY |
365 | * Force anti-replay enforcement even when performing just manifest evaluation |
366 | * without executing a firmware. When executing a firmware, this flag need not |
367 | * be passed in since anti-replay enforcement is always enabled. |
368 | */ |
369 | IMG4_API_AVAILABLE_20200508 |
370 | OS_CLOSED_OPTIONS(img4_firmware_flags, uint64_t, |
371 | IMG4_FIRMWARE_FLAG_INIT, |
372 | IMG4_FIRMWARE_FLAG_ATTACHED_MANIFEST = (1 << 0), |
373 | IMG4_FIRMWARE_FLAG_BARE = (1 << 1), |
374 | IMG4_FIRMWARE_FLAG_SUBSEQUENT_STAGE = (1 << 2), |
375 | IMG4_FIRMWARE_FLAG_RESPECT_AMNM = (1 << 3), |
376 | IMG4_FIRMWARE_FLAG_PASSTHROUGH = (1 << 4), |
377 | IMG4_FIRMWARE_FLAG_FORCE_ANTI_REPLAY = (1 << 5), |
378 | ); |
379 | |
380 | /*! |
381 | * @function img4_firmware_new |
382 | * Allocate and initialize a new firmware object. |
383 | * |
384 | * @param rt |
385 | * The runtime in which to initialize the object. |
386 | * |
387 | * @param _4cc |
388 | * The 4cc which distinguishes the firmware. |
389 | * |
390 | * @param buff |
391 | * A buffer containing a valid Image4 payload (usually the contents of either a |
392 | * .im4p or .img4 file). |
393 | * |
394 | * Upon return, the destructor in the buffer is replaced with NULL, and the |
395 | * implementation assumes responsibility for deallocating the underlying memory. |
396 | * |
397 | * @param flags |
398 | * Flags modifying the behavior of the object. |
399 | * |
400 | * @result |
401 | * A new firmware object or NULL if there was an allocation failure. If |
402 | * {@link rt} has a NULL allocation function, NULL is returned. |
403 | * |
404 | * @discussion |
405 | * The resulting object assumes ownership of the given buffer. |
406 | * |
407 | * In the Darwin userspace runtime, NULL will not be returned. |
408 | */ |
409 | #if !XNU_KERNEL_PRIVATE |
410 | IMG4_API_AVAILABLE_20200508 |
411 | OS_EXPORT OS_WARN_RESULT OS_MALLOC OS_NONNULL1 OS_NONNULL2 OS_NONNULL4 |
412 | img4_firmware_t _Nullable |
413 | img4_firmware_new(const img4_runtime_t *rt, |
414 | const img4_firmware_execution_context_t *exec, |
415 | img4_4cc_t _4cc, |
416 | img4_buff_t *buff, |
417 | img4_firmware_flags_t flags); |
418 | #else |
419 | #define img4_firmware_new(...) (img4if->i4if_v7.firmware_new(__VA_ARGS__)) |
420 | #endif |
421 | |
422 | /*! |
423 | * @function img4_firmware_new_from_vnode_4xnu |
424 | * Allocate and initialize a new firmware object from a vnode. |
425 | * |
426 | * @param rt |
427 | * The runtime in which to initialize the object. This interface is only |
428 | * supported with the Darwin kernel runtime. If any other runtime is provided, |
429 | * the implementation's behavior is undefined. |
430 | * |
431 | * @param _4cc |
432 | * The 4cc which distinguishes the firmware. |
433 | * |
434 | * @param vn |
435 | * A vnode representing a valid Image4 payload (usually the contents of either a |
436 | * .im4p or .img4 file). |
437 | * |
438 | * @param flags |
439 | * Flags modifying the behavior of the object. |
440 | * |
441 | * @result |
442 | * A new firmware object or NULL if there was an allocation failure. |
443 | * |
444 | * @discussion |
445 | * Verification of a vnode is performed by reading in chunks of data, updating |
446 | * an ongoing hash operation with that data, and then discarding it. Therefore, |
447 | * firmware objects created in this manner can only guarantee their validity at |
448 | * the time the check was performed since the vnode's contents are not kept in |
449 | * memory and may be tampered with after validation has been performed. |
450 | * |
451 | * As such, on successful execution, the image passed to the |
452 | * {@link img4_firmware_authenticated_execute_t} function of the execution |
453 | * context is NULL. |
454 | * |
455 | * Firmwares created with this interface cannot be created with the |
456 | * {@link IMG4_FIRMWARE_FLAG_ATTACHED_MANIFEST} flag. |
457 | */ |
458 | #if IMG4_TARGET_XNU |
459 | #if !XNU_KERNEL_PRIVATE |
460 | IMG4_API_AVAILABLE_20200508 |
461 | OS_EXPORT OS_WARN_RESULT OS_MALLOC OS_NONNULL1 OS_NONNULL2 OS_NONNULL4 |
462 | img4_firmware_t _Nullable |
463 | img4_firmware_new_from_vnode_4xnu(const img4_runtime_t *rt, |
464 | const img4_firmware_execution_context_t *exec, |
465 | img4_4cc_t _4cc, |
466 | vnode_t vn, |
467 | img4_firmware_flags_t flags); |
468 | #else |
469 | #define img4_firmware_new_from_vnode_4xnu(...) \ |
470 | (img4if->i4if_v7.firmware_new_from_vnode_4xnu(__VA_ARGS__)) |
471 | #endif // !XNU_KERNEL_PRIVATE |
472 | #endif // IMG4_TARGET_XNU |
473 | |
474 | /*! |
475 | * @function img4_firmware_new_from_fd_4MSM |
476 | * Allocate and initialize a new firmware object from a file descriptor. |
477 | * |
478 | * @param rt |
479 | * The runtime in which to initialize the object. This interface is only |
480 | * supported with the Darwin userspace runtime. If any other runtime is |
481 | * provided, the implementation's behavior is undefined. |
482 | * |
483 | * @param _4cc |
484 | * The 4cc which distinguishes the firmware. |
485 | * |
486 | * @param fd |
487 | * A pointer to a file descriptor representing a valid Image4 payload (usually |
488 | * the contents of either a .im4p or .img4 file). The object assumes ownership |
489 | * of the descriptor, and upon return, the value referenced by the pointer will |
490 | * be set to -1. |
491 | * |
492 | * @param flags |
493 | * Flags modifying the behavior of the object. |
494 | * |
495 | * @result |
496 | * A new firmware object. The implementation will not return NULL. |
497 | * |
498 | * @discussion |
499 | * This interface is the userspace equivalent of |
500 | * {@link img4_firmware_new_from_vnode_4xnu}, and all the same caveats apply. |
501 | */ |
502 | #if IMG4_TARGET_DARWIN |
503 | IMG4_API_AVAILABLE_20200508 |
504 | OS_EXPORT OS_WARN_RESULT OS_MALLOC OS_NONNULL1 OS_NONNULL2 |
505 | img4_firmware_t |
506 | img4_firmware_new_from_fd_4MSM(const img4_runtime_t *rt, |
507 | const img4_firmware_execution_context_t *exec, |
508 | img4_4cc_t _4cc, |
509 | os_fd_t *fd, |
510 | img4_firmware_flags_t flags); |
511 | #endif |
512 | |
513 | /*! |
514 | * @function img4_firmware_init_from_buff |
515 | * Initializes a buffer as a firmware object. This interface is useful for |
516 | * runtimes which do not provide for dynamic memory allocation. |
517 | * |
518 | * @param storage |
519 | * A pointer to the storage to use for the firmware object. |
520 | * |
521 | * @param len |
522 | * The size of the buffer. |
523 | * |
524 | * @discussion |
525 | * The caller is expected to pass a buffer that is "big enough". If the provided |
526 | * buffer is too small, the implementation will abort the caller. |
527 | * |
528 | * @example |
529 | * |
530 | * uint8_t _buff[IMG4_FIRMWARE_SIZE_RECOMMENDED]; |
531 | * img4_firmware_t fw = NULL; |
532 | * |
533 | * fw = img4_firmware_init_from_buff(_buff, sizeof(_buff)); |
534 | * img4_firmware_init(fw, IMG4_RUNTIME_DEFAULT, &exec_context, |
535 | * kImg4Tag_krnl, fw_buff, 0); |
536 | */ |
537 | #if !XNU_KERNEL_PRIVATE |
538 | IMG4_API_AVAILABLE_20200508 |
539 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 |
540 | img4_firmware_t |
541 | img4_firmware_init_from_buff(void *__sized_by(len) buff, size_t len); |
542 | #else |
543 | #define img4_firmware_init_from_buff(...) \ |
544 | (img4if->i4if_v7.firmware_init_from_buff(__VA_ARGS__)) |
545 | #endif |
546 | |
547 | /*! |
548 | * @function img4_firmware_init |
549 | * Initialize a firmware object. |
550 | * |
551 | * @param fw |
552 | * A pointer to the storage for the firmware object. This pointer should refer |
553 | * to a region of memory that is sufficient to hold a {@link img4_firmware_t} |
554 | * object. This size should be queried with the {@link i4rt_object_size} |
555 | * function of the runtime. |
556 | * |
557 | * @param rt |
558 | * The runtime in which to initialize the object. |
559 | * |
560 | * @param _4cc |
561 | * The 4cc which distinguishes the firmware. |
562 | * |
563 | * @param buff |
564 | * A buffer containing a valid Image4 payload (usually the contents of either a |
565 | * .im4p or .img4 file). |
566 | * |
567 | * Upon return, the destructor in the buffer is replaced with NULL, and the |
568 | * implementation assumes responsibility for deallocating the underlying memory. |
569 | * |
570 | * @param flags |
571 | * Flags modifying the behavior of the object. |
572 | * |
573 | * @discussion |
574 | * The resulting object assumes ownership of the given buffer. This routine |
575 | * should only be used when dynamic memory allocation is not available in the |
576 | * runtime. Otherwise, use {@link img4_firmware_new}. |
577 | */ |
578 | #if !XNU_KERNEL_PRIVATE |
579 | IMG4_API_AVAILABLE_20200508 |
580 | OS_EXPORT OS_NONNULL1 OS_NONNULL2 OS_NONNULL3 OS_NONNULL5 |
581 | void |
582 | img4_firmware_init(img4_firmware_t fw, |
583 | const img4_runtime_t *rt, |
584 | const img4_firmware_execution_context_t *exec, |
585 | img4_4cc_t _4cc, |
586 | img4_buff_t *buff, |
587 | img4_firmware_flags_t flags); |
588 | #else |
589 | #define img4_firmware_init(...) (img4if->i4if_v7.firmware_init(__VA_ARGS__)) |
590 | #endif |
591 | |
592 | /*! |
593 | * @function img4_firmware_init_sentinel |
594 | * Initialize a firmware object as a sentinel without any manifest attached. |
595 | * This firmware has no object tag and is not executable. It is only suitable |
596 | * for use with {@link img4_firmware_attach_manifest} and |
597 | * {@link img4_firmware_evaluate} to determine whether a manifest is acceptable |
598 | * to a particular chip environment. |
599 | * |
600 | * @param fw |
601 | * A pointer to the storage for the firmware object. This pointer should refer |
602 | * to a region of memory that is sufficient to hold a {@link img4_firmware_t} |
603 | * object. This size should be queried with the {@link i4rt_object_size} |
604 | * function of the runtime. |
605 | * |
606 | * @param rt |
607 | * The runtime in which to initialize the object. |
608 | * |
609 | * @param flags |
610 | * Flags modifying the behavior of the object. |
611 | * |
612 | * @discussion |
613 | * Sentinel firmwares do not enforce anti-replay, so |
614 | * {@link img4_firmware_evaluate} will not return ESTALE when evaluating such |
615 | * firmwares. Anti-replay enforcement can be enabled by using |
616 | * {@link IMG4_FIRMWARE_FLAG_FORCE_ANTI_REPLAY}. |
617 | */ |
618 | #if !XNU_KERNEL_PRIVATE |
619 | IMG4_API_AVAILABLE_20211126 |
620 | OS_EXPORT OS_NONNULL1 OS_NONNULL2 |
621 | void |
622 | img4_firmware_init_sentinel(img4_firmware_t fw, |
623 | const img4_runtime_t *rt, |
624 | img4_firmware_flags_t flags); |
625 | #else |
626 | #define img4_firmware_init_sentinel(...) \ |
627 | (img4if->i4if_v17.firmware_init_sentinel(__VA_ARGS__)) |
628 | #endif |
629 | |
630 | /*! |
631 | * @function img4_firmware_attach_manifest |
632 | * Attaches a signed manifest to the firmware. |
633 | * |
634 | * @param fw |
635 | * The firmware to manipulate. |
636 | * |
637 | * @param buff |
638 | * A buffer containing a valid Image4 manifest (usually the contents of either a |
639 | * .im4m or .img4 file). |
640 | * |
641 | * Upon return, the destructor in the buffer is replaced with NULL, and the |
642 | * implementation assumes responsibility for deallocating the underlying memory. |
643 | * |
644 | * @discussion |
645 | * If this interface is called on a firmware created with the |
646 | * {@link IMG4_FIRMWARE_FLAG_ATTACHED_MANIFEST} flag, the implementation's |
647 | * behavior is undefined. |
648 | * |
649 | * This interface must be called on any firmware created with the |
650 | * {@link IMG4_FIRMWARE_FLAG_BARE} flag. |
651 | * |
652 | * The object assumes ownership of the given buffer. |
653 | */ |
654 | #if !XNU_KERNEL_PRIVATE |
655 | IMG4_API_AVAILABLE_20200508 |
656 | OS_EXPORT OS_NONNULL1 OS_NONNULL2 |
657 | void |
658 | img4_firmware_attach_manifest(img4_firmware_t fw, |
659 | img4_buff_t *buff); |
660 | #else |
661 | #define img4_firmware_attach_manifest(...) \ |
662 | (img4if->i4if_v7.firmware_attach_manifest(__VA_ARGS__)) |
663 | #endif |
664 | |
665 | /*! |
666 | * @function img4_firmware_select_chip |
667 | * Returns the chip from the provided array which may be used to authenticate |
668 | * the firmware. |
669 | * |
670 | * @param fw |
671 | * The firmware to query. |
672 | * |
673 | * @param chips |
674 | * An array of chips the caller finds acceptable to verify the firmware. |
675 | * |
676 | * @param chips_cnt |
677 | * The number of elements in {@link chips}. |
678 | * |
679 | * @result |
680 | * If the manifest may be authenticated by the certificate chain associated with |
681 | * one of the manifests provided in {@link chips}, that chip is |
682 | * returned. If the manifest cannot be authenticated with any of the provided |
683 | * chips, NULL is returned. |
684 | * |
685 | * @discussion |
686 | * The result of calling this function on a firmware which does not have a |
687 | * manifest attached is undefined. |
688 | * |
689 | * If multiple chips may be used to authenticate the firmware, the |
690 | * implementation does not define which of those chips will be returned. |
691 | * |
692 | * If the firmware was created without the |
693 | * {@link IMG4_FIRMWARE_FLAG_SUBSEQUENT_STAGE} flag, this function will return |
694 | * NULL. This function cannot be used to establish new trust chains, only to |
695 | * verify an existing one. |
696 | */ |
697 | #if !XNU_KERNEL_PRIVATE |
698 | IMG4_API_AVAILABLE_20200724 |
699 | OS_EXPORT OS_WARN_RESULT |
700 | const img4_chip_t *_Nullable |
701 | img4_firmware_select_chip(const img4_firmware_t fw, |
702 | const img4_chip_select_array_t __counted_by(chips_cnt) _Nonnull chips, |
703 | size_t chips_cnt); |
704 | #else |
705 | #define img4_firmware_select_chip(...) \ |
706 | (img4if->i4if_v10.firmware_select_chip(__VA_ARGS__)) |
707 | #endif |
708 | |
709 | /*! |
710 | * @function img4_firmware_execute |
711 | * Authenticate the firmware and execute it within its context. |
712 | * |
713 | * @param fw |
714 | * The firmware to execute. |
715 | * |
716 | * @param chip |
717 | * The chip on which to execute the firmware. |
718 | * |
719 | * @param nonce |
720 | * The nonce to use for authentication. May be NULL if the chip environment does |
721 | * not maintain an anti-replay token or if a chained evaluation is being |
722 | * performed. |
723 | * |
724 | * @discussion |
725 | * The implementation will always invoke the |
726 | * {@link img4_firmware_authenticated_execute_t} provided in the execution |
727 | * context with either a successful result or a failure. All error handling must |
728 | * take place in that context. |
729 | * |
730 | * The {@link img4_firmware_authenticated_execute_t} is called before the |
731 | * implementation returns. |
732 | * |
733 | * The result of executing a firmware without a manifest attached (either via |
734 | * {@link img4_firmware_attach_manifest} or by creating the firmware with the |
735 | * {@link IMG4_FIRMWARE_FLAG_ATTACHED_MANIFEST} flag set) is undefined. |
736 | */ |
737 | #if !XNU_KERNEL_PRIVATE |
738 | IMG4_API_AVAILABLE_20200508 |
739 | OS_EXPORT OS_NONNULL1 OS_NONNULL2 |
740 | void |
741 | img4_firmware_execute(img4_firmware_t fw, |
742 | const img4_chip_t *chip, |
743 | const img4_nonce_t *_Nullable nonce); |
744 | #else |
745 | #define img4_firmware_execute(...) \ |
746 | (img4if->i4if_v7.firmware_execute(__VA_ARGS__)) |
747 | #endif |
748 | |
749 | /*! |
750 | * @function img4_firmware_evaluate |
751 | * Evaluate the firmware for authenticity. |
752 | * |
753 | * @param fw |
754 | * The firmware to evaluate. |
755 | * |
756 | * @param chip |
757 | * The chip on which to evaluate the firmware. |
758 | * |
759 | * @param nonce |
760 | * The nonce to use for authentication. May be NULL if the chip environment does |
761 | * not maintain an anti-replay token or if a chained evaluation is being |
762 | * performed. |
763 | * |
764 | * @result |
765 | * An error code describing the result of the authentication. If authentication |
766 | * was successful, zero is returned. Otherwise, one of the following error codes |
767 | * will be returned: |
768 | * |
769 | * [EILSEQ] The firmware data is not valid Image4 data -- this will not |
770 | * be returned for firmwares created with |
771 | * {@link IMG4_FIRMWARE_FLAG_BARE} |
772 | * [EFTYPE] The attached manifest is not a valid Image4 manifest |
773 | * [ENOENT] The attached manifest does not authenticate this type of |
774 | * firmware |
775 | * [EAUTH] The attached manifest is not authentic (i.e. was not signed |
776 | * by an Apple CA) |
777 | * [EACCES] The given chip does not satisfy the constraints of the |
778 | * attached manifest |
779 | * [ESTALE] The manifest has been invalidated and is no longer valid for |
780 | * the provided chip |
781 | * [ENOEXEC] The firmware has been corrupted, or the given chip does not |
782 | * satisfy the constraints of the corresponding object in the |
783 | * attached manifest |
784 | * [EPWROFF] The chip environment has not yet booted; most chip |
785 | * environments are booted and available by the time the caller |
786 | * has begun executing, but some require additional |
787 | * initialization before they can execute objects |
788 | * |
789 | * @discussion |
790 | * This interface should be used when the caller is only concerned with the |
791 | * authenticity and integrity of the firmware image and does not intend to |
792 | * execute it. |
793 | * |
794 | * The result of evaluating a firmware without a manifest attached (either via |
795 | * {@link img4_firmware_attach_manifest} or by creating the firmware with the |
796 | * {@link IMG4_FIRMWARE_FLAG_ATTACHED_MANIFEST} flag set) is undefined. |
797 | */ |
798 | #if !XNU_KERNEL_PRIVATE |
799 | IMG4_API_AVAILABLE_20200608 |
800 | OS_EXPORT OS_WARN_RESULT OS_NONNULL1 OS_NONNULL2 |
801 | errno_t |
802 | img4_firmware_evaluate(img4_firmware_t fw, |
803 | const img4_chip_t *chip, |
804 | const img4_nonce_t *_Nullable nonce); |
805 | #else |
806 | #define img4_firmware_evaluate(...) \ |
807 | (img4if->i4if_v9.firmware_evaluate(__VA_ARGS__)) |
808 | #endif |
809 | |
810 | /*! |
811 | * @function img4_firmware_destroy |
812 | * Destroys a firmware object and releases the associated resources according to |
813 | * the runtime's specification. |
814 | * |
815 | * @param fw |
816 | * A pointer to the firmware object. |
817 | * |
818 | * Upon return, this will be replaced with a known-invalid pointer value. This |
819 | * parameter may be NULL in which case the implementation will return |
820 | * immediately. |
821 | * |
822 | * @discussion |
823 | * The implementation will invoke the provided deallocation function of the |
824 | * buffer object underlying the firmware. |
825 | */ |
826 | #if !XNU_KERNEL_PRIVATE |
827 | IMG4_API_AVAILABLE_20200508 |
828 | OS_EXPORT |
829 | void |
830 | img4_firmware_destroy(img4_firmware_t _Nullable *_Nonnull fw); |
831 | #else |
832 | #define img4_firmware_destroy(...) \ |
833 | (img4if->i4if_v7.firmware_destroy(__VA_ARGS__)) |
834 | #endif |
835 | |
836 | OS_ASSUME_PTR_ABI_SINGLE_END |
837 | OS_ASSUME_NONNULL_END |
838 | __END_DECLS |
839 | |
840 | #endif // __IMG4_FIRMWARE_H |
841 | |