first and last commit
This commit is contained in:
commit
1bf4efd552
2612 files changed
+636500
No files matched your search
Binary file not shown.
+1543
File diff suppressed because it is too large.
Load diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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
@@ -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.
@@ -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.
|
||||
@@ -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);
|
||||
@@ -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).
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
Reference in new issue
Block a user