Skip to content

Commit ded0849

Browse files
stevenportleycjevans-google
authored andcommitted
Add payload inspection to htool/libhoth
1 parent f416109 commit ded0849

File tree

13 files changed

+466
-22
lines changed

13 files changed

+466
-22
lines changed

examples/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ cc_binary(
7171
"//protocol:authz_record",
7272
"//protocol:host_cmd",
7373
"//protocol:rot_firmware_version",
74+
"//protocol:payload_info",
7475
"//protocol:payload_status",
7576
"//protocol:panic",
7677
"//protocol:payload_update",

examples/htool.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,14 @@ static const struct htool_cmd CMDS[] = {
764764
{HTOOL_POSITIONAL, .name = "source-file"}, {}},
765765
.func = htool_payload_update,
766766
},
767+
{
768+
.verbs = (const char*[]){"payload", "info", NULL},
769+
.desc = "Display payload info for a Titan image.",
770+
.params =
771+
(const struct htool_param[]){
772+
{HTOOL_POSITIONAL, .name = "source-file"}, {}},
773+
.func = htool_payload_info,
774+
},
767775
{.verbs = (const char*[]){"flash_spi_info", NULL},
768776
.desc = "Get SPI NOR flash info.",
769777
.params = (const struct htool_param[]){{}},

examples/htool_payload.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,19 @@
1414

1515
#include "htool_payload.h"
1616

17+
#include <errno.h>
18+
#include <fcntl.h>
1719
#include <stdio.h>
1820
#include <stdlib.h>
21+
#include <string.h>
22+
#include <sys/mman.h>
23+
#include <sys/stat.h>
24+
#include <sys/types.h>
25+
#include <unistd.h>
1926

2027
#include "host_commands.h"
2128
#include "htool.h"
29+
#include "protocol/payload_info.h"
2230
#include "protocol/payload_status.h"
2331

2432
int htool_payload_status() {
@@ -68,3 +76,69 @@ int htool_payload_status() {
6876
}
6977
return 0;
7078
}
79+
80+
int htool_payload_info(const struct htool_invocation* inv) {
81+
struct libhoth_device* dev = htool_libhoth_device();
82+
if (!dev) {
83+
return -1;
84+
}
85+
86+
const char* image_file;
87+
if (htool_get_param_string(inv, "source-file", &image_file) != 0) {
88+
return -1;
89+
}
90+
91+
int fd = open(image_file, O_RDONLY, 0);
92+
if (fd == -1) {
93+
fprintf(stderr, "Error opening file %s: %s\n", image_file, strerror(errno));
94+
return -1;
95+
}
96+
struct stat statbuf;
97+
if (fstat(fd, &statbuf)) {
98+
fprintf(stderr, "fstat error: %s\n", strerror(errno));
99+
goto cleanup2;
100+
}
101+
if (statbuf.st_size > SIZE_MAX) {
102+
fprintf(stderr, "file too large\n");
103+
goto cleanup2;
104+
}
105+
106+
uint8_t* image = mmap(NULL, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
107+
if (image == MAP_FAILED) {
108+
fprintf(stderr, "mmap error: %s\n", strerror(errno));
109+
goto cleanup2;
110+
}
111+
112+
struct payload_info info;
113+
if (!libhoth_payload_info(image, statbuf.st_size, &info)) {
114+
fprintf(stderr, "Failed to parse payload image. Is this a titan image?\n");
115+
goto cleanup;
116+
}
117+
118+
printf("Payload Info:\n");
119+
printf(" name: %-32s\n", info.image_name);
120+
printf(" family: %u\n", info.image_family);
121+
printf(" version: %u.%u.%u.%u\n", info.image_version.major,
122+
info.image_version.minor, info.image_version.point,
123+
info.image_version.subpoint);
124+
printf(" type: %u\n", info.image_type);
125+
printf(" hash: ");
126+
for (int i = 0; i < sizeof(info.image_hash); i++) {
127+
printf("%02x", info.image_hash[i]);
128+
}
129+
printf("\n");
130+
131+
cleanup:
132+
if(munmap(image, statbuf.st_size) != 0) {
133+
fprintf(stderr, "munmap error: %s\n", strerror(errno));
134+
return -1;
135+
}
136+
137+
cleanup2:
138+
if (close(fd) != 0) {
139+
fprintf(stderr, "close error: %s\n", strerror(errno));
140+
return -1;
141+
}
142+
143+
return 0;
144+
}

examples/htool_payload.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,15 @@
1717

1818
#include <stdint.h>
1919

20+
#include "htool.h"
21+
#include "htool_cmd.h"
22+
2023
#ifdef __cplusplus
2124
extern "C" {
2225
#endif
2326

2427
int htool_payload_status();
28+
int htool_payload_info(const struct htool_invocation* inv);
2529

2630
#ifdef __cplusplus
2731
}

protocol/BUILD

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ cc_library(
8585
deps = [
8686
"//transports:libhoth_device",
8787
":host_cmd",
88+
":payload_info",
8889
],
8990
)
9091

@@ -231,7 +232,6 @@ cc_library(
231232
],
232233
)
233234

234-
235235
cc_test(
236236
name = "spi_proxy_test",
237237
srcs = ["spi_proxy_test.cc"],
@@ -243,3 +243,22 @@ cc_test(
243243
":spi_proxy",
244244
],
245245
)
246+
247+
cc_library(
248+
name = "payload_info",
249+
hdrs = ["payload_info.h"],
250+
srcs = ["payload_info.c"],
251+
)
252+
253+
cc_test(
254+
name = "payload_info_test",
255+
srcs = ["payload_info_test.cc"],
256+
deps = [
257+
"@googletest//:gtest",
258+
"@googletest//:gtest_main",
259+
":payload_info",
260+
],
261+
data = [
262+
"//protocol/test:test_data",
263+
],
264+
)

protocol/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ protocol_srcs = [
1111
'authz_record.c',
1212
'progress.c',
1313
'spi_proxy.c',
14+
'payload_info.c',
1415
]
1516

1617
incdir = include_directories('..')

protocol/payload_info.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "payload_info.h"
16+
17+
#include <string.h>
18+
19+
const struct image_descriptor* libhoth_find_image_descriptor(const uint8_t* image,
20+
size_t len) {
21+
for (size_t off = 0; off + sizeof(struct image_descriptor) - 1 < len;
22+
off += TITAN_IMAGE_DESCRIPTOR_ALIGNMENT) {
23+
int64_t magic_candidate;
24+
memcpy(&magic_candidate, image + off, sizeof(magic_candidate));
25+
if (magic_candidate == TITAN_IMAGE_DESCRIPTOR_MAGIC) {
26+
struct image_descriptor* img_dsc =
27+
(struct image_descriptor*)(image + off);
28+
29+
if(img_dsc->descriptor_area_size + off > len) {
30+
// Image descriptor is clipped
31+
return NULL;
32+
}
33+
34+
return img_dsc;
35+
}
36+
}
37+
return NULL;
38+
}
39+
40+
bool libhoth_payload_info(const uint8_t* image, size_t len,
41+
struct payload_info* payload_info) {
42+
const struct image_descriptor* descr = libhoth_find_image_descriptor(image, len);
43+
if (descr == NULL) {
44+
return false;
45+
}
46+
47+
memcpy(payload_info->image_name, descr->image_name,
48+
sizeof(payload_info->image_name));
49+
payload_info->image_name[sizeof(payload_info->image_name)-1] = 0;
50+
51+
payload_info->image_family = descr->image_family;
52+
payload_info->image_version.major = descr->image_major;
53+
payload_info->image_version.minor = descr->image_minor;
54+
payload_info->image_version.point = descr->image_point;
55+
payload_info->image_version.subpoint = descr->image_subpoint;
56+
payload_info->image_type = descr->image_type;
57+
58+
if (descr->hash_type != HASH_SHA2_256) {
59+
memset(payload_info->image_hash, 0, sizeof(payload_info->image_hash));
60+
} else {
61+
uint32_t region_size = descr->region_count * sizeof(struct image_region);
62+
struct hash_sha256* hash =
63+
(struct hash_sha256*)((uint8_t*)&descr->image_regions + region_size);
64+
memcpy(payload_info->image_hash, hash->hash, sizeof(hash->hash));
65+
}
66+
67+
return true;
68+
}

0 commit comments

Comments
 (0)