Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions examples/htool.c
Original file line number Diff line number Diff line change
Expand Up @@ -1319,6 +1319,15 @@ static const struct htool_cmd CMDS[] = {
{HTOOL_POSITIONAL, .name = "source-file"}, {}},
.func = htool_payload_info_nonstatic,
},
{
.verbs = (const char*[]){"payload", "info", "target_watchdog", NULL},
.desc = "Print the target watchdog config of a Titan image or image "
"descriptor as key=value lines.",
.params =
(const struct htool_param[]){
{HTOOL_POSITIONAL, .name = "source-file"}, {}},
.func = htool_payload_info_target_watchdog,
},
{
.verbs = (const char*[]){"payload", "info", NULL},
.desc = "Display payload info for a Titan image.",
Expand Down
28 changes: 28 additions & 0 deletions examples/htool_payload.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,34 @@ int htool_payload_info_all(const struct htool_invocation* inv) {
return htool_payload_image_close(&img);
}

int htool_payload_info_target_watchdog(const struct htool_invocation* inv) {
struct htool_payload_image img;
if (htool_payload_image_open(inv, &img) != 0) {
return -1;
}

struct target_watchdog_config config;
enum image_blob_status status =
libhoth_payload_target_watchdog_config(img.image, img.size, &config);
int rv = htool_payload_image_close(&img);
if (status == IMAGE_BLOB_NOT_FOUND) {
fprintf(stderr, "Image has no target watchdog (TWCH) blob\n");
Comment thread
rkr35 marked this conversation as resolved.
return -1;
}
if (status != IMAGE_BLOB_OK) {
fprintf(stderr, "Invalid target watchdog config in image: %s\n",
libhoth_image_blob_status_string(status));
return -1;
}

printf("initial_delay_seconds=%" PRIu32 "\n", config.initial_delay_seconds);
printf("watchdog_timeout_seconds=%" PRIu32 "\n",
config.watchdog_timeout_seconds);
printf("hold_in_reset_microseconds=%" PRIu32 "\n",
config.hold_in_reset_microseconds);
return rv;
}

int htool_payload_info_nonstatic(const struct htool_invocation* inv) {
struct htool_payload_image img;
if (htool_payload_image_open(inv, &img) != 0) {
Expand Down
1 change: 1 addition & 0 deletions examples/htool_payload.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ int htool_payload_status(const struct htool_invocation* inv);
int htool_payload_info(const struct htool_invocation* inv);
int htool_payload_info_all(const struct htool_invocation* inv);
int htool_payload_info_nonstatic(const struct htool_invocation* inv);
int htool_payload_info_target_watchdog(const struct htool_invocation* inv);
int htool_get_compiled_payload_mauv(const struct htool_invocation* inv);
int htool_get_effective_payload_mauv(const struct htool_invocation* inv);

Expand Down
107 changes: 106 additions & 1 deletion protocol/payload_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const struct image_descriptor* libhoth_find_image_descriptor(
struct image_descriptor* img_dsc =
(struct image_descriptor*)(image + off);

if (img_dsc->descriptor_area_size + off > len) {
if (img_dsc->descriptor_area_size > len - off) {
// Image descriptor is clipped
return NULL;
}
Expand Down Expand Up @@ -130,3 +130,108 @@ bool libhoth_payload_info_all(const uint8_t* image, size_t len,

return true;
}

#define TITAN_IMAGE_DESCRIPTOR_MAX_MAJOR_VERSION 1
#define TITAN_IMAGE_DESCRIPTOR_BLOB_MAGIC 0x424f4c42 // "BLOB"
#define IMAGE_BLOB_ALIGNMENT 4
#define IMAGE_BLOB_TYPE_TARGET_WATCHDOG 0x48435754 // "TWCH"

struct image_blob_header {
uint32_t blob_type;
// Size of the blob in bytes. Does NOT include `sizeof(image_blob_header)`.
uint32_t payload_size;
Comment thread
rkr35 marked this conversation as resolved.
} __attribute__((__packed__));

static uint32_t blob_list_magic_offset(const struct image_descriptor* descr) {
uint32_t offset = sizeof(struct image_descriptor) +
descr->region_count * sizeof(struct image_region) +
sizeof(struct hash_sha256);
if (descr->denylist_size != 0) {
offset += sizeof(uint32_t) +
descr->denylist_size * sizeof(struct payload_version);
}
return offset;
}

const char* libhoth_image_blob_status_string(enum image_blob_status status) {
switch (status) {
case IMAGE_BLOB_OK:
return "ok";
case IMAGE_BLOB_NOT_FOUND:
return "blob not found";
case IMAGE_BLOB_NO_DESCRIPTOR:
return "no image descriptor found";
case IMAGE_BLOB_UNSUPPORTED_DESCRIPTOR:
return "unsupported image descriptor version or hash type";
case IMAGE_BLOB_LIST_INVALID_MAGIC:
return "invalid blob list magic";
case IMAGE_BLOB_LIST_MALFORMED:
return "malformed blob list";
case IMAGE_BLOB_DUPLICATE:
return "duplicate blob";
case IMAGE_BLOB_INVALID_SIZE:
return "invalid blob payload size";
}
return "unknown error";
}

enum image_blob_status libhoth_payload_target_watchdog_config(
const uint8_t* image, size_t len, struct target_watchdog_config* config) {
const struct image_descriptor* descr =
libhoth_find_image_descriptor(image, len);
if (descr == NULL) {
return IMAGE_BLOB_NO_DESCRIPTOR;
}
// The blob list's location depends on the descriptor's layout.
if (descr->descriptor_major > TITAN_IMAGE_DESCRIPTOR_MAX_MAJOR_VERSION ||
descr->hash_type != HASH_SHA2_256) {
return IMAGE_BLOB_UNSUPPORTED_DESCRIPTOR;
}
if (descr->blob_size == 0) {
return IMAGE_BLOB_NOT_FOUND;
}

// libhoth_find_image_descriptor() guarantees that the whole descriptor area
// is inside `image`, so bounding the list by it keeps every read in bounds.
const uint8_t* descr_bytes = (const uint8_t*)descr;
uint64_t magic_offset = blob_list_magic_offset(descr);
uint64_t list_end = magic_offset + sizeof(uint32_t) + descr->blob_size;
if (list_end > descr->descriptor_area_size) {
return IMAGE_BLOB_LIST_MALFORMED;
}
uint32_t magic;
memcpy(&magic, descr_bytes + magic_offset, sizeof(magic));
if (magic != TITAN_IMAGE_DESCRIPTOR_BLOB_MAGIC) {
return IMAGE_BLOB_LIST_INVALID_MAGIC;
}

bool found = false;
uint64_t offset = magic_offset + sizeof(magic);
while (offset < list_end) {
struct image_blob_header header;
if (list_end - offset < sizeof(header)) {
return IMAGE_BLOB_LIST_MALFORMED;
}
memcpy(&header, descr_bytes + offset, sizeof(header));
offset += sizeof(header);
if (header.payload_size > list_end - offset) {
return IMAGE_BLOB_LIST_MALFORMED;
}

if (header.blob_type == IMAGE_BLOB_TYPE_TARGET_WATCHDOG) {
if (found) {
return IMAGE_BLOB_DUPLICATE;
}
if (header.payload_size != sizeof(*config)) {
return IMAGE_BLOB_INVALID_SIZE;
}
memcpy(config, descr_bytes + offset, sizeof(*config));
found = true;
}

offset += header.payload_size;
offset = (offset + IMAGE_BLOB_ALIGNMENT - 1) / IMAGE_BLOB_ALIGNMENT *
IMAGE_BLOB_ALIGNMENT;
}
return found ? IMAGE_BLOB_OK : IMAGE_BLOB_NOT_FOUND;
}
25 changes: 24 additions & 1 deletion protocol/payload_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ struct image_descriptor {
/* image_type enum { DEV, PROD, BREAKOUT, UNSIGNED_INTEGRITY} */
uint8_t image_type;

uint8_t reserved_3;
uint8_t denylist_size;

/* hash_type enum { NONE, SHA2_224, SHA2_256, ...} */
uint8_t hash_type;
Expand Down Expand Up @@ -186,6 +186,29 @@ bool libhoth_payload_info(const uint8_t* image, size_t len,
bool libhoth_payload_info_all(const uint8_t* image, size_t len,
struct payload_info_all* info_all);

enum image_blob_status {
IMAGE_BLOB_OK = 0,
IMAGE_BLOB_NOT_FOUND,
IMAGE_BLOB_NO_DESCRIPTOR,
IMAGE_BLOB_UNSUPPORTED_DESCRIPTOR,
IMAGE_BLOB_LIST_INVALID_MAGIC,
// The blob list overruns the descriptor area, or an entry overruns the list.
IMAGE_BLOB_LIST_MALFORMED,
IMAGE_BLOB_DUPLICATE,
IMAGE_BLOB_INVALID_SIZE,
};

const char* libhoth_image_blob_status_string(enum image_blob_status status);

struct target_watchdog_config {
uint32_t initial_delay_seconds;
uint32_t watchdog_timeout_seconds;
uint32_t hold_in_reset_microseconds;
} __attribute__((__packed__));

enum image_blob_status libhoth_payload_target_watchdog_config(
const uint8_t* image, size_t len, struct target_watchdog_config* config);

#ifdef __cplusplus
}
#endif
Expand Down
Loading
Loading