first and last commit

This commit is contained in:
Chris Nutter committed 2023-07-08 13:03:17 -07:00
commit 1bf4efd552
2612 files changed
+636500

No files matched your search

Binary file not shown.
+1543
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
+120
View File
@@ -0,0 +1,120 @@
CHAIN VALIDATION
- cert chain consists of concatenation of certificates (binary/der)
- first is a trusted anchor (optional if embedded: PKI_CHECK_ANCHOR_BY_SHA1=0,
otherwise it needs to be there and is compared to an embedded SHA-1 hash),
second intermediate, third leaf.
- if PKI_APPLE_ROOT_CA=1, the chain is anchored to Apple's root, otherwise a
fake chain that matches all checks.
- check signatures on chain
- check intermediate cert subject CN: Apple Secure Boot Certification Authority
- find spec oid extension in leaf and return pointer to blob in cert chain
memory
- generate digest info from passed in hash and add padding
- verify against signature (digest info || hash || padding)
DEBUG style builds expose pki menu commands in iBoot that performs validation
and will print failures.
GENERATE FAKE CHAIN
# Generate and self-sign test CA
openssl req -newkey rsa:2048 -sha1 -days 365 -sha1 -subj "/C=US/O=Apple Inc./OU=Apple Certification Authority/CN=Apple Root CA" -nodes -keyout CA-key.pem -out CA-csr.pem
openssl x509 -req -sha1 -in CA-csr.pem -signkey CA-key.pem -set_serial 0 -out CA-cert.pem -extfile SecureBootCertSpecExtension.txt -extensions CA_default
# Generate and output request for intermediate
openssl req -newkey rsa:2048 -sha1 -days 365 -sha1 -subj "/C=US/O=Apple Inc./OU=Apple Certification Authority/CN=Apple Secure Boot Certification Authority" -nodes -keyout intermediate-key.pem -out intermediate-csr.pem
# Sign intermediate
openssl x509 -req -sha1 -in intermediate-csr.pem -CA CA-cert.pem -CAkey CA-key.pem -set_serial 16 -out intermediate-cert.pem -extfile SecureBootCertSpecExtension.txt -extensions v3_req
# Generate and output request for test leaf
openssl req -newkey rsa:1024 -sha1 -days 365 -sha1 -subj "/C=US/O=Apple Inc./OU=Apple Secure Boot Certification Authority/CN=S5L8900 Secure Boot" -nodes -out leaf-prod-csr.pem -keyout leaf-prod-key.pem
# Sign leaf
openssl x509 -req -sha1 -in leaf-prod-csr.pem -CA intermediate-cert.pem -CAkey intermediate-key.pem -set_serial 1 -out leaf-prod-cert.pem -extfile SecureBootCertSpecExtension.txt -extensions prod_apple_spec_oid
# Generate and output request for test leaf
openssl req -newkey rsa:1024 -sha1 -days 365 -sha1 -subj "/C=US/O=Apple Inc./OU=Apple Secure Boot Certification Authority/CN=S5L8900 Secure Boot" -nodes -out leaf-dev-csr.pem -keyout leaf-dev-key.pem
# Sign leaf
openssl x509 -req -sha1 -in leaf-dev-csr.pem -CA intermediate-cert.pem -CAkey intermediate-key.pem -set_serial 2 -out leaf-dev-cert.pem -extfile SecureBootCertSpecExtension.txt -extensions dev_apple_spec_oid
# convert certs and keys to der
openssl x509 -in CA-cert.pem -outform DER -out CA-cert.der
openssl rsa -in CA-key.pem -outform DER -out CA-key.der
openssl x509 -in intermediate-cert.pem -outform DER -out intermediate-cert.der
openssl x509 -in leaf-prod-cert.pem -outform DER -out leaf-prod-cert.der
openssl x509 -in leaf-dev-cert.pem -outform DER -out leaf-dev-cert.der
# generate blob and sign with leaf
dd if=/dev/random of=blob bs=1000k count=1
openssl dgst -binary -sha1 -out blob.sha1 blob
openssl dgst -sign leaf-prod-key.pem -binary -sha1 -out blob-prod.sig blob
openssl dgst -sign leaf-dev-key.pem -binary -sha1 -out blob-dev.sig blob
# add CA-cert.der to fake_ca.h
openssl x509 -in CA-cert.pem -C > for-fake_ca.h
# partial chain for verification
cat intermediate-cert.der leaf-dev-cert.der > dev-chain.der
cat intermediate-cert.der leaf-prod-cert.der > prod-chain.der
# BUILDS=DEBUG iBoot verification
#usb get blob.sha1 0x09001000
#usb get blob-dev.sig 0x09002000
#usb get dev-chain.der 0x09003000
#pki verify 0x09003000 1632 0x09002000 128 0x09001000 20
Make sure to add the new root cert to lib/pki/anchor_ca.h and use it in
lib/pki/chain-validation.c.
SecureBootCertSpecExtension.txt:
oid_section = new_oids
[ CA_default ]
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always
basicConstraints = critical,CA:true
keyUsage = digitalSignature
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always
[ new_oids ]
apple_spec_oid=1.2.840.113635.100.6.1.1
[ foo_apple_spec_oid ]
1.2.840.113635.100.6.1.1=critical,DER:04:04:46:6f:6f:21
# Octet (04) Length (04) Value (Foo!)
#apple_spec_oid=critical,DER:FEEDFACE
#apple_spec_oid=critical,ASN1:FORMAT:HEX,OCTETSTRING:FEEDFACE
[ prod_apple_spec_oid ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always
1.2.840.113635.100.6.1.1=critical,DER:04:24:33:67:6d:49:24:00:00:00:1c:00:00:00:00:00:00:00:2a:2a:2a:2a:44:4f:52:50:10:00:00:00:04:00:00:00:01:00:00:00
[ dev_apple_spec_oid ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always
1.2.840.113635.100.6.1.1=critical,DER:04:24:33:67:6d:49:24:00:00:00:1c:00:00:00:00:00:00:00:2a:2a:2a:2a:44:4f:52:50:10:00:00:00:04:00:00:00:00:00:00:00
# 0x30 total: Img3, 0x30 skip, 0x1c size, 0x0 no signed data, **** type,
# empty DATA, SMOD 0x0000000000000400
# PROD, skip 16, len 4, val 0 => 44:4f:52:50:10:00:00:00:04:00:00:00:00:00:00:00
# Img3 33:67:6d:49
# skip 30:00:00:00
# len 1c:00:00:00
# lsgn 00:00:00:00
# type 2a:2a:2a:2a
# DATA 41:54:41:44:0c:00:00:00:00:00:00:00
# SDOM 4d:4f:44:53:10:00:00:00:04:00:00:00:00:00:00:00
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+83
View File
@@ -0,0 +1,83 @@
Introduction
============
A number of iBoot modules have fuzzing interfaces. This document describes
how to fuzz those modules, and how to set up a new module for fuzzing.
There are a number of open and closed-source fuzzers available, but by far
the best is AFL (american fuzzy lop): <http://lcamtuf.coredump.cx/afl/>.
The rest of this document is geared towards fuzzing with AFL, but the
interface is fairly generic.
Getting AFL
===========
AFL is available in source format at http://lcamtuf.coredump.cx/afl/.
Building should just be a matter of typing "make".
The source includes a good README. The following AFL docs are also
useful (in the AFL source):
- docs/technical_details.txt
- docs/status_screen.txt
- docs/notes_for_asan.txt
Instrumenting Test Binaries
===========================
AFL is an instrumentation-guided fuzzer, so the test case needs to be
built with AFL's instrumentation. As described in the documents above,
this is accomplished by using the afl-clang tool, which interposes on
clang to modify the assembly produced by clang. It's possible to build
iBoot's test binaries using afl-clang as follows:
make TESTS_FLAVOR=tests-darwin-afl USE_XCRUN=NO HOST_CC='path/to/afl/afl-clang -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk' build-tests
The exact SDK path will depend on the version of OS X being used.
This should produce a number of test binaries located at:
./build/test-darwin-afl/<test-name>/<test-name>
By convention, iBoot fuzz tests have names ending in -fuzz and take a
test input file as the first argument on the commandline.
Seeding the fuzzer
==================
It's possible to seed the fuzzer with a file containing all 0's:
dd if=/dev/zero of=testcases/zeroes bs=1024 count=1
If the binary format being fuzzed is not too complicated, this may
produce good results.
However, the fuzzer does best by starting valid input files. If possible,
their size should be no more than a few kB. If this isn't possible, just
find seed test cases that are as small as possible.
Running Fuzz Jobs
=================
mkdir testcases
<copy test cases to testcases>
mkdir findings
path/to/afl/afl-fuzz -i testcases -o findings -t 500 ./build/tests-darwin-afl/<test-name>/<test-name> @@
Interpreting Results
====================
Read the AFL documentation for details on interpreting the results. Here
are a few tips:
- Inputs producing crashes are obviously very important, and can be found
in findings/crashes.
- Inputs producing hangs may be interesting, or may be a result of the
system being briefly bogged down. Run the test manually to confirm if
it's a real hang. Real hangs can be a sign of a programming error, and
can make it harder to find crashing test cases.
- Inputs producing results that vary from run to run are often a sign of
use after free or buffer overflows. Use address sanitizer to diagnose.
As AFL runs, it produces a corpus of input files that result in different
paths through the program under test. Even if afl doesn't find crashes,
this is a useful set of inputs to run with address sanitizer. This can be
done as follows:
make SANITIZE=YES build-tests
for i in findings/queue/*; do echo; echo $i; ./build/tests-darwin-sanitize/<test-name>/<test-name> $i; done
Binary file not shown.
+199
View File
@@ -0,0 +1,199 @@
Image3 Tagged Object Format
===========================
Overview
--------
The Image3 format attempts to address some of the shortcomings of the Image2 and 'DFU' formats
based on lessons learned during their deployment.
Compared with Image2, Image3 features far fewer fields in the fixed portion of the header, and
discards many of the optional behaviours that have been found to be redundant and/or confusing.
Compared with the DFU format, Image3 provides a flexible mechanism for extending image metadata
and a simpler signing and encryption strategy.
Description
-----------
The Image3 object format features a compact fixed header, followed by a variable-length buffer
containing (tag,data) tuples. A balanced approach is taken towards the use of structured tag data;
tags should avoid collecting unrelated data items, but structured tags are acceptable.
The header contains a magic number ('Img3') identifying the format, size information for the tag
buffer and signed area, and a type value used to describe the contents of the image.
When placed into storage 'owned' by the device, a field in the fixed header can be used to indicate
the skip distance to the next image. This field should be considered a hint only, as it is not
signed.
Code handling tags should be careful not to assume any set of valid tags; new tags may be added
at any point.
Security
--------
Image3 objects are not mutable once hashed and signed. The signing of an image is indicated by
a non-zero value for the "signed length" header field, which further implies the presence of
two tags containing the signed hash and applicable certificate chain. These tags are always
placed last in the buffer, and are necessarily not covered by the signature. The two tags
contain a signed hash (placed first) and the certificate chain buffer (placed last).
The signed hash covers the signed length field and the buffer as described by that length. Code
handling Image3 images must range-check the buffer length against whatever local buffer is in use.
Once the signed hash is validated, the internal structure of the object can be trusted and further
bounds checking is not required for security purposes.
When an Image3 object is written into local storage (storage 'owned' by a given system) the signed
hash should be encrypted using a system-private key. When the object is subsequently read back the
hash should likewise be decrypted. This operation prevents objects being 'stolen' by code that does
not have access to the system-private key, limiting the potential impact of leaked objects.
Format Details
--------------
In the descriptions below, tags may be described as 'unique', in which case only one may be present,
or 'multiple' in which case more than one may legally be present. Additionally, tags may be
mandatory or optional.
Image header
''''''''''''
struct image3_header {
UInt32 ihMagic = 'Img3';
UInt32 ihSkipDistance;
UInt32 ihBufferLength;
UInt32 ihSignedLength;
UInt32 ihType;
UInt8 ihBuffer[];
};
ihSkipDistance is the byte offset from the address of the current header to the next header when the
object is placed in a byte-addressed storage container, e.g. ROM.
ihBufferLength is the valid length of the buffer in bytes.
ihSignedLength is the length of the portion of the buffer which is signed. This is thus the offset
from the start of the buffer to the tag containing the signed hash.
ihType is the four-byte type tag for the image. This is typically consulted before signature
verification when scanning a collection of images, but as it is contained within the signed area
providing verification is successful it can be considered trusted.
Tag header
''''''''''
struct image3_tag {
UInt32 itTag = 'xxxx';
UInt32 itLength;
UInt32 itSkipDistance;
UInt8 itBuffer[];
};
itLength is the valid length in bytes of the data within the tag's data buffer.
itSkipDistance is the distance in bytes from the address of the current tag header to the next tag
header. This value may be adjusted in order to obtain specific alignment of the payload of
subsequent tags.
Signed Hash - "SHSH" - unique, optional
'''''''''''''''''''''''''''''''''''''''
The SHSH tag contains the signed SHA-1 hash of the signed portion of the buffer. If present it is
always the second-last tag in the buffer.
Certificate Chain - 'CERT' - unique, optional
'''''''''''''''''''''''''''''''''''''''''''''
The CERT tag contains the opaque certificate chain that will be used to validate the signed hash.
If present it is always the last tag in the buffer.
Note that it is permitted for the leaf certificate in the certificate chain to carry an Image3
object (which is assumed to be signed/certified by the chain itself), and trust evaluation of
an object may add valid tags to the object by way of this embedded image.
Version - 'VERS' - unique, optional
'''''''''''''''''''''''''''''''''''
Free-form 7-bit ascii version information
Security Epoch - 'SEPO' - unique, optional
''''''''''''''''''''''''''''''''''''''''''
32-bit unsigned little-endian value.
This tag provides the security epoch for which the image is considered valid. If the tag is
not present, the image is valid for any epoch.
Security Domain - 'SDOM' - unique, optional
'''''''''''''''''''''''''''''''''''''''''''
Describes the organisational domain for which this image can be considered valid.
This tag is supplied by the leaf certificate rather than the image itself, in order to constrain the
uses to which a given certificate can be put.
#define kImage3SecurityDomainManufacturer 0
#define kImage3SecurityDomainDarwin 1
Production Status - 'PROD' - unique, optional
'''''''''''''''''''''''''''''''''''''''''''''
Indicates whether this is a 'production' status image.
This tag is supplied by the leaf certificate rather than the image itself, in order to constrain the
uses to which a given certificate can be put.
#define kImage3SecurityProductionStatus 1
Chip Type ID - 'CHIP' - multiple, optional
''''''''''''''''''''''''''''''''''''''''''
Indicates which specific chip type the image is valid for.
This tag is supplied by the leaf certificate rather than the image itself, in order to constrain the
uses to which a given certificate can be put.
Board Type ID - 'BORD' - multiple, optional
Unique Chip ID - 'ECID' - multiple, optional
''''''''''''''''''''''''''''''''''''''''''''
These tags allow for the restriction of objects to specific chip or board types, or specific chips.
For the payload to be considered valid, one of each present tag type must match the device. In the
absence of a tag type, all devices are assumed to match that type.
Data Payload - 'DATA' - unique, optional
''''''''''''''''''''''''''''''''''''''''
This tag is used in the common case where the object has a plain data payload.
Encryption Keybag - 'KBAG' - multiple, optional
'''''''''''''''''''''''''''''''''''''''''''''''
In the case where the data payload is encrypted, one or more keybag tags will be present. The data
payload is never encrypted with a key directly known to the consumer; the payload key is placed in a
keybag, encrypted by a key known to a specific consumer. The keybag includes a selector mechanism
that allows the consumer to determine which keybag is applicable.
The presence of a keybag indicates that the data payload is encrypted.
typedef struct {
u_int32_t kbSelector;
#define kImage3KeybagSelectorNoKey (0)
#define kImage3KeybagSelectorChipUnique (1)
u_int32_t kbKeySize;
u_int8_t kbIVBytes[16];
u_int8_t kbKeyBytes[32];
} Image3TagKBAG;
The kbKeySize value is expresed in bits.
The kbSelector indicates which key is to be used to decrypt the key in kbKeyBytes. The decryption
buffer should be padded with zeroes before decrypting the key.
kImage3KeybagSelectorNoKey The key is not encrypted; use it as-is (this is not useful
except for testing purposes).
kImage3KeybagSelectorChipUnique The key is encrypted with a key unique to the chip type;
this is generally referred to as GID 0.
+78
View File
@@ -0,0 +1,78 @@
Image3 PKI Interface
====================
The Image3 format defines support for the use of Public Key Cryptography digital signature
techniques.
The implementation in turn depends on an external interface to provide this support. This document
describes the interface.
Signature Generation
--------------------
It is assumed that the signature generation process will take as input a cryptographic hash (SHA-1)
and produce a signed object.
In addition, a certificate chain may be supplied that will be enclosed in the Image3 container and
made available to the signature verification phase.
extern int
image3PKISignHash(
void *hashBuffer,
size_t hashSize,
void **resultPointer,
size_t *resultSize,
void **certBlobPointer,
size_t *certBlobSize)
Populates the result buffer with a signed version of the supplied hash.
Additionally obtains a pointer to a buffer containing the certificate chain blob, which will be
supplied to the verification code as-is.
TBD: result pointers to static buffers? allocated data?
Signature Verification
----------------------
The signature verification process is expected to verify the correctness of a hash calculated by the
Image3 parser.
If available at signing time, the certificate chain blob will also be supplied at verification time.
extern int
image3PKIVerifyHash(
void *hashBuffer,
size_t hashSize,
void *signedHashBuffer,
size_t signedHashSize,
void *certBlobBuffer,
size_t certBlobSize,
void **certCustomData,
size_t *certCustomDataSize)
Verifies that the hash in hashBuffer corresponds to the signed hash in signedHashBuffer. If
supplied, may use the contents of the certBlobBuffer in order to perform this verification.
Additionally, if the cert chain contains custom data (e.g. in the Common Name field or elsewhere)
this can be returned via *certCustomData. Such custom data will have been supplied at the time that
the certificate chain was assembled (most likely at the point where the leaf certificate is
generated).
TBD specific results.
Hash Generation
---------------
SHA-1 hashes for validation are generated using an external interfaace.
extern int
image3SHA1Generate(void *dataBuffer, size_t dataSize, void *hashBuffer)
extern int
image3AESDecrypt(void *sourceBuffer, void *dataBuffer, void *keyBuffer, void *ivBuffer,
int keySize);
extern int
image3AESEncrypt(void *sourceBuffer, void *dataBuffer, void *keyBuffer, void *ivBuffer,
int keySize);
+169
View File
@@ -0,0 +1,169 @@
Image3 User Library
===================
The Image3 library provides convenient functions for creating and referencing Image3 format objects.
Overview
--------
An Image3 object is a simple collection of tag/data tuples, with optional support for signing of
images.
Image3 objects are referenced by an Image3ObjectHandle, which can be obtained either by
instantiating a new object, or by creating one from a buffer which may have been loaded from some
other source.
Objects may be mutable, if the library was built with IMAGE3_CREATOR defined and they have not been
signed. Signed objects are never mutable (for obvious reasons).
Signing
-------
When an Image3 object is signed, two tags are added (SHSH and CERT) by the signing process which
contain the signed hash and certificate chain respectively. These tags are always the last two to
be added, and once an image is signed (as part of the finalisation process) it cannot have further
tags added.
Signature verification may discover a nested Image3 object in the certificate chain. This nested
image handle can be accessed by the user and treated as an image in its own right, but is otherwise
not managed by the library.
Creating an Object
------------------
extern int
image3InstantiateNew(
Image3ObjectHandle *newHandle,
size_t initialAllocation);
Creates an object, and allows an initial allocation to be specified for efficiency purposes.
extern int
image3InstantiateFromBuffer(
Image3ObjectHandle *newHandle,
const void *fromBuffer,
const size_t bufferSize,
bool copyBuffer);
Instantiates an object from a buffer. This can be used when reading a finalised but unsigned image
if you wish to further update or sign the image. If copyBuffer is set, or if the image will be
mutable, the image buffer is copied; otherwise it continues to reference the source buffer.
extern int
image3SetTagStructure(
const Image3ObjectHandle withHandle,
u_int32_t withTag,
const void *withValue,
size_t withSize,
int withAlignment);
This is the workhorse tag/data insertion interface. It appends a tag to the object's buffer with
the supplied tag value, and populates the tag data with the value supplied. If the withAlignment
argument is nonzero, it specifies the alignment within the object that the data buffer will have.
Note that this implies that the object itself will always be loaded at an address that is a common
multiple of all of the alignment values in use within the object.
extern int
image3SetTagSignedNumber(
const Image3ObjectHandle withHandle,
u_int32_t withTag,
int64_t withValue);
extern int
image3SetTagUnsignedNumber(
const Image3ObjectHandle withHandle,
u_int32_t withTag,
u_int64_t withValue);
extern int
image3SetTagString(
const Image3ObjectHandle withHandle,
u_int32_t withTag,
char *withValue);
Wrappers around image3SetTagStructure to simplify handling of simple data types.
extern int
image3Finalize(
const Image3ObjectHandle withHandle,
void **objectBuffer,
size_t *objectSize,
bool signImage);
Updates the image's internal summary fields and obtains a pointer/size value for the image buffer
that can be written to a file, etc. Note that if signImage is set, the image will be signed via the
PKI interfaces, at which point it will become immutable.
Working with an Object
----------------------
extern int
image3InstantiateFromBuffer(
Image3ObjectHandle *newHandle,
const void *fromBuffer,
const size_t bufferSize,
bool copyBuffer);
Instantiates an object from a buffer. If the copyBuffer argument is true, the image data is copied,
otherwise it will continue to reference the source buffer.
extern int
image3ValidateSignature(
const Image3ObjectHandle withHandle,
const u_int32_t validationOptions);
Attempts to determine whether an image has a valid signature. Will return EPERM if the image fails
to validate either due to a lack of signature data, or incorrect signature data.
Note that if the certificate chain supplied with the image contains a nested image, it will be
available only if validation is successful.
extern int
image3TagIsPresent(
const Image3ObjectHandle withHandle,
const u_int32_t withTag);
Tests for the presence of a tag without requiring any local storage.
extern int
image3GetTagStruct(
const Image3ObjectHandle withHandle,
const u_int32_t withTag,
void **structPtr,
size_t *structSize,
int skipCount);
Workhorse tag retrieval function. Fetches a pointer to the data of the nominated instance of the
nominated tag. If the structSize argument points to a nonzero value, the data size of the tag is
required to match exactly or an error will be returned.
extern int
image3GetTagSignedNumber(
const Image3ObjectHandle withHandle,
const u_int32_t withTag,
int64_t *toNumber);
extern int
image3GetTagUnsignedNumber(
const Image3ObjectHandle withHandle,
const u_int32_t withTag,
u_int64_t *toNumber);
extern int
image3GetTagString(
const Image3ObjectHandle withHandle,
const u_int32_t withTag,
char **toBuffer);
Wrappers around image3GetTagStruct to simplify the handling of simple data types.
Image3ObjectHandle
image3GetNestedImage(const Image3ObjectHandle withHandle);
Fetshes the image3 handle for a nested image (if one is present).
+83
View File
@@ -0,0 +1,83 @@
MMU usage on ARMv8
------------------
= Permissions =
Pages are mapped with the minimum permissions required. This means
all data is mapped as Write/XN (read/write but not execute)
and code is mapped as read-only. To prevent the page tables from
being modified by an attacker, the page tables are not mapped into
virtual memory at all. Therefore, the page tables cannot be modified
after the MMU is turned on.
To protect against buffer overflows, some pages are left unmapped
to act as guard pages. For applications like iBoot that need to
clear memory, these pages need to be cleared prior to enabling the
MMU.
The ROM trampoline is a special case, as it needs to be copied out
of the ROM into SRAM so that it can be executed from outside of ROM
after ROM access is disabled. To deal with this, the trampoline is
copied by startup code prior to the MMU being enabled, and then
mapped as read-only. This allows the ROM to jump into the trampoline
without having a security risk from writeable code.
To enforce all of the above, the WXN (write execute never) bit is
set in SCTLR whenever the MMU is enabled.
= Secure/Non-secure Walks
The top level page table (regardless of how many total levels you
have) is always walked in secure mode in EL3 regardless of
SCR_EL3.NS. For subsequent levels, the page table attributes (which we
mark as non-secure) are used. Almost immediately after starting up on
cpus with EL3 support, iBoot switches to EL3 non-secure mode. If we
tried to dynamically update the top-level page table to add a mapping
those writes would be non-secure and woudl be tagged as such in the L2
cache. This means they wouldn't be seen by the top-level page table walk
(which remember is always secure) resulting in an abort when the code
tries to access the new mapping.
This is not an issue when the page tables are not modified after
enabling the MMU, so this note is mainly for historical purposes.
See <rdar://problem/11973915>.
= Address space sizes =
All of our ARMv8 CPUs are in SoCs with 36-bit physical addresses.
Because we always map so that a virtual address corresponds to its
physical address, we set the virtual address size to 36 bits in TCR
to match the physical address. As a result, one less level of walk
is required than if we used the full 48-bit virtual addresses
supported by the architecture
Address translation source bits at L0..L3 depend on selection of
4KB/16KB/64KB granule.
= Translation table sizes =
Because translation tables cannot be modified after enabling the MMU,
they need to live in their own pages. Therefore, regardless of how
many entries in a tables are used, each table must be aligned to and
have the size of a mapping granule.
L0 Translation table.
Not used
L1 Translation table.
Granule bits entries size in bytes entry type
4KB [35:30] 128 4096 1GB L2 or block
16KB N/A 0 0 64GB L2
64KB N/A 0 0 4TB L2
L2 Translation table.
Granule bits entries size in bytes entry type
4KB [29:21] 512 4096 2MB L3 or block
16KB [35:25] 2048 16384 32MB L3 or block
64KB [35:29] 2048 65536 512MB L3 or block
L3 Translation table
Granule bits entries size in bytes entry type
4KB [20:12] 512 4096 4KB block
16KB [24:14] 2048 16384 16KB block
64KB [28:16] 8192 65536 64KB block
+159
View File
@@ -0,0 +1,159 @@
/apps
Top-level applications, typically corresponds to a deliverable.
/apps/SecureROM
SecureROM for Darwin SoCs.
/apps/iBoot
Multi-platform Darwin bootloader.
/apps/EmbeddedIOP
Runtime for embedded IO processors.
/arch
Platform architecture-specific code.
/arch/arm
ARM-specific code.
/docs
Optimisim.
/drivers
Portable drivers and driver infrastructure.
/drivers/apple
Drivers for Apple devices.
/drivers/flash_nand
The AND flash translation layer.
/drivers/flash_nor
NOR flash support.
/drivers/power
PMU drivers.
/drivers/primecell
Drivers for ARM Primecell devices.
/drivers/samsung
Drivers for Samsung devices.
/drivers/usb
Device-independent USB infrastructure.
/include
Common header files.
/include/drivers
Headers describing interfaces to drivers and common properties of drivers.
/include/lib
/include/lib/net
/include/lib/usb
Library interface defintions.
/include/platform
Generic interfaces to platform-specific functions.
/include/posix
/include/posix/sys
Interfaces to the Posix subset libarary.
/include/sys
Interfaces to OS services.
/lib
Support library.
/lib/blockdev
Block device support.
/lib/cbuf
Inter-thread pipe.
/lib/cksum
Various checksum routines.
/lib/devicetree
I/O Kit device tree support.
/lib/env
NVRAM environment support.
/lib/fs
Filesystems.
/lib/fs/hfs
HFS+
/lib/heap
Malloc and friends.
/lib/image
Support for the Image2 and Image3 pseudo-filesystems.
/lib/pki
cert chain validation and signature checking.
/lib/libc
Posix libc subset.
/lib/lzss
LZSS decompressor.
/lib/macho
Support for the Mach-O executable format.
/lib/net
Ethernet/IP networking.
/lib/nvram
CHRP NVRAM support.
/lib/paint
Simple graphics primitives.
/lib/partition
MBR partition scheme support.
/lib/syscfg
Support for the diagnostics/manufacturing system configuration area.
/lib/tftp
TFTP client.
/lib/usb
USB client code.
/makefiles
Deliverable makefiles and infrastructure.
/platform
SoC-specific code. One directory per SoC, containing drivers unique to
the SoC, startup code, etc.
/platform/s5l8720x
Samsung S5L8720X ("M2")
/platform/s5l8920x
Apple S5L8920X ("H2P")
/platform/s5l8930x
Apple S5L8930X ("H3P")
/platform/s5l8940x
Apple S5L8940x ("H4P")
/sys
Core OS services.
/target
Target-specific code.
/target/s5l8720xfpga
FPGA board for the S5L8720X
/target/s5l8920xfpga
FPGA board for the S5L8920X
+168
View File
@@ -0,0 +1,168 @@
indent_align_string=true
indent_braces=false
indent_braces_no_func=false
indent_brace_parent=false
indent_namespace=false
indent_extern=false
indent_class=false
indent_class_colon=false
indent_else_if=false
indent_func_call_param=false
indent_func_def_param=false
indent_func_proto_param=false
indent_func_class_param=false
indent_func_ctor_var_param=false
indent_template_param=false
indent_func_param_double=false
indent_relative_single_line_comments=false
indent_col1_comment=false
indent_access_spec_body=false
indent_paren_nl=false
indent_comma_paren=false
indent_bool_paren=false
indent_square_nl=false
indent_preserve_sql=false
sp_balance_nested_parens=false
align_keep_tabs=false
align_with_tabs=false
align_on_tabstop=false
align_number_left=false
align_func_params=false
align_same_func_call_params=false
align_var_def_colon=false
align_var_def_inline=false
align_right_cmt_mix=false
align_mix_var_proto=false
align_single_line_func=true
align_single_line_brace=false
align_nl_cont=true
align_left_shift=true
nl_collapse_empty_body=false
nl_assign_leave_one_liners=true
nl_class_leave_one_liners=true
nl_enum_leave_one_liners=true
nl_getset_leave_one_liners=true
nl_func_leave_one_liners=true
nl_if_leave_one_liners=false
nl_multi_line_cond=false
nl_multi_line_define=false
nl_before_case=false
nl_after_case=false
nl_after_return=true
nl_after_semicolon=true
nl_after_brace_open=true
nl_after_brace_open_cmt=false
nl_after_vbrace_open=true
nl_define_macro=false
nl_squeeze_ifdef=false
nl_ds_struct_enum_cmt=false
nl_ds_struct_enum_close_brace=false
nl_create_if_one_liner=false
nl_create_for_one_liner=false
nl_create_while_one_liner=false
ls_for_split_full=true
ls_func_split_full=true
nl_after_multiline_comment=false
eat_blanks_after_open_brace=true
eat_blanks_before_close_brace=true
mod_pawn_semicolon=true
mod_full_paren_if_bool=true
mod_remove_extra_semicolon=true
mod_sort_import=false
mod_sort_using=false
mod_sort_include=false
mod_move_case_break=false
cmt_indent_multi=false
cmt_c_group=false
cmt_c_nl_start=false
cmt_c_nl_end=false
cmt_cpp_group=false
cmt_cpp_nl_start=false
cmt_cpp_nl_end=false
cmt_cpp_to_c=false
cmt_star_cont=true
cmt_multi_check_last=true
pp_indent_at_level=false
pp_region_indent_code=false
pp_if_indent_code=false
pp_define_at_level=false
input_tab_size=8
indent_columns=8
code_width=120
nl_after_func_body=2
nl_before_block_comment=1
nl_before_c_comment=1
nl_before_cpp_comment=1
cmt_width=120
cmt_sp_before_star_cont=1
cmt_sp_after_star_cont=1
newlines=auto
indent_with_tabs=0
sp_arith=add
sp_assign=add
sp_enum_assign=add
sp_bool=add
sp_compare=add
sp_inside_paren=remove
sp_paren_paren=remove
sp_paren_brace=add
sp_before_ptr_star=add
sp_between_ptr_star=remove
sp_after_ptr_star=remove
sp_before_byref=add
sp_before_sparen=add
sp_inside_sparen=remove
sp_after_sparen=add
sp_sparen_brace=add
sp_before_semi=remove
sp_before_square=remove
sp_before_squares=remove
sp_inside_square=remove
sp_after_comma=add
sp_before_comma=remove
sp_sizeof_paren=remove
sp_func_proto_paren=remove
sp_func_def_paren=remove
sp_inside_fparen=remove
sp_func_call_paren=remove
sp_return_paren=remove
sp_attribute_paren=remove
sp_defined_paren=remove
sp_else_brace=add
sp_brace_else=add
sp_brace_typedef=add
sp_cond_colon=add
sp_cond_question=add
sp_case_label=add
nl_end_of_file=force
nl_fcall_brace=remove
nl_enum_brace=force
nl_struct_brace=force
nl_union_brace=force
nl_if_brace=remove
nl_brace_else=remove
nl_elseif_brace=remove
nl_else_brace=remove
nl_else_if=remove
nl_while_brace=remove
nl_do_brace=remove
nl_brace_while=remove
nl_switch_brace=remove
nl_func_type_name=force
nl_func_proto_type_name=remove
nl_func_paren=remove
nl_func_decl_start=remove
nl_func_decl_end=remove
nl_fdef_brace=add
nl_return_expr=remove
pos_arith=trail
pos_assign=trail
pos_bool=trail
pos_comma=trail
mod_full_brace_do=add
mod_full_brace_for=add
mod_full_brace_function=add
mod_full_brace_if=add
mod_full_brace_while=add
mod_paren_on_return=add
pp_space=add
+110
View File
@@ -0,0 +1,110 @@
iBoot has a system for building and running unit tests. Currently the system only allows
for tests to be run on an x86 host using the native libc, but it's intended that the
system will allow tests to run on x86 with iBoot's libc, and built for arm and run on
targets (either hosted or freestanding).
Overview
========
To add tests to a module, do the following:
1. Create a test driver .c file (details below).
2. Create a test makefile in the module's directory, normally called tests.mk. If the module
requires multiple test binaries (usually because of different compilation options), add
a makefile per binary, usually called tests-<flavor>.mk. Details on makefiles are below
3. Add the makefile to the TEST_MAKEFILES list in makefiles/tests.mk
Writing tests
=============
The only requirement for test binaries is that their main function returns 0 on success
and nonzero on failure. By default, tests should only print to stdio on failure. iBoot
includes a unit testing framework, but its use is optional is a different testing strategy
is needed (or for legacy tests that don't use the framework). Most unit tests should use
the testing framework, however.
Using the testing framework
===========================
To use the testing framework, add tests/unittest-main.o to the test's object file list
(normally TEST_SUPPORT_OBJS, not TEST_OBJS) and include <unittest.h> in your main test
file. unittest-main includes a main() function to run test cases, so only the test cases
themselves need to be defined when using the testing framework.
The unit testing frameworks works with test suites and test cases. A test suite includes
an optional setup function, a list of test cases, and an optional cleanup function.
The setup and cleanup function are respectively run before and after each test case.
Each test cases is simply a function that takes a uintptr_t parameter.
Use struct test_suite to define a test suite, and then use the TEST_SUITE macro to make
the test suite visble to the main() function. For example:
struct test_suite my_test_suite = {
.name = "mymodule",
.setup_function = my_setup_function // optional
.cleanup_function = my_cleanup_function // optional
.test_cases = {
{ "test1", run_test1, 0 },
{ "test2,0", run_test2, 0 }, // passes 0 in parameter
{ "test2,100", run_test2, 100 }, // passes 100 in parameter
TEST_CASE_LAST
}
};
Test cases are defined by their name, their function, and their argument (a uintptr_t).
Test case functions take a single uintptr_t parameter and return void.
A test succeeds if no assertions fail, no unexpected panics occur, expected panics
(if any) do occur, and TEST_FAIL is not called. Tests are immediately aborted on
assertion failures, panics (expected or unexpected), and calls to TEST_FAIL.
Assertions can be embedded inside the code under test using the typical iBoot ASSERT
and RELEASE_ASSERT macros. These assertions end up in shipping code, of course. For
assertions in the test code, the unittest framework provides a number of convenience
macros, including:
For integeger types: TEST_ASSERT_{EQ,NEQ,GT,LT,GTE,LTE}
For C strings: TEST_ASSERT_STR_EQ, TEST_ASSERT_STR_NEQ
For binary data: TEST_ASSERT_MEM_EQ, TEST_ASSERT_MEM_NEQ
For pointers: TEST_ASSERT_PTR_EQ, TEST_ASSERT_PTR_NEQ, TEST_ASSERT_NULL, TEST_ASSERT_NOT_NULL
These macros (with the exception of the MEM macros) support printing the expression and
value for the left hand and right hand side of the comparison on failure.
A general-purpose TEST_FAIL macro is also provided for things not covered by the assertion
macros above.
Writing test makefiles
======================
Test makefiles define the following variables:
TEST_NAME
The name of the test binary, must be unique
TEST_OBJS
The object files being tested
TEST_SUPPORT_OBJS (optional):
Object files used to run the tests. These are listed separately so that
their source files are not included in test coverage reporting
TEST_CFLAGS (optional):
CFLAGS to be used while building the test binary
TEST_LDFLAGS (optional):
LDFLAGS to be used when building the test binary
Test coverage
=============
The unit tests are automatically built with gcov support. This can be suppressed by passing
COVERAGE=NO on the make commandline.
make COVERAGE=NO tests
The best way to parse the coverage info generated by the tests is with the gcovr tool
(find it online until it gets included in iBoot source). Run the tool as follows:
mkdir -p build/coverage && ./gcovr -b -r . --html -o build/coverage/index.html --html-details
This will only give coverage statistics for the source files as built for unit testing, which
may be different from how they're built for real targets. To see how well the tests are
covering real world scenarios, it's possible to generate coverage info for real targets. This
will just emit info on which source lines emitted executable code; no profiling will actually
be performed on the targets. To generate this info, add COVERAGE=YES to the make commandline:
make COVERAGE=YES build
+67
View File
@@ -0,0 +1,67 @@
iBoot Upgrade Mode
==================
The iBoot application normally insists on booting from the first
partition on the storage device, using a kernelcache located in
/System/Library/Caches/com.apple.kernelcaches/kernelcache, with a
devicetree located in ROM and with the first partition as the root
device.
Upgrade mode provides an alternative boot path suitable for booting a
standalone restore/recovery system. It chains to a new bootloader,
and the new bootloader then loads kernelcache, devicetree, ramdisk and
optionally a display image before booting the kernelcache.
To invoke upgrade mode, the boot-command variable must be set to
'upgrade', and the upgrade partition must contain the following files:
/iBEC
/kernelcache
/devicetree
/ramdisk
/apticket.der
being the appropriate iBoot iBEC component, kernelcache, device tree,
ramdisk and personalised AP ticket for the system. In addition if the
file /logo is present, it will be displayed by the iBEC before the other
components are loaded.
When the kernelcache is booted, the RELEASE-configured iBEC will force
the boot-args variable to:
'rd=md0 nand-enable-reformat=1 -progress'
Non-RELEASE configurations will add 'rd=md0' to boot-args but
otherwise preserve its contents. In neither case is the value saved
to NVRAM.
All of the files listed above are expected to be in their usual
(image3) format, and must be signed and/or personalised as normal.
Both iBoot and the upgrade iBEC will identify the upgrade partition by
its LwVM partition name, which must be 'Update'.
If any of the following occurs, the unit will end up in the ROM
iBoot in recovery mode:
- the upgrade partition does not exist or cannot be mounted
- the file /iBEC does not exist in the upgrade partition
- the contents of the iBEC file are not an Image3 file or fail
authentication
If any of the following occurs, the unit will end up in the upgrade
iBEC in recovery mode:
- the upgrade partition cannot be mounted (e.g. due to NAND
format incompatibility)
- the files /kernelcache, /devicetree and /ramdisk do not exist
in the upgrade partition
- the contents of any of these files are not valid Image3, or
fail authentication
- the kernelcache file does not contain a compressed mach-o
kernelcache
- the devicetree file does not contain a valid devicetree
The iBEC component will set the auto-boot variable to false when
loaded in upgrade mode, to avoid the risk of locking the unit up due
to a hang while booting the upgrade kernel.