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