3 * Interfaces for manipulating Image4 firmware objects.
5 #ifndef __IMG4_FIRMWARE_H
6 #define __IMG4_FIRMWARE_H
11 #include <sys/cdefs.h>
19 #if !_DARWIN_BUILDING_PROJECT_APPLEIMAGE4
20 #if __has_include(<os/linker_set.h>) && !KERNEL
21 #include <os/linker_set.h>
22 #elif XNU_KERNEL_PRIVATE
23 // There is no linker set header in the KDK, and the one from the SDK is not
24 // safe for kexts to use.
26 // <rdar://problem/64576673>
27 #include <sys/linker_set.h>
29 #define LINKER_SET_ENTRY(...)
31 #endif // !_DARWIN_BUILDING_PROJECT_APPLEIMAGE4
35 * When used from the pmap layer, this header pulls in the types from libsa,
36 * which conflict with the BSD sys/types.h header that we need to pull in. But
37 * we only need it for the errno_t typedef and the vnode_t typedef. So when
38 * building MACH_KERNEL_PRIVATE, we do two things:
40 * 1. Explicitly pull in <sys/_types/_errno_t.h>, so we get errno_t and
41 * nothing else (no transitive #include's)
42 * 2. #define _SYS_TYPES_H_ before #includ'ing <sys/kernel_types.h> so that
43 * we don't get the transitive #include of <sys/types.h> but we still get
44 * the definitions we need
46 #if MACH_KERNEL_PRIVATE
47 #define _SYS_TYPES_H_ 1
48 #include <sys/kernel_types.h>
49 #include <sys/_types/_errno_t.h>
51 #include <sys/kernel_types.h>
52 #include <sys/types.h>
55 #define __IMG4_INDIRECT 1
62 OS_ASSUME_NONNULL_BEGIN
66 * A type which represents a four-character code (4cc) that identifies the
67 * firmware. These 4cc's are statically assigned and correspond to long-form tag
68 * names -- e.g. the 4cc 'krnl' corresponds to the "KernelCache" tag.
70 IMG4_API_AVAILABLE_20200508
71 typedef uint32_t img4_4cc_t
;
74 * @typedef img4_buff_t
75 * A structure describing a buffer. See {@link _img4_buff}.
77 IMG4_API_AVAILABLE_20200508
78 typedef struct _img4_buff img4_buff_t
;
81 * @typedef img4_firmware_t
82 * An opaque type describing an Image4 firmware object.
84 IMG4_API_AVAILABLE_20200508
85 typedef struct _img4_firmware
*img4_firmware_t
;
88 * @typedef img4_image_t
89 * An opaque type describing an authenticated Image4 firmware image.
91 IMG4_API_AVAILABLE_20200508
92 typedef struct _img4_image
*img4_image_t
;
95 * @typedef img4_runtime_t
96 * A structure describing required primitives in the operating environment's
97 * runtime. See {@link _img4_runtime}.
99 IMG4_API_AVAILABLE_20200508
100 typedef struct _img4_runtime img4_runtime_t
;
102 OS_ASSUME_NONNULL_END
104 #if !_DARWIN_BUILDING_PROJECT_APPLEIMAGE4 || IMG4_TAPI
105 #define __IMG4_INDIRECT 1
106 #include <img4/nonce.h>
107 #include <img4/object.h>
108 #include <img4/chip.h>
109 #include <img4/image.h>
110 #include <img4/runtime.h>
113 OS_ASSUME_NONNULL_BEGIN
116 * @typedef img4_firmware_authenticated_execute_t
117 * A firmware execution function. This function is called when the firmware has
118 * been successfully authenticated and is ready for execution.
121 * The firmware which has been authenticated.
124 * The resulting firmware image that may be executed. The implementation will
125 * pass NULL if there was a failure.
127 * This object is automatically freed by the implementation upon return.
130 * An error code describing the result of the authentication. If authentication
131 * was successful, the implementation will pass zero. Otherwise, one of the
132 * following error codes will be provided:
134 * [EILSEQ] The firmware data is not valid Image4 data -- this will not
135 * be passed for firmwares created with
136 * {@link IMG4_FIRMWARE_FLAG_BARE}
137 * [EFTYPE] The attached manifest is not a valid Image4 manifest
138 * [ENOENT] The attached manifest does not authenticate this type of
140 * [EAUTH] The attached manifest is not authentic (i.e. was not signed
142 * [EACCES] The given chip does not satisfy the constraints of the
144 * [ESTALE] The manifest has been invalidated and is no longer valid for
146 * [ENOEXEC] The firmware has been corrupted, or the given chip does not
147 * satisfy the constraints of the corresponding object in the
151 * The user-provided context pointer.
153 IMG4_API_AVAILABLE_20200508
154 typedef void (*img4_firmware_authenticated_execute_t
)(
155 const img4_firmware_t fw
,
156 img4_image_t _Nullable image
,
162 * @define IMG4_FIRMWARE_EXECUTION_CONTEXT_STRUCT_VERSION
163 * The version of the {@link img4_firmware_execution_context_t} structure
164 * supported by the implementation.
166 #define IMG4_FIRMWARE_EXECUTION_CONTEXT_STRUCT_VERSION (0u)
169 * @typedef img4_firmware_execution_context_t
170 * A structure describing the context in which a firmware is to be executed.
172 * @field i4fex_version
173 * The version of the structure supported by the implementation. Initialize to
174 * {@link IMG4_FIRMWARE_EXECUTION_CONTEXT_STRUCT_VERSION}.
176 * @field i4fex_execute
177 * A pointer to the firmware execution function.
179 * @field i4fex_context
180 * A caller-provided context pointer that will be passed to functions invoked
181 * from the execution context.
183 IMG4_API_AVAILABLE_20200508
184 typedef struct _img4_firmware_execution_context
{
185 img4_struct_version_t i4fex_version
;
186 img4_firmware_authenticated_execute_t i4fex_execute
;
188 } img4_firmware_execution_context_t
;
191 * @typedef img4_firmware_flags_t
192 * A bitfield modifying the behavior of an {@link img4_firmware_t} object.
194 * @const IMG4_FIRMWARE_FLAG_INIT
195 * No bits set. This value is suitable for initialization purposes.
197 * @const IMG4_FIRMWARE_FLAG_ATTACHED_MANIFEST
198 * The manifest authenticating the firmware is attached (i.e. the buffer given
199 * represents a .img4 file).
201 * @const IMG4_FIRMWARE_FLAG_BARE
202 * The firmware image is not wrapped with an Image4 payload structure. This flag
203 * is mutually exclusive with {@link IMG4_FIRMWARE_FLAG_ATTACHED_MANIFEST}, and
204 * if both are present, the implementation's behavior is undefined.
206 * @const IMG4_FIRMWARE_FLAG_SUBSEQUENT_STAGE
207 * The firmware image extends an existing chain of trust. If set, the
208 * runtime must provide a {@link i4rt_get_digest} function which returns a
209 * digest for {@link IMG4_IDENTIFIER_CHMH}.
211 * If set, the firmware may optionally provide a {@link i4rt_get_bool} function
212 * which returns a value for {@link IMG4_IDENTIFIER_AMNM}.
214 * @const IMG4_FIRMWARE_FLAG_RESPECT_AMNM
215 * Forces the implementation to respect the manifest's AMNM entitlement if it is
216 * present, even if the validation is creating a new chain of trust. This is
217 * technically maybe sort of against the Image4 spec, but it is useful for
218 * certain internal workflows (cf. v2.3, ยง2.2.10).
220 * This flag has no effect if {@link IMG4_FIRMWARE_FLAG_SUBSEQUENT_STAGE} is
223 IMG4_API_AVAILABLE_20200508
224 OS_CLOSED_OPTIONS(img4_firmware_flags
, uint64_t,
225 IMG4_FIRMWARE_FLAG_INIT
,
226 IMG4_FIRMWARE_FLAG_ATTACHED_MANIFEST
= (1 << 0),
227 IMG4_FIRMWARE_FLAG_BARE
= (1 << 1),
228 IMG4_FIRMWARE_FLAG_SUBSEQUENT_STAGE
= (1 << 2),
229 IMG4_FIRMWARE_FLAG_RESPECT_AMNM
= (1 << 3),
233 * @function img4_firmware_new
234 * Allocate and initialize a new firmware object.
237 * The runtime in which to initialize the object.
240 * The 4cc which distinguishes the firmware.
243 * A buffer containing a valid Image4 payload (usually the contents of either a
244 * .im4p or .img4 file).
246 * Upon return, the destructor in the buffer is replaced with NULL, and the
247 * implementation assumes responsibility for deallocating the underlying memory.
250 * Flags modifying the behavior of the object.
253 * A new firmware object or NULL if there was an allocation failure.
256 * The resulting object assumes ownership of the given buffer.
258 * In the Darwin userspace runtime, NULL will not be returned.
260 #if !XNU_KERNEL_PRIVATE
261 IMG4_API_AVAILABLE_20200508
262 OS_EXPORT OS_WARN_RESULT OS_MALLOC OS_NONNULL1 OS_NONNULL2 OS_NONNULL4
263 img4_firmware_t _Nullable
264 img4_firmware_new(const img4_runtime_t
*rt
,
265 const img4_firmware_execution_context_t
*exec
,
268 img4_firmware_flags_t flags
);
270 #define img4_firmware_new(...) (img4if->i4if_v7.firmware_new(__VA_ARGS__))
274 * @function img4_firmware_new_from_vnode_4xnu
275 * Allocate and initialize a new firmware object from a vnode.
278 * The runtime in which to initialize the object. This interface is only
279 * supported with the Darwin kernel runtime. If any other runtime is provided,
280 * the implementation's behavior is undefined.
283 * The 4cc which distinguishes the firmware.
286 * A vnode representing a valid Image4 payload (usually the contents of either a
287 * .im4p or .img4 file).
290 * Flags modifying the behavior of the object.
293 * A new firmware object or NULL if there was an allocation failure.
296 * Verification of a vnode is performed by reading in chunks of data, updating
297 * an ongoing hash operation with that data, and then discarding it. Therefore,
298 * firmware objects created in this manner can only guarantee their validity at
299 * the time the check was performed since the vnode's contents are not kept in
300 * memory and may be tampered with after validation has been performed.
302 * As such, on successful execution, the image passed to the
303 * {@link img4_firmware_authenticated_execute_t} function of the execution
306 * Firmwares created with this interface cannot be created with the
307 * {@link IMG4_FIRMWARE_FLAG_ATTACHED_MANIFEST} flag.
310 #if !XNU_KERNEL_PRIVATE
311 IMG4_API_AVAILABLE_20200508
312 OS_EXPORT OS_WARN_RESULT OS_MALLOC OS_NONNULL1 OS_NONNULL2 OS_NONNULL4
313 img4_firmware_t _Nullable
314 img4_firmware_new_from_vnode_4xnu(const img4_runtime_t
*rt
,
315 const img4_firmware_execution_context_t
*exec
,
318 img4_firmware_flags_t flags
);
320 #define img4_firmware_new_from_vnode_4xnu(...) \
321 (img4if->i4if_v7.firmware_new_from_vnode_4xnu(__VA_ARGS__))
322 #endif // !XNU_KERNEL_PRIVATE
326 * @function img4_firmware_new_from_fd_4MSM
327 * Allocate and initialize a new firmware object from a file descriptor.
330 * The runtime in which to initialize the object. This interface is only
331 * supported with the Darwin userspace runtime. If any other runtime is
332 * provided, the implementation's behavior is undefined.
335 * The 4cc which distinguishes the firmware.
338 * A pointer to a file descriptor representing a valid Image4 payload (usually
339 * the contents of either a .im4p or .img4 file). The object assumes ownership
340 * of the descriptor, and upon return, the value referenced by the pointer will
344 * Flags modifying the behavior of the object.
347 * A new firmware object. The implementation will not return NULL.
350 * This interface is the userspace equivalent of
351 * {@link img4_firmware_new_from_vnode_4xnu}, and all the same caveats apply.
354 IMG4_API_AVAILABLE_20200508
355 OS_EXPORT OS_WARN_RESULT OS_MALLOC OS_NONNULL1 OS_NONNULL2
357 img4_firmware_new_from_fd_4MSM(const img4_runtime_t
*rt
,
358 const img4_firmware_execution_context_t
*exec
,
361 img4_firmware_flags_t flags
);
365 * @function img4_firmware_init_from_buff
366 * Initializes a buffer as a firmware object. This interface is useful for
367 * runtimes which do not provide for dynamic memory allocation.
370 * A pointer to the storage to use for the firmware object.
373 * The size of the buffer.
376 * The caller is expected to pass a buffer that is "big enough". If the provided
377 * buffer is too small, the implementation will abort the caller.
381 * uint8_t _buff[IMG4_FIRMWARE_SIZE_RECOMMENDED];
382 * img4_firmware_t fw = NULL;
384 * fw = img4_firmware_init_from_buff(_buff, sizeof(_buff));
385 * img4_firmware_init(fw, IMG4_RUNTIME_DEFAULT, &exec_context,
386 * kImg4Tag_krnl, fw_buff, 0);
388 #if !XNU_KERNEL_PRIVATE
389 IMG4_API_AVAILABLE_20200508
390 OS_EXPORT OS_WARN_RESULT OS_NONNULL1
392 img4_firmware_init_from_buff(void *buff
, size_t len
);
394 #define img4_firmware_init_from_buff(...) \
395 (img4if->i4if_v7.firmware_init_from_buff(__VA_ARGS__))
399 * @function img4_firmware_init
400 * Initialize a firmware object.
403 * A pointer to the storage for the firmware object. This pointer should refer
404 * to a region of memory that is sufficient to hold a {@link img4_firmware_t}
405 * object. This size should be queried with the {@link i4rt_object_size}
406 * function of the runtime.
409 * The runtime in which to initialize the object.
412 * The 4cc which distinguishes the firmware.
415 * A buffer containing a valid Image4 payload (usually the contents of either a
416 * .im4p or .img4 file).
418 * Upon return, the destructor in the buffer is replaced with NULL, and the
419 * implementation assumes responsibility for deallocating the underlying memory.
422 * Flags modifying the behavior of the object.
425 * The resulting object assumes ownership of the given buffer. This routine
426 * should only be used when dynamic memory allocation is not available in the
427 * runtime. Otherwise, use {@link img4_firmware_new}.
429 #if !XNU_KERNEL_PRIVATE
430 IMG4_API_AVAILABLE_20200508
431 OS_EXPORT OS_NONNULL1 OS_NONNULL2 OS_NONNULL3 OS_NONNULL5
433 img4_firmware_init(img4_firmware_t fw
,
434 const img4_runtime_t
*rt
,
435 const img4_firmware_execution_context_t
*exec
,
438 img4_firmware_flags_t flags
);
440 #define img4_firmware_init(...) (img4if->i4if_v7.firmware_init(__VA_ARGS__))
444 * @function img4_firmware_attach_manifest
445 * Attaches a signed manifest to the firmware.
448 * The firmware to manipulate.
451 * A buffer containing a valid Image4 manifest (usually the contents of either a
452 * .im4m or .img4 file).
454 * Upon return, the destructor in the buffer is replaced with NULL, and the
455 * implementation assumes responsibility for deallocating the underlying memory.
458 * If this interface is called on a firmware created with the
459 * {@link IMG4_FIRMWARE_FLAG_ATTACHED_MANIFEST} flag, the implementation's
460 * behavior is undefined.
462 * This interface must be called on any firmware created with the
463 * {@link IMG4_FIRMWARE_FLAG_BARE} flag.
465 * The object assumes ownership of the given buffer.
467 #if !XNU_KERNEL_PRIVATE
468 IMG4_API_AVAILABLE_20200508
469 OS_EXPORT OS_NONNULL1 OS_NONNULL2
471 img4_firmware_attach_manifest(img4_firmware_t fw
,
474 #define img4_firmware_attach_manifest(...) \
475 (img4if->i4if_v7.firmware_attach_manifest(__VA_ARGS__))
479 * @function img4_firmware_select_chip
480 * Returns the chip from the provided array which may be used to authenticate
484 * The firmware to query.
486 * @param acceptable_chips
487 * An array of chips the caller finds acceptable to verify the firmware.
489 * @param acceptable_chips_cnt
490 * The number of elements in {@link acceptable_chips}.
493 * If the manifest may be authenticated by the certificate chain associated with
494 * one of the manifests provided in {@link acceptable_chips}, that chip is
495 * returned. If the manifest cannot be authenticated with any of the provided
496 * chips, NULL is returned.
499 * The result of calling this function on a firmware which does not have a
500 * manifest attached is undefined.
502 * If multiple chips may be used to authenticate the firmware, the
503 * implementation does not define which of those chips will be returned.
505 * If the firmware was created without the
506 * {@link IMG4_FIRMWARE_FLAG_SUBSEQUENT_STAGE} flag, this function will return
507 * NULL. This function cannot be used to establish new trust chains, only to
508 * verify an existing one.
510 #if !XNU_KERNEL_PRIVATE
511 IMG4_API_AVAILABLE_20200724
512 OS_EXPORT OS_WARN_RESULT
513 const img4_chip_t
*_Nullable
514 img4_firmware_select_chip(const img4_firmware_t fw
,
515 const img4_chip_select_array_t _Nonnull acceptable_chips
,
516 size_t acceptable_chips_cnt
);
518 #define img4_firmware_select_chip(...) \
519 (img4if->i4if_v10.firmware_select_chip(__VA_ARGS__))
523 * @function img4_firmware_execute
524 * Authenticate the firmware and execute it within its context.
527 * The firmware to execute.
530 * The chip on which to execute the firmware.
533 * The nonce to use for authentication. May be NULL if the chip environment does
534 * not maintain an anti-replay token or if a chained evaluation is being
538 * The implementation will always invoke the
539 * {@link img4_firmware_authenticated_execute_t} provided in the execution
540 * context with either a successful result or a failure. All error handling must
541 * take place in that context.
543 * The {@link img4_firmware_authenticated_execute_t} is called before the
544 * implementation returns.
546 * The result of executing a firmware without a manifest attached (either via
547 * {@link img4_firmware_attach_manifest} or by creating the firmware with the
548 * {@link IMG4_FIRMWARE_FLAG_ATTACHED_MANIFEST} flag set) is undefined.
550 #if !XNU_KERNEL_PRIVATE
551 IMG4_API_AVAILABLE_20200508
552 OS_EXPORT OS_NONNULL1 OS_NONNULL2
554 img4_firmware_execute(img4_firmware_t fw
,
555 const img4_chip_t
*chip
,
556 const img4_nonce_t
*_Nullable nonce
);
558 #define img4_firmware_execute(...) \
559 (img4if->i4if_v7.firmware_execute(__VA_ARGS__))
563 * @function img4_firmware_evaluate
564 * Evaluate the firmware for authenticity.
567 * The firmware to evaluate.
570 * The chip on which to evaluate the firmware.
573 * The nonce to use for authentication. May be NULL if the chip environment does
574 * not maintain an anti-replay token or if a chained evaluation is being
578 * An error code describing the result of the authentication. If authentication
579 * was successful, zero is returned. Otherwise, one of the following error codes
582 * [EILSEQ] The firmware data is not valid Image4 data -- this will not
583 * be returned for firmwares created with
584 * {@link IMG4_FIRMWARE_FLAG_BARE}
585 * [EFTYPE] The attached manifest is not a valid Image4 manifest
586 * [ENOENT] The attached manifest does not authenticate this type of
588 * [EAUTH] The attached manifest is not authentic (i.e. was not signed
590 * [EACCES] The given chip does not satisfy the constraints of the
592 * [ESTALE] The manifest has been invalidated and is no longer valid for
594 * [ENOEXEC] The firmware has been corrupted, or the given chip does not
595 * satisfy the constraints of the corresponding object in the
599 * This interface should be used when the caller is only concerned with the
600 * authenticity and integrity of the firmware image and does not intend to
603 * The result of evaluating a firmware without a manifest attached (either via
604 * {@link img4_firmware_attach_manifest} or by creating the firmware with the
605 * {@link IMG4_FIRMWARE_FLAG_ATTACHED_MANIFEST} flag set) is undefined.
607 #if !XNU_KERNEL_PRIVATE
608 IMG4_API_AVAILABLE_20200608
609 OS_EXPORT OS_WARN_RESULT OS_NONNULL1 OS_NONNULL2
611 img4_firmware_evaluate(img4_firmware_t fw
,
612 const img4_chip_t
*chip
,
613 const img4_nonce_t
*_Nullable nonce
);
615 #define img4_firmware_evaluate(...) \
616 (img4if->i4if_v9.firmware_evaluate(__VA_ARGS__))
620 * @function img4_firmware_destroy
621 * Destroys a firmware object and releases the associated resources according to
622 * the runtime's specification.
625 * A pointer to the firmware object.
627 * Upon return, this will be replaced with a known-invalid pointer value. This
628 * parameter may be NULL in which case the implementation will return
632 * The implementation will invoke the provided deallocation function of the
633 * buffer object underlying the firmware.
635 #if !XNU_KERNEL_PRIVATE
636 IMG4_API_AVAILABLE_20200508
639 img4_firmware_destroy(img4_firmware_t _Nonnull
*_Nullable fw
);
641 #define img4_firmware_destroy(...) \
642 (img4if->i4if_v7.firmware_destroy(__VA_ARGS__))
645 OS_ASSUME_NONNULL_END
649 #endif // __IMG4_FIRMWARE_H