first and last commit
This commit is contained in:
commit
1bf4efd552
2612 files changed
+636500
No files matched your search
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2013 Apple Inc. All rights reserved.
|
||||
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
#include <debug.h>
|
||||
#include <sys/boot.h>
|
||||
#include <sys/menu.h>
|
||||
#include <lib/image.h>
|
||||
#include <lib/env.h>
|
||||
#include <lib/fs.h>
|
||||
#include <platform/memmap.h>
|
||||
|
||||
#if defined(WITH_MENU) && WITH_MENU
|
||||
|
||||
static int do_image(int argc, struct cmd_arg *args)
|
||||
{
|
||||
|
||||
bool detailed;
|
||||
int ret_val;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("not enough arguments.\n");
|
||||
usage:
|
||||
printf("%s list [<detailed>]\n", args[0].str);
|
||||
printf("%s load [<type>|memory] [<address>]\n", args[0].str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!strcmp("list", args[1].str)) {
|
||||
if (argc > 2)
|
||||
detailed = true;
|
||||
else
|
||||
detailed = false;
|
||||
image_dump_list(detailed);
|
||||
} else if (!strcmp("load", args[1].str)) {
|
||||
struct image_info *image;
|
||||
addr_t source_address;
|
||||
size_t filesize;
|
||||
void *addr;
|
||||
size_t len = 0xFFFFFFFF;
|
||||
u_int32_t type;
|
||||
u_int32_t *types = NULL; /* default to any image type */
|
||||
u_int32_t count = 0;
|
||||
|
||||
if (argc < 3) {
|
||||
printf("not enough arguments.\n");
|
||||
goto usage;
|
||||
}
|
||||
|
||||
if (!strcmp(args[2].str, "memory")) {
|
||||
/* load image from memory */
|
||||
|
||||
source_address = env_get_uint("loadaddr", DEFAULT_LOAD_ADDRESS);
|
||||
filesize = env_get_uint("filesize", DEFAULT_KERNEL_SIZE);
|
||||
|
||||
if ((image = image_create_from_memory((void *)source_address, filesize, 0)) == NULL) {
|
||||
printf("image creation failed\n");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* search for image */
|
||||
|
||||
type = htonl(*(uint32_t *)args[2].str);
|
||||
|
||||
image = image_find(type);
|
||||
if (!image) {
|
||||
printf("could not find image\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* use the image type since it is known */
|
||||
types = &type;
|
||||
count = 1;
|
||||
}
|
||||
|
||||
if (argc < 4)
|
||||
addr = (void *)DEFAULT_KERNEL_ADDRESS;
|
||||
else
|
||||
addr = (void *)args[3].u;
|
||||
|
||||
ret_val = image_load(image, types, count, NULL, &addr, &len);
|
||||
if ( 0 <= ret_val )
|
||||
printf("successfully loaded image\n");
|
||||
else
|
||||
printf("unable to load image\n");
|
||||
} else {
|
||||
printf("unrecognized command.\n");
|
||||
goto usage;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MENU_COMMAND_DEBUG(image, do_image, "flash image inspection", NULL);
|
||||
|
||||
#if WITH_IMAGE4
|
||||
|
||||
static int do_image4_test(int argc, struct cmd_arg *args)
|
||||
{
|
||||
int result = -1, i;
|
||||
char file_path[FS_MAXPATHLEN];
|
||||
bool file_option = false;
|
||||
u_int32_t image_type;
|
||||
u_int32_t *image_types = NULL;
|
||||
u_int32_t image_types_count = 0;
|
||||
u_int32_t options = 0;
|
||||
addr_t from_address, to_address = DEFAULT_KERNEL_ADDRESS;
|
||||
size_t from_size, to_size = DEFAULT_LOAD_SIZE;
|
||||
bool load_image_type = false;
|
||||
|
||||
from_address = env_get_uint("loadaddr", DEFAULT_LOAD_ADDRESS);
|
||||
from_size = env_get_uint("filesize", DEFAULT_LOAD_SIZE);
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(args[i].str, "-options") == 0) {
|
||||
options = args[++i].u;
|
||||
}
|
||||
else if (strcmp(args[i].str, "-type") == 0) {
|
||||
image_type = htonl(*(uint32_t *)args[++i].str);
|
||||
image_types = &image_type;
|
||||
image_types_count = 1;
|
||||
}
|
||||
else if (strcmp(args[i].str, "-file") == 0) {
|
||||
snprintf(file_path, FS_MAXPATHLEN, "/boot%s", args[++i].str);
|
||||
file_option = true;
|
||||
}
|
||||
else if (strcmp(args[i].str, "-addr") == 0) {
|
||||
from_address = args[++i].u;
|
||||
}
|
||||
else if (strcmp(args[i].str, "-size") == 0) {
|
||||
from_size = args[++i].u;
|
||||
}
|
||||
else if (strcmp(args[i].str, "-load-type") == 0) {
|
||||
load_image_type = true;
|
||||
}
|
||||
else {
|
||||
goto print_usage;
|
||||
}
|
||||
}
|
||||
|
||||
if (file_option) {
|
||||
#if WITH_FS
|
||||
result = mount_bootfs();
|
||||
if (result == 0) {
|
||||
result = image_load_file(file_path, &to_address, &to_size, image_types, image_types_count, NULL, options);
|
||||
fs_unmount("/boot");
|
||||
}
|
||||
else {
|
||||
dprintf(DEBUG_INFO, "root filesystem mount failed\n");
|
||||
}
|
||||
#else
|
||||
dprintf(DEBUG_INFO, "file-system support not available\n");
|
||||
#endif
|
||||
}
|
||||
else if (load_image_type) {
|
||||
if (image_types_count != 0)
|
||||
result = image_load_type(&to_address, &to_size, image_type, options);
|
||||
else
|
||||
dprintf(DEBUG_INFO, "image type not specified\n");
|
||||
}
|
||||
else {
|
||||
result = image_load_memory(from_address, from_size, &to_address, &to_size, image_types, image_types_count, NULL, options);
|
||||
}
|
||||
|
||||
if (result == 0)
|
||||
dprintf(DEBUG_INFO, "image_load test succeed\n");
|
||||
else
|
||||
dprintf(DEBUG_INFO, "image_load test failed, result:%d\n", result);
|
||||
|
||||
security_restore_environment();
|
||||
|
||||
return result;
|
||||
|
||||
print_usage:
|
||||
dprintf(DEBUG_INFO, "image4_test [-file <file_path>] [-options <options>] [-type <image_type>] [-load-type] [-addr <address>] [-size <size>] [-help]\n");
|
||||
dprintf(DEBUG_INFO, "\t- address defaults to $loadadr and size defaults to $filesize\n");
|
||||
dprintf(DEBUG_INFO, "\t- load-type option loads image of type specified with '-type' option from nand_firmare partition\n");
|
||||
dprintf(DEBUG_INFO, "\t- list option list images stored in nand_firmare partition\n");
|
||||
dprintf(DEBUG_INFO, "\t- various options -> require_trust:(1<<1), local_storage:(1<<3), new_trust_chain:(1<<4) \n");
|
||||
dprintf(DEBUG_INFO, "\t- various types -> dtre, rdtr, krnl, rkrn, ibss, ibec, illb, ibot, rdsk, logo, rlgo, recm, diag, 0 (any) \n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
MENU_COMMAND_DEBUG(image4_test, do_image4_test, "load and validate image4", NULL);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2013 Apple Inc. All rights reserved.
|
||||
* Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
#include <debug.h>
|
||||
#include <stdlib.h>
|
||||
#include <lib/profile.h>
|
||||
#include <lib/env.h>
|
||||
#include <lib/image.h>
|
||||
#include <errno.h>
|
||||
#include <platform.h>
|
||||
#include <platform/breadcrumbs.h>
|
||||
|
||||
#if WITH_FS
|
||||
#include <lib/fs.h>
|
||||
#include <platform/memmap.h>
|
||||
#endif
|
||||
|
||||
#if WITH_IMAGE3
|
||||
# include "image3/image3_wrapper.h"
|
||||
#endif
|
||||
#if WITH_IMAGE4
|
||||
# include "image4/image4_wrapper.h"
|
||||
#endif
|
||||
|
||||
|
||||
#define MAP_SIZE 512
|
||||
|
||||
#if WITH_IMAGE3 || WITH_IMAGE4 || WITH_ENV
|
||||
static uint32_t image_version = 0;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Look for a compatible image superblock in the supplied block device.
|
||||
*/
|
||||
int
|
||||
image_search_bdev(struct blockdev *bdev, off_t map_offset, uint32_t imageOptions)
|
||||
{
|
||||
int err;
|
||||
void *buf = 0;
|
||||
int images_found = 0;
|
||||
|
||||
posix_memalign(&buf, CPU_CACHELINE_SIZE, MAP_SIZE);
|
||||
|
||||
/*
|
||||
* Read in the image superblock.
|
||||
*/
|
||||
err = blockdev_read(bdev, buf, map_offset, MAP_SIZE);
|
||||
if (err != MAP_SIZE)
|
||||
goto exit;
|
||||
|
||||
#if WITH_IMAGE4
|
||||
if (images_found == 0) {
|
||||
images_found = image4_process_superblock(buf, bdev, map_offset, imageOptions);
|
||||
if (images_found)
|
||||
image_version = 4;
|
||||
}
|
||||
#endif
|
||||
#if WITH_IMAGE3
|
||||
if (images_found == 0) {
|
||||
images_found = image3_process_superblock((Image2Superblock *)buf, bdev, map_offset, imageOptions);
|
||||
if (images_found)
|
||||
image_version = 3;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WITH_ENV
|
||||
if (image_version)
|
||||
env_set_uint("image-version", image_version, 0);
|
||||
#endif
|
||||
|
||||
exit:
|
||||
if (buf)
|
||||
free(buf);
|
||||
|
||||
return images_found;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free all images found by image_search_bdev(), above, for the specified bdev.
|
||||
*/
|
||||
void
|
||||
image_free_bdev(struct blockdev *bdev)
|
||||
{
|
||||
#if WITH_IMAGE4
|
||||
image4_free_bdev(bdev);
|
||||
#endif
|
||||
#if WITH_IMAGE3
|
||||
image3_free_bdev(bdev);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Load an already-known image.
|
||||
*
|
||||
* This function is complicated by the desire to support multiple image formats
|
||||
* at the same time. The logic for images of an unknown type being loaded from
|
||||
* memory is that if configured, handlers should be tried in a canonical order,
|
||||
* falling back to a previous version if the loader returns EINVAL.
|
||||
*/
|
||||
int
|
||||
image_load(struct image_info *image, const u_int32_t *types, u_int32_t count, u_int32_t *actual, void **load_addr, size_t *load_len)
|
||||
{
|
||||
void *addr = *load_addr;
|
||||
size_t len = *load_len;
|
||||
int ret_val = -1;
|
||||
|
||||
if (NULL == image)
|
||||
goto exit;
|
||||
|
||||
if (image->imageAllocation > len) {
|
||||
dprintf(DEBUG_CRITICAL, "image_load: image too large\n");
|
||||
platform_record_breadcrumb_int("image_load_pre_fail", kBCImgLoadImageTooLarge);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((types == NULL) && (count != 0)) {
|
||||
dprintf(DEBUG_CRITICAL, "image_load: count must be zero if types is NULL\n");
|
||||
platform_record_breadcrumb_int("image_load_pre_fail", kBCImgLoadCountNotZero);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((count > 1) && (actual == NULL)) {
|
||||
dprintf(DEBUG_CRITICAL, "image_load: actual must not be NULL when types has multiple values\n");
|
||||
platform_record_breadcrumb_int("image_load_pre_fail", kBCImgLoadCountIsZero);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (actual != NULL) {
|
||||
*actual = IMAGE_TYPE_ANY;
|
||||
}
|
||||
|
||||
dprintf(DEBUG_INFO, "loading image with private magic %x\n", image->imagePrivateMagic);
|
||||
switch (image->imagePrivateMagic) {
|
||||
#if WITH_IMAGE4
|
||||
case IMAGE4_IMAGE_INFO_MAGIC:
|
||||
ret_val = image4_load(image, types, count, actual, &addr, &len);
|
||||
break;
|
||||
#endif
|
||||
#if WITH_IMAGE3
|
||||
case IMAGE3_IMAGE_INFO_MAGIC:
|
||||
ret_val = image3_load(image, types, count, actual, &addr, &len);
|
||||
break;
|
||||
#endif
|
||||
case IMAGE_MEMORY_INFO_MAGIC:
|
||||
dprintf(DEBUG_INFO, "memory image\n");
|
||||
#if WITH_IMAGE4
|
||||
/* image4 is forgiving, try it first */
|
||||
dprintf(DEBUG_INFO, "trying image4\n");
|
||||
ret_val = image4_load(image, types, count, actual, &addr, &len);
|
||||
if (ret_val == 0) {
|
||||
/* good image4 image */
|
||||
break;
|
||||
}
|
||||
dprintf(DEBUG_INFO, "image4_load failed\n");
|
||||
|
||||
/* restore addr & len for next image format's try */
|
||||
addr = *load_addr;
|
||||
len = *load_len;
|
||||
#endif
|
||||
#if WITH_IMAGE3
|
||||
/* image3 is forgiving, try it second */
|
||||
dprintf(DEBUG_INFO, "trying image3\n");
|
||||
ret_val = image3_load(image, types, count, actual, &addr, &len);
|
||||
if (ret_val == 0) {
|
||||
/* good image3 image */
|
||||
break;
|
||||
}
|
||||
dprintf(DEBUG_INFO, "image3_load failed\n");
|
||||
|
||||
/* restore addr & len for next image format's try */
|
||||
addr = *load_addr;
|
||||
len = *load_len;
|
||||
#endif
|
||||
#if !(WITH_IMAGE3 || WITH_IMAGE4)
|
||||
/* raw image */
|
||||
memcpy(addr, image->imagePrivate, len);
|
||||
ret_val = 0;
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
if (ret_val == 0) {
|
||||
*load_addr = addr;
|
||||
*load_len = len;
|
||||
} else {
|
||||
*load_addr = 0;
|
||||
*load_len = 0;
|
||||
|
||||
/* any value other than zero is an error, our callers expect -1 */
|
||||
ret_val = -1;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
void
|
||||
image_dump_list(bool detailed)
|
||||
{
|
||||
#if WITH_IMAGE4
|
||||
image4_dump_list(detailed);
|
||||
#endif
|
||||
#if WITH_IMAGE3
|
||||
image3_dump_list(detailed);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a handle to the first instance of an image of (type)
|
||||
*/
|
||||
struct image_info *
|
||||
image_find(u_int32_t type)
|
||||
{
|
||||
struct image_info *image = 0;
|
||||
|
||||
#if WITH_IMAGE4
|
||||
if (image == 0) image = image4_find(type);
|
||||
#endif
|
||||
#if WITH_IMAGE3
|
||||
if (image == 0) image = image3_find(type);
|
||||
#endif
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create an image from a range of memory, rather than finding it on a bdev.
|
||||
*/
|
||||
struct image_info *
|
||||
image_create_from_memory(void *address, size_t length, uint32_t imageOptions)
|
||||
{
|
||||
struct image_info *image = NULL;
|
||||
|
||||
image = malloc(sizeof(struct image_info));
|
||||
|
||||
image->imageLength = length;
|
||||
image->imageAllocation = length;
|
||||
image->imagePrivateMagic = IMAGE_MEMORY_INFO_MAGIC;
|
||||
image->imageOptions = imageOptions;
|
||||
image->imagePrivate = address;
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
#if WITH_FS
|
||||
/*
|
||||
* Load an image from a file.
|
||||
*/
|
||||
int
|
||||
image_load_file(const char *path, addr_t *address, size_t *length, const u_int32_t *types, u_int32_t count, u_int32_t *actual, u_int32_t options)
|
||||
{
|
||||
struct image_info *image;
|
||||
int result;
|
||||
|
||||
if (fs_load_file(path, DEFAULT_LOAD_ADDRESS, length))
|
||||
return(-1);
|
||||
if (NULL == (image = image_create_from_memory((void *)DEFAULT_LOAD_ADDRESS, *length, options))) {
|
||||
platform_record_breadcrumb_marker("ICFM-malloc-fail");
|
||||
return(-1);
|
||||
}
|
||||
result = image_load(image, types, count, actual, (void **)address, length);
|
||||
image_free(image);
|
||||
return(result);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Load an image from a memory buffer.
|
||||
*/
|
||||
int
|
||||
image_load_memory(addr_t fromAddress, size_t fromLength, addr_t *address, size_t *length, const u_int32_t *types, u_int32_t count, u_int32_t *actual, u_int32_t options)
|
||||
{
|
||||
struct image_info *image;
|
||||
int result;
|
||||
|
||||
PROFILE_ENTER('ILM');
|
||||
|
||||
if (NULL == (image = image_create_from_memory((void *)fromAddress, fromLength, options)))
|
||||
return(-1);
|
||||
|
||||
result = image_load(image, types, count, actual, (void **)address, length);
|
||||
image_free(image);
|
||||
|
||||
PROFILE_EXIT('ILM');
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find and load an image of the given type from the default image device.
|
||||
*/
|
||||
int
|
||||
image_load_type(addr_t *address, size_t *length, uint32_t type, uint32_t options)
|
||||
{
|
||||
struct image_info *image;
|
||||
|
||||
if (NULL == (image = image_find(type)))
|
||||
return(-1);
|
||||
|
||||
return(image_load(image, &type, 1, NULL, (void **)address, length));
|
||||
}
|
||||
|
||||
/*
|
||||
* Free an allocated image.
|
||||
*/
|
||||
void
|
||||
image_free(struct image_info *image)
|
||||
{
|
||||
if ((NULL != image) && (image->imagePrivateMagic == IMAGE_MEMORY_INFO_MAGIC)) {
|
||||
free(image);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,383 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2011 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
#ifndef _IMAGE3_H_
|
||||
#define _IMAGE3_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifndef false
|
||||
# include <stdbool.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* All Image3 operations use an Image3ObjectHandle to refer to the image being worked on.
|
||||
*/
|
||||
struct _Image3InternalState;
|
||||
typedef struct _Image3InternalState *Image3ObjectHandle;
|
||||
|
||||
/*
|
||||
* Discards an Image3 image.
|
||||
*/
|
||||
extern void
|
||||
image3Discard(
|
||||
Image3ObjectHandle *withHandle);
|
||||
|
||||
|
||||
#ifdef IMAGE3_CREATOR
|
||||
/*
|
||||
* Create a new Image3 working object.
|
||||
*
|
||||
* Returns:
|
||||
* 0 Success
|
||||
* ENOMEM Unable to allocate memory
|
||||
*/
|
||||
extern int
|
||||
image3InstantiateNew(
|
||||
Image3ObjectHandle *newHandle,
|
||||
size_t initialAllocation,
|
||||
u_int32_t imageType);
|
||||
|
||||
/*
|
||||
* Finalises an image.
|
||||
*
|
||||
* If signImage is set, hashes and signs the image. Reservation length, if non-zero, indicates that the final signed image
|
||||
* will include tags not currently present in the image. A partial digest is computed, but the size of the reservation is
|
||||
* required so that ihSignedLength can be set properly for inclusion in the partial hash state. The partial digest is
|
||||
* constrained to conclude on a 64 byte boundary by adding the appropriate padding following the last tag in the signed portion
|
||||
* of a finalised image.
|
||||
*
|
||||
* Returns:
|
||||
* 0 Success
|
||||
*/
|
||||
extern int
|
||||
image3Finalize(
|
||||
const Image3ObjectHandle withHandle,
|
||||
void **objectBuffer,
|
||||
size_t *objectSize,
|
||||
bool signImage,
|
||||
size_t reservationSize);
|
||||
|
||||
/*
|
||||
* Set a numeric tag.
|
||||
*
|
||||
* Returns:
|
||||
* 0 Success
|
||||
* ENOMEM Unable to allocate memory
|
||||
*/
|
||||
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);
|
||||
|
||||
/*
|
||||
* Set a string tag.
|
||||
*
|
||||
* Returns:
|
||||
* 0 Success
|
||||
* ENOMEM Unable to allocate memory
|
||||
*/
|
||||
extern int
|
||||
image3SetTagString(
|
||||
const Image3ObjectHandle withHandle,
|
||||
u_int32_t withTag,
|
||||
char *withValue);
|
||||
|
||||
/*
|
||||
* Set a structure tag.
|
||||
*
|
||||
* Note that the withAlignment field aligns the structure, not the tag.
|
||||
*
|
||||
* Returns:
|
||||
* 0 Success
|
||||
* ENOMEM Unable to allocate memory
|
||||
*/
|
||||
extern int
|
||||
image3SetTagStructure(
|
||||
const Image3ObjectHandle withHandle,
|
||||
u_int32_t withTag,
|
||||
const void *withValue,
|
||||
size_t withSize,
|
||||
int withAlignment);
|
||||
|
||||
|
||||
/*
|
||||
* Advances the cursor with zero padding.
|
||||
*
|
||||
* Returns:
|
||||
* 0 Success
|
||||
* ENOMEM Unable to allocate memory
|
||||
* EROFS Image is read-only
|
||||
*/
|
||||
extern int
|
||||
image3AdvanceCursorWithZeroPad(
|
||||
const Image3ObjectHandle withHandle,
|
||||
int withSize);
|
||||
|
||||
#endif /* IMAGE3_CREATOR */
|
||||
|
||||
|
||||
/*
|
||||
* Take a data buffer that might contain an Image3 object and get a handle to it.
|
||||
*
|
||||
* Note that no security-relatd validation is performed by this operation.
|
||||
*
|
||||
* If IMAGE3_CREATOR is defined and the image is mutable, or if copyBuffer is
|
||||
* true, then the image buffer is copied. Otherwise the image directly references
|
||||
* the supplied buffer.
|
||||
*
|
||||
* Returns:
|
||||
* 0 Success.
|
||||
* EINVAL The contents of the buffer are malformed
|
||||
*/
|
||||
extern int
|
||||
image3InstantiateFromBuffer(
|
||||
Image3ObjectHandle *newHandle,
|
||||
const void *fromBuffer,
|
||||
const size_t bufferSize,
|
||||
bool copyBuffer);
|
||||
|
||||
/*
|
||||
* Validate the signature on an Image3 object.
|
||||
*
|
||||
* Note that images from untrusted sources should be handled with *extreme caution*
|
||||
* until this operation has reported success.
|
||||
*
|
||||
* If the object was loaded from local storage where it was expected that it was
|
||||
* personalised for the device (normally the case) then the kImage3ValidateLocalStorage
|
||||
* option should be supplied.
|
||||
*
|
||||
* If the object's validity can only be asserted via the ticket API,
|
||||
* kImage3ValidateRequireTicket should be supplied.
|
||||
*
|
||||
* The result of the validation operation is cached, so it is safe to call this function
|
||||
* multiple times. Once the initial validation operation is performed, the validation
|
||||
* options are ignored, so knowledge of the source of the object is not required in this
|
||||
* case.
|
||||
*
|
||||
* Returns:
|
||||
* 0 Success.
|
||||
* EINVAL The contents of the buffer are malformed or otherwise cannot be validated.
|
||||
* EPERM Validation failed, the image cannot be trusted.
|
||||
*/
|
||||
#define kImage3ValidateLocalStorage (1<<0)
|
||||
#define kImage3ValidateRequireTicket (1<<2)
|
||||
|
||||
extern int
|
||||
image3ValidateSignature(
|
||||
const Image3ObjectHandle withHandle,
|
||||
const u_int32_t expectedType,
|
||||
const u_int32_t validationOptions,
|
||||
bool *validatedWithEmbeddedSignature);
|
||||
|
||||
/*
|
||||
* Test for the presence of a tag in an image.
|
||||
*
|
||||
* Returns:
|
||||
* 0 Success
|
||||
* EINVAL The buffer is malformed.
|
||||
* ENOENT The tag was not found.
|
||||
*/
|
||||
extern int
|
||||
image3TagIsPresent(
|
||||
const Image3ObjectHandle withHandle,
|
||||
const u_int32_t withTag);
|
||||
|
||||
/*
|
||||
* Fetch a numeric tag's value.
|
||||
*
|
||||
* Returns:
|
||||
* 0 Success
|
||||
* EINVAL The buffer is malformed.
|
||||
* ENOENT The tag was not found.
|
||||
*/
|
||||
extern int
|
||||
image3GetTagSignedNumber(
|
||||
const Image3ObjectHandle withHandle,
|
||||
const u_int32_t withTag,
|
||||
int64_t *toNumber,
|
||||
int skipCount);
|
||||
|
||||
extern int
|
||||
image3GetTagUnsignedNumber(
|
||||
const Image3ObjectHandle withHandle,
|
||||
const u_int32_t withTag,
|
||||
u_int64_t *toNumber,
|
||||
int skipCount);
|
||||
|
||||
/*
|
||||
* Fetch a string tag's value.
|
||||
*
|
||||
* Returns:
|
||||
* 0 Success. *toBuffer contains an ASCIIZ string that must be freed by the caller.
|
||||
* EINVAL The buffer is malformed.
|
||||
* ENOENT The tag was not found.
|
||||
*/
|
||||
extern int
|
||||
image3GetTagString(
|
||||
const Image3ObjectHandle withHandle,
|
||||
const u_int32_t withTag,
|
||||
char **toBuffer,
|
||||
int skipCount);
|
||||
|
||||
/*
|
||||
* Fetch a direct pointer to a structure tag. Note that this points into the image itself
|
||||
* and should be used with some caution.
|
||||
*
|
||||
* The skipCount argument may be used to specify a number of matching tags to be ignored.
|
||||
*
|
||||
* Returns:
|
||||
* 0 Success.
|
||||
* EINVAL The buffer is malformed.
|
||||
* ENOENT The tag was not found.
|
||||
*/
|
||||
extern int
|
||||
image3GetTagStruct(
|
||||
const Image3ObjectHandle withHandle,
|
||||
const u_int32_t withTag,
|
||||
void **structPtr,
|
||||
size_t *structSize,
|
||||
int skipCount);
|
||||
|
||||
/*
|
||||
* Compute the digest to be signed into the root ticket. If the image has been previously
|
||||
* personalized with the old method (with a signature covering an added ECID tag), the digest
|
||||
* excludes the personalized region.
|
||||
*
|
||||
* Although the underlying image3 buffer is returned unmodified, this function may
|
||||
* temporarily modify the buffer when computing the hash. The buffer must therefore be in a
|
||||
* writable region of memory.
|
||||
|
||||
*/
|
||||
extern int
|
||||
image3GetPrePersonalizedDigest(
|
||||
const Image3ObjectHandle withHandle,
|
||||
uint8_t *hashBuffer,
|
||||
size_t hashBufferLength);
|
||||
|
||||
/*
|
||||
* Return the nested image's handle (if one exists).
|
||||
*
|
||||
* Note that the nested image is only discoverable if an image is authenticated.
|
||||
*/
|
||||
Image3ObjectHandle
|
||||
image3GetNestedImage(const Image3ObjectHandle withHandle);
|
||||
|
||||
|
||||
#ifdef IMAGE3_DEBUG
|
||||
extern void
|
||||
_image3PrintImage(Image3ObjectHandle withHandle);
|
||||
|
||||
#ifdef IMAGE3_UTILITY
|
||||
int
|
||||
_image3WriteData(Image3ObjectHandle withHandle, const char *path);
|
||||
#endif /* IMAGE3_UTILITY */
|
||||
|
||||
#endif /* IMAGE3_DEBUG */
|
||||
|
||||
/*
|
||||
* Prototypes for external functions that must be supplied.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Generate a SHA-1 hash of the supplied buffer.
|
||||
*/
|
||||
extern void
|
||||
image3SHA1Generate(void *dataBuffer, size_t dataSize, void *hashBuffer);
|
||||
|
||||
#ifdef IMAGE3_CREATOR
|
||||
/*
|
||||
* Generate a partial SHA-1 hash of the supplied buffer.
|
||||
*/
|
||||
void
|
||||
image3SHA1Partial(void *dataBuffer, size_t dataSize, void *hashBuffer);
|
||||
#endif /* IMAGE3_CREATOR */
|
||||
|
||||
/*
|
||||
* Sign a hash.
|
||||
*/
|
||||
extern int
|
||||
image3PKISignHash(
|
||||
void *hashBuffer,
|
||||
size_t hashSize,
|
||||
void **resultPointer,
|
||||
size_t *resultSize,
|
||||
void **certBlobPointer,
|
||||
size_t *certBlobSize);
|
||||
|
||||
/*
|
||||
* Verify the signature on a hash.
|
||||
*
|
||||
* Returns:
|
||||
* 0 - image is valid and can be trusted
|
||||
* EPERM - image is valid but cannot be trusted
|
||||
* EINVAL - image is not valid, cannot be trusted
|
||||
*/
|
||||
extern int
|
||||
image3PKIVerifyHash(
|
||||
void *hashBuffer,
|
||||
size_t hashSize,
|
||||
void *signedHashBuffer,
|
||||
size_t signedHashSize,
|
||||
void *certBlobBuffer,
|
||||
size_t certBlobSize,
|
||||
void **certCustomData,
|
||||
size_t *certCustomDataSize);
|
||||
|
||||
/*
|
||||
* Validate an image hash using the ticket database.
|
||||
*
|
||||
* Returns:
|
||||
* 0 - image is valid and can be trusted
|
||||
* EPERM - image is valid but cannot be trusted
|
||||
* EINVAL - image is not valid, cannot be trusted
|
||||
*/
|
||||
extern int
|
||||
image3TicketVerifyHash(
|
||||
void *hashBuffer,
|
||||
size_t hashSize,
|
||||
uint32_t imageType,
|
||||
uint32_t expectedType);
|
||||
|
||||
/*
|
||||
* Decrypt a buffer in-place using AES and a local unit-specific key.
|
||||
*/
|
||||
extern int
|
||||
image3AESDecryptUsingLocalKey(void *buffer, size_t length);
|
||||
|
||||
/*
|
||||
* Encrypt a buffer in-place using AES and a local unit-specific key.
|
||||
*/
|
||||
extern void
|
||||
image3AESEncryptUsingLocalKey(void *buffer, size_t length);
|
||||
|
||||
/*
|
||||
* Memory allocator
|
||||
*/
|
||||
extern void *
|
||||
image3Malloc(size_t size);
|
||||
|
||||
/*
|
||||
* Memory de-allocator
|
||||
*/
|
||||
extern void
|
||||
image3Free(void *ptr, size_t size);
|
||||
|
||||
#endif /* _IMAGE3_H_ */
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2011, 2014 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
#ifndef _IMAGE3_FORMAT_H_
|
||||
#define _IMAGE3_FORMAT_H_
|
||||
|
||||
#include <drivers/sha1.h>
|
||||
|
||||
/*
|
||||
* All structures defined here are on-media formats.
|
||||
*/
|
||||
#pragma pack(push, 1)
|
||||
|
||||
/*
|
||||
* Fixed object header.
|
||||
*/
|
||||
typedef struct _Image3ObjectHeader {
|
||||
/* these fields are unsigned */
|
||||
u_int32_t ihMagic;
|
||||
#define kImage3HeaderMagic 'Img3'
|
||||
u_int32_t ihSkipDistance;
|
||||
u_int32_t ihBufferLength;
|
||||
|
||||
/* fields below are signed */
|
||||
u_int32_t ihSignedLength;
|
||||
u_int32_t ihType;
|
||||
u_int8_t ihBuffer[];
|
||||
} Image3ObjectHeader;
|
||||
|
||||
/*
|
||||
* Generic tag header.
|
||||
*/
|
||||
typedef struct {
|
||||
u_int32_t itTag;
|
||||
u_int32_t itSkipDistance;
|
||||
u_int32_t itBufferLength;
|
||||
u_int8_t itBuffer[];
|
||||
} Image3TagHeader;
|
||||
|
||||
#ifdef IMAGE3_CREATOR
|
||||
/*
|
||||
* Partial hash types.
|
||||
*/
|
||||
typedef struct {
|
||||
/* number of valid bytes in the buffer */
|
||||
u_int32_t masteredReservationLength;
|
||||
u_int32_t masteredSignedLength;
|
||||
u_int8_t sha1_state[CCSHA1_OUTPUT_SIZE];
|
||||
} Image3PartialHash;
|
||||
#endif /* IMAGE3_CREATOR */
|
||||
|
||||
/*
|
||||
* Utility tag types.
|
||||
*/
|
||||
typedef struct {
|
||||
/* number of valid bytes in the buffer */
|
||||
u_int32_t stringLength;
|
||||
char stringBytes[];
|
||||
} Image3TagString;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
u_int32_t u32;
|
||||
int32_t s32;
|
||||
} value;
|
||||
} Image3TagNumber32;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
u_int64_t u64;
|
||||
int64_t s64;
|
||||
} value;
|
||||
} Image3TagNumber64;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
Image3TagNumber32 n32;
|
||||
Image3TagNumber64 n64;
|
||||
} number;
|
||||
} Image3TagNumber;
|
||||
|
||||
#ifdef IMAGE3_CREATOR
|
||||
#define IMAGE_TYPE_EMBEDCERT 'cert' /* ihType of image embedded in leaf cert */
|
||||
#endif /* IMAGE3_CREATOR */
|
||||
|
||||
/*
|
||||
* Defined tags and their datastructures.
|
||||
*/
|
||||
|
||||
#define kImage3TagTypeData 'DATA' /* opaque */
|
||||
#define kImage3TagTypeSignedHash 'SHSH' /* opaque */
|
||||
#define kImage3TagTypeCertificateChain 'CERT' /* opaque */
|
||||
#define kImage3TagTypeVersion 'VERS' /* string */
|
||||
#define kImage3TagTypeSecurityEpoch 'SEPO' /* number */
|
||||
#define kImage3TagTypeSecurityDomain 'SDOM' /* number */
|
||||
#define kImage3TagTypeProductionStatus 'PROD' /* number */
|
||||
#define kImage3TagTypeChipType 'CHIP' /* number */
|
||||
#define kImage3TagTypeBoardType 'BORD' /* number */
|
||||
#define kImage3TagTypeUniqueID 'ECID' /* number */
|
||||
#define kImage3TagTypeRandomPad 'SALT' /* number */
|
||||
#define kImage3TagTypeType 'TYPE' /* number */
|
||||
#define kImage3TagTypeOverride 'OVRD' /* bitmap */
|
||||
#define kImage3TagTypeHardwareEpoch 'CEPO' /* number */
|
||||
#define kImage3TagTypeNonce 'NONC' /* opaque */
|
||||
|
||||
#define kImage3TagTypeKeybag 'KBAG'
|
||||
typedef struct {
|
||||
u_int32_t kbSelector;
|
||||
#define kImage3KeybagSelectorNoKey (0)
|
||||
#define kImage3KeybagSelectorChipUnique (1)
|
||||
#define kImage3KeybagSelectorChipUniqueDev (2)
|
||||
u_int32_t kbKeySize;
|
||||
u_int8_t kbIVBytes[16];
|
||||
u_int8_t kbKeyBytes[32];
|
||||
} Image3TagKBAG;
|
||||
|
||||
#define kImage3SecurityDomainManufacturer 0
|
||||
#define kImage3SecurityDomainDarwin 1
|
||||
#define kImage3SecurityDomainRTXC 3
|
||||
|
||||
#define kImage3SecurityProductionStatus 1
|
||||
|
||||
#define kImage3OverrideProductionMode 1
|
||||
|
||||
/* restore structure packing */
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif /* _IMAGE3_FORMAT_H_ */
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2010 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
#ifndef _IMAGE3_SUPER_BLOCK_H_
|
||||
#define _IMAGE3_SUPER_BLOCK_H_
|
||||
|
||||
/*
|
||||
* All structures defined here are on-media formats.
|
||||
*/
|
||||
#pragma pack(push, 1)
|
||||
|
||||
/*
|
||||
* The I3 layout is described by the superblock, which is located at
|
||||
* kI2SuperblockOffset from the top of the media. The superblock is a write-once
|
||||
* item; it should only be updated when the bootblock code is rewritten, implying
|
||||
* a complete re-initialisation of the media.
|
||||
*
|
||||
* Following the superblock there is a reserved area for boot code, after which
|
||||
* image headers describe individual images.
|
||||
*
|
||||
* 0x0 --------------------
|
||||
*
|
||||
* Image3Superblock
|
||||
* ...
|
||||
* ...
|
||||
* 0x8000 --------------------
|
||||
* Image3Header
|
||||
* ...
|
||||
* Image3Header
|
||||
* ...
|
||||
*
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
u_int32_t isMagic;
|
||||
#define kImage2SuperMagic 0x494d4732 /* "IMG2" */
|
||||
u_int32_t isImageGranule; /* fundamental block size (bytes) */
|
||||
u_int32_t isImageOffset; /* image header offset within granule (image granules) */
|
||||
u_int32_t isBootBlockSize; /* size of the bootblock (image granules) */
|
||||
u_int32_t isImageAvail; /* total granules available for images. */
|
||||
u_int32_t isNvramGranule; /* size of NVRAM blocks (bytes) */
|
||||
u_int32_t isNvramOffset; /* offset to first NVRAM block (nvram granules) */
|
||||
u_int32_t isFlags; /* flags field reserved for future use */
|
||||
u_int32_t isRsvd1; /* reserved 1 for future use */
|
||||
u_int32_t isRsvd2; /* reserved 2 for future use */
|
||||
u_int32_t isRsvd3; /* reserved 3 for future use */
|
||||
u_int32_t isRsvd4; /* reserved 4 for future use */
|
||||
u_int32_t isCheck; /* CRC-32 of header fields preceding this one */
|
||||
} Image3Superblock;
|
||||
|
||||
/* Image types */
|
||||
#define IMAGE_TYPE_DIAG 'diag' // diagnostics
|
||||
#define IMAGE_TYPE_IBOOT_LLB 'illb' // iboot (darwin) first-stage loader
|
||||
#define IMAGE_TYPE_IBOOT 'ibot' // iboot (darwin) loader
|
||||
#define IMAGE_TYPE_DEVTREE 'dtre' // darwin device tree
|
||||
#define IMAGE_TYPE_LOGO 'logo' // boot logo image
|
||||
#define IMAGE_TYPE_RECMODE 'recm' // recovery mode image
|
||||
#define IMAGE_TYPE_NEEDSERVICE 'nsrv' // recovery mode image
|
||||
#define IMAGE_TYPE_BATTERYLOW0 'batl' // battery low image - empty
|
||||
#define IMAGE_TYPE_BATTERYLOW1 'batL' // battery low image - red
|
||||
#define IMAGE_TYPE_BATTERYCHRG 'batC' // battery charge image
|
||||
#define IMAGE_TYPE_ENV 'ienv' // environment vars
|
||||
#define IMAGE_TYPE_TSYS 'tsys' // tsys tester
|
||||
#define IMAGE_TYPE_CHIME 'beep' // boot chime
|
||||
|
||||
/* restore structure packing */
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif /* _IMAGE3_SUPER_BLOCK_H_ */
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2007-2013 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
#include <lib/Image2Format.h>
|
||||
|
||||
/*
|
||||
* image3_process_superblock
|
||||
*
|
||||
* Searches the given bdev looking for image3 images. Returns a count of found
|
||||
* images.
|
||||
*/
|
||||
extern int
|
||||
image3_process_superblock(Image2Superblock *sblock, struct blockdev *bdev, off_t offset, uint32_t imageOptions);
|
||||
|
||||
/*
|
||||
* image3_free_bdev
|
||||
*
|
||||
* Frees resources for any previously found images on the specified bdev.
|
||||
* Useful for starting afresh with a new image superblock.
|
||||
*/
|
||||
extern void
|
||||
image3_free_bdev(struct blockdev *bdev);
|
||||
|
||||
/*
|
||||
* image3_load
|
||||
*
|
||||
* Given an image_info handle and type from a previous image_find, load the image and
|
||||
* return the size and address of the payload (DATA tag).
|
||||
*/
|
||||
extern int
|
||||
image3_load(struct image_info *image, const u_int32_t *types, u_int32_t count, u_int32_t *actual, void **load_addr, size_t *load_len);
|
||||
|
||||
/*
|
||||
* image3_dump_list
|
||||
*
|
||||
* Print the list of images from the currently active bdev, if any.
|
||||
*/
|
||||
extern void
|
||||
image3_dump_list(bool detailed);
|
||||
|
||||
|
||||
/*
|
||||
* image3_find
|
||||
*
|
||||
* Returns the image_info handle to the first image of the specified type
|
||||
* from the currently active bdev, if any.
|
||||
*/
|
||||
extern struct image_info *
|
||||
image3_find(u_int32_t image_type);
|
||||
@@ -0,0 +1,21 @@
|
||||
# Copyright (C) 2007 Apple Inc. All rights reserved.
|
||||
#
|
||||
# This document is the property of Apple Inc.
|
||||
# It is considered confidential and proprietary.
|
||||
#
|
||||
# This document may not be reproduced or transmitted in any form,
|
||||
# in whole or in part, without the express written permission of
|
||||
# Apple Inc.
|
||||
#
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
OPTIONS += WITH_IMAGE3=1
|
||||
|
||||
MODULES += \
|
||||
lib/cksum \
|
||||
drivers/sha1 \
|
||||
lib/image
|
||||
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/Image3.o \
|
||||
$(LOCAL_DIR)/image3_wrapper.o
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
#include <compiler.h>
|
||||
#include <debug.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libDER/libDER_config.h>
|
||||
#include <libDER/asn1Types.h>
|
||||
#include <libDER/DER_Decode.h>
|
||||
#include "image4_partial.h"
|
||||
|
||||
// TODO - libDER/asn1Types.h is missing ASN1_EOC
|
||||
#ifndef ASN1_EOC
|
||||
#define ASN1_EOC 0x00
|
||||
#endif
|
||||
|
||||
static int der_expect(const DERItem *bounds, DERTag tag, DERDecodedInfo *info,
|
||||
bool partial);
|
||||
static int der_restrict(DERItem *bounds, const DERItem *item);
|
||||
static int der_compare_ia5string(const DERItem *item, const char *s);
|
||||
static int der_skip_over(DERItem *bounds, const DERItem *item);
|
||||
static int der_expect_ia5string(DERItem *bounds, const char *s);
|
||||
|
||||
#ifdef TEST
|
||||
static void hexdump(const void *buf, size_t len);
|
||||
#endif
|
||||
|
||||
// Parse a partial buffer enough to identify and get type.
|
||||
int image4_get_partial(const void *buf, size_t buf_bytes,
|
||||
uint32_t *ret_type, uint32_t *ret_size)
|
||||
{
|
||||
DERItem bounds;
|
||||
DERDecodedInfo info;
|
||||
// See sample Image4 header at the top of this file.
|
||||
bounds.data = (DERByte *) buf;
|
||||
bounds.length = buf_bytes;
|
||||
dprintf(DEBUG_SPEW, "image4_get_partial %p,%u\n",
|
||||
bounds.data, (unsigned) bounds.length);
|
||||
|
||||
// Outer SEQUENCE. Allow partial.
|
||||
dprintf(DEBUG_SPEW, "Parse outer SEQUENCE\n");
|
||||
if (der_expect(&bounds, ASN1_CONSTR_SEQUENCE, &info, true) != 0)
|
||||
return -1;
|
||||
// Infer Image4 size from the bounds of the sequence.
|
||||
if (ret_size != NULL) {
|
||||
DERSize offset = info.content.data - bounds.data;
|
||||
if (offset + info.content.length < offset) {
|
||||
dprintf(DEBUG_SPEW, "Sneaky size wraparound %llu\n",
|
||||
(uint64_t) offset + info.content.length);
|
||||
return -1;
|
||||
}
|
||||
*ret_size = offset + info.content.length;
|
||||
}
|
||||
// Update bounds to contents of SEQUENCE.
|
||||
if (der_restrict(&bounds, &info.content) != 0)
|
||||
return -1;
|
||||
|
||||
// IA5String "IMG4". Update bounds to skip over.
|
||||
dprintf(DEBUG_SPEW, "Parse IA5String \"IMG4\"\n");
|
||||
if (der_expect_ia5string(&bounds, "IMG4") != 0)
|
||||
return -1;
|
||||
|
||||
// Inner SEQUENCE. Allow partial.
|
||||
dprintf(DEBUG_SPEW, "Parse inner sequence\n");
|
||||
if (der_expect(&bounds, ASN1_CONSTR_SEQUENCE, &info, true) != 0)
|
||||
return -1;
|
||||
if (der_restrict(&bounds, &info.content) != 0)
|
||||
return -1;
|
||||
|
||||
// IA5String "IM4P". Update bounds to skip over.
|
||||
dprintf(DEBUG_SPEW, "Parse IA5String \"IM4P\"\n");
|
||||
if (der_expect_ia5string(&bounds, "IM4P") != 0)
|
||||
return -1;
|
||||
|
||||
// IA5String "type". We're interested in this one.
|
||||
dprintf(DEBUG_SPEW, "Parse IA5String type\n");
|
||||
if (der_expect(&bounds, ASN1_IA5_STRING, &info, false) != 0)
|
||||
return -1;
|
||||
if (info.content.length != sizeof(*ret_type)) {
|
||||
dprintf(DEBUG_SPEW, "Expected %d byte tag, got %d\n",
|
||||
(int) sizeof(*ret_type), (int) info.content.length);
|
||||
return -1;
|
||||
}
|
||||
if (ret_type != NULL) {
|
||||
uint32_t local_type;
|
||||
memcpy(&local_type, info.content.data, sizeof(local_type));
|
||||
*ret_type = swap32(local_type);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
der_expect(const DERItem *bounds, DERTag tag, DERDecodedInfo *info,
|
||||
bool partial)
|
||||
{
|
||||
DERReturn ret;
|
||||
dprintf(DEBUG_SPEW, "Bounds %p,%u\n",
|
||||
bounds->data, (unsigned) bounds->length);
|
||||
ret = DERDecodeItemPartialBuffer(bounds, info, partial);
|
||||
if (ret != DR_Success) {
|
||||
dprintf(DEBUG_SPEW, "Error decoding DER: %d\n", (int) ret);
|
||||
return ret;
|
||||
} else if (info->tag != tag) {
|
||||
dprintf(DEBUG_SPEW,
|
||||
"Didn't get expected tag 0x%llx, got 0x%llx\n",
|
||||
(uint64_t) tag, (uint64_t) info->tag);
|
||||
return -1;
|
||||
} else {
|
||||
// Got expected tag.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
der_restrict(DERItem *bounds, const DERItem *item)
|
||||
{
|
||||
// Update *bounds to *item, keeping staying within *bounds.
|
||||
RELEASE_ASSERT(item->data >= bounds->data);
|
||||
DERByte *buf_start = bounds->data;
|
||||
DERByte *buf_end = bounds->data + bounds->length;
|
||||
// This should have been guaranteed elsewhere, but worth checking.
|
||||
// Zero length returned *bounds allowed.
|
||||
if ((item->data < buf_start) || (item->data > buf_end)) {
|
||||
dprintf(DEBUG_SPEW, "DERItem.data=%p outside bounds %p,%p\n",
|
||||
item->data, buf_start, buf_end);
|
||||
return -1;
|
||||
}
|
||||
// Set *bounds to *item, then restrict range.
|
||||
bounds->data = item->data;
|
||||
bounds->length = __min((size_t)item->length, (size_t)(buf_end - bounds->data));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
der_compare_ia5string(const DERItem *item, const char *s)
|
||||
{
|
||||
int cmp;
|
||||
size_t len = strlen(s);
|
||||
dprintf(DEBUG_SPEW, "content %p,%u\n", item->data, item->length);
|
||||
if (item->length != len) {
|
||||
dprintf(DEBUG_SPEW, "IA5String expected %s but length %d\n",
|
||||
s, (int) len);
|
||||
return -1;
|
||||
}
|
||||
cmp = memcmp(item->data, s, len);
|
||||
if (cmp != 0) {
|
||||
dprintf(DEBUG_SPEW, "Expected %s, got:\n", s);
|
||||
dhexdump(DEBUG_SPEW, item->data, len);
|
||||
}
|
||||
return cmp;
|
||||
}
|
||||
|
||||
static int
|
||||
der_skip_over(DERItem *bounds, const DERItem *item)
|
||||
{
|
||||
DERSize skip, offset;
|
||||
// Calculate number of bytes to move bounds->data to end of *item.
|
||||
RELEASE_ASSERT(item->data >= bounds->data);
|
||||
offset = item->data - bounds->data;
|
||||
skip = offset + item->length;
|
||||
if ((skip < offset) || (skip > bounds->length)) {
|
||||
dprintf(DEBUG_SPEW, "Skipping over item -> outside bounds\n");
|
||||
return -1;
|
||||
}
|
||||
bounds->data += skip;
|
||||
bounds->length -= skip;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
der_expect_ia5string(DERItem *bounds, const char *s)
|
||||
{
|
||||
// Get IA5String info, compare data, update bounds to skip over.
|
||||
DERDecodedInfo info;
|
||||
if (der_expect(bounds, ASN1_IA5_STRING, &info, false) != 0)
|
||||
return -1;
|
||||
if (der_compare_ia5string(&info.content, s) != 0)
|
||||
return -1;
|
||||
if (der_skip_over(bounds, &info.content) != 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
// Run test with:
|
||||
// cc -Werror -Wall -O -o image4_partial image4_partial.c ../../pki/libDER/DER_Decode.c -DTEST -DDEBUG_LEVEL=30 -I../../../include -I../../pki && ./image4_partial
|
||||
// Try both -m32 and -m64
|
||||
#include <assert.h>
|
||||
|
||||
int main() {
|
||||
static const uint8_t big_img4[] = { // 4GB-1 file
|
||||
0x30, 0x84, 0xff, 0xff, 0xff, 0xf9, // SEQUENCE { 4GB-7
|
||||
0x16, 0x04, 0x49, 0x4d, 0x47, 0x34, // IA5String 'IMG4'
|
||||
0x30, 0x84, 0xff, 0xff, 0xff, 0xed, // SEQUENCE { 4GB-19
|
||||
0x16, 0x04, 0x49, 0x4d, 0x34, 0x50, // IA5String 'IM4P'
|
||||
0x16, 0x04, 0x41, 0x42, 0x43, 0x44, // IA5String 'ABCD'
|
||||
};
|
||||
uint32_t type, size;
|
||||
int ret = image4_get_partial(big_img4, sizeof(big_img4),
|
||||
&type, &size);
|
||||
assert(ret == 0);
|
||||
assert(memcmp(&type, "ABCD", 4) == 0);
|
||||
assert(size == 0xffffffff);
|
||||
printf("Pass\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hexdump(const void *buf, size_t len) {
|
||||
const uint8_t *p = buf;
|
||||
size_t i;
|
||||
for (i = 0; i < len; ++i)
|
||||
printf("[%llu] = 0x%02x '%c'\n", (uint64_t) i, p[i], p[i]);
|
||||
}
|
||||
|
||||
void _panic(const char *func, const char *str, ...) {
|
||||
va_list args;
|
||||
va_start(args, str);
|
||||
printf("\n%s: ", func);
|
||||
vprintf(str, args);
|
||||
printf("\n\n");
|
||||
va_end(args);
|
||||
exit(1);
|
||||
}
|
||||
#endif // defined(TEST)
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2012 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
#ifndef IMAGE4_PARTIAL_H
|
||||
#define IMAGE4_PARTIAL_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* Maximum number of bytes needed to ID an Image4 file.
|
||||
*
|
||||
* Image4 header for a large (but <4GB) file contains:
|
||||
*
|
||||
* SEQUENCE { 30 84 xx xx xx xx
|
||||
* IA5String 'IMG4' 16 04 49 4d 47 34
|
||||
* SEQUENCE { 30 84 yy yy yy yy
|
||||
* IA5String 'IM4P' 16 04 53 45 50 4f
|
||||
* IA5String 'abcd' 16 04 aa bb cc dd
|
||||
*/
|
||||
#define IMAGE4_ID_BYTES 30
|
||||
|
||||
// Parse a partial buffer enough to identify and get type.
|
||||
// Return pointers can be NULL if not needed.
|
||||
int image4_get_partial(const void *buf, size_t buf_bytes,
|
||||
uint32_t *ret_type, uint32_t *ret_size);
|
||||
|
||||
#endif // defined(IMAGE4_PARTIAL_H)
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2013 Apple Inc. All rights reserved.
|
||||
*
|
||||
* This document is the property of Apple Inc.
|
||||
* It is considered confidential and proprietary.
|
||||
*
|
||||
* This document may not be reproduced or transmitted in any form,
|
||||
* in whole or in part, without the express written permission of
|
||||
* Apple Inc.
|
||||
*/
|
||||
|
||||
#ifndef IMAGE4_WRAPPER_H
|
||||
|
||||
/*
|
||||
* image4_process_superblock
|
||||
*
|
||||
* Searches the given bdev looking for image4 images. Returns a count of found
|
||||
* images.
|
||||
*/
|
||||
extern int
|
||||
image4_process_superblock(void *sblock, struct blockdev *bdev, off_t offset, uint32_t imageOptions);
|
||||
|
||||
/*
|
||||
* image4_free_bdev
|
||||
*
|
||||
* Frees resources for any previously found images on the specified bdev.
|
||||
* Useful for starting afresh with a new image superblock.
|
||||
*/
|
||||
extern void
|
||||
image4_free_bdev(struct blockdev *bdev);
|
||||
|
||||
/*
|
||||
* image4_load
|
||||
*
|
||||
* Given an image_info handle and type from a previous image_find, load the image and
|
||||
* return the size and address of the payload (DATA tag).
|
||||
*/
|
||||
extern int
|
||||
image4_load(struct image_info *image, const u_int32_t *types, u_int32_t count, u_int32_t *actual, void **load_addr, size_t *load_len);
|
||||
|
||||
/*
|
||||
* image4_dump_list
|
||||
*
|
||||
* Print the list of images from the currently active bdev, if any.
|
||||
*/
|
||||
extern void
|
||||
image4_dump_list(bool detailed);
|
||||
|
||||
|
||||
/*
|
||||
* image4_find
|
||||
*
|
||||
* Returns the image_info handle to the first image of the specified type
|
||||
* from the currently active bdev, if any.
|
||||
*/
|
||||
extern struct image_info *
|
||||
image4_find(u_int32_t image_type);
|
||||
|
||||
#endif // defined(IMAGE4_WRAPPER_H)
|
||||
@@ -0,0 +1,40 @@
|
||||
# Copyright (C) 2012, 2014 Apple Inc. All rights reserved.
|
||||
#
|
||||
# This document is the property of Apple Inc.
|
||||
# It is considered confidential and proprietary.
|
||||
#
|
||||
# This document may not be reproduced or transmitted in any form,
|
||||
# in whole or in part, without the express written permission of
|
||||
# Apple Inc.
|
||||
#
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
IMAGE_FORMAT := 4
|
||||
|
||||
# Hack to link against SDKROOT or PLATFORMROOT until somebody figures
|
||||
# out why libImg4Decode is bouncing between locations.
|
||||
IMG4_IN_SDKROOT := $(realpath $(SDKROOT)/usr/local/lib/libImg4Decode_os.a)
|
||||
IMG4_IN_PLATFORMROOT := $(realpath $(PLATFORMROOT)/usr/local/lib/libImg4Decode_os.a)
|
||||
ifneq ($(IMG4_IN_SDKROOT),)
|
||||
EXTERNAL_STATICLIBS += $(IMG4_IN_SDKROOT)
|
||||
EXTERNAL_INCLUDES += $(SDKROOT)/usr/local/include/
|
||||
else
|
||||
ifneq ($(IMG4_IN_PLATFORMROOT),)
|
||||
EXTERNAL_STATICLIBS += $(IMG4_IN_PLATFORMROOT)
|
||||
EXTERNAL_INCLUDES += $(PLATFORMROOT)/usr/local/include/
|
||||
else
|
||||
$(error libImg4Decode.a not found in SDKROOT or PLATFORMROOT)
|
||||
endif
|
||||
endif
|
||||
|
||||
OPTIONS += WITH_IMAGE4=1
|
||||
|
||||
MODULES += \
|
||||
drivers/sha1 \
|
||||
lib/cksum \
|
||||
lib/image \
|
||||
lib/pki
|
||||
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/image4_partial.o \
|
||||
$(LOCAL_DIR)/image4_wrapper.o
|
||||
@@ -0,0 +1,14 @@
|
||||
# Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
|
||||
#
|
||||
# This document is the property of Apple Computer, Inc.
|
||||
# It is considered confidential and proprietary.
|
||||
#
|
||||
# This document may not be reproduced or transmitted in any form,
|
||||
# in whole or in part, without the express written permission of
|
||||
# Apple Computer, Inc.
|
||||
#
|
||||
LOCAL_DIR := $(GET_LOCAL_DIR)
|
||||
|
||||
ALL_OBJS += \
|
||||
$(LOCAL_DIR)/image.o \
|
||||
$(LOCAL_DIR)/debug.o
|
||||
Reference in new issue
Block a user