xref: /aosp_15_r20/external/vboot_reference/utility/load_kernel_test.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
1 /* Copyright 2011 The ChromiumOS Authors
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  *
5  * Routines for verifying a file's signature. Useful in testing the core
6  * RSA verification implementation.
7  */
8 
9 #include <stdio.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12 
13 #include "2api.h"
14 #include "2common.h"
15 #include "2misc.h"
16 #include "2sysincludes.h"
17 #include "host_common.h"
18 
19 #define LBA_BYTES 512
20 #define KERNEL_BUFFER_SIZE 0xA00000
21 
22 static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE];
23 static struct vb2_context *ctx;
24 static struct vb2_shared_data *sd;
25 
26 /* Global variables for stub functions */
27 static struct vb2_kernel_params lkp;
28 static struct vb2_disk_info disk_info;
29 static FILE *image_file = NULL;
30 
31 
32 /* Boot device stub implementations to read from the image file */
VbExDiskRead(vb2ex_disk_handle_t handle,uint64_t lba_start,uint64_t lba_count,void * buffer)33 vb2_error_t VbExDiskRead(vb2ex_disk_handle_t handle, uint64_t lba_start,
34 			 uint64_t lba_count, void *buffer)
35 {
36 	printf("Read(%" PRIu64 ", %" PRIu64 ")\n", lba_start, lba_count);
37 
38 	if (lba_start >= disk_info.streaming_lba_count ||
39 	    lba_start + lba_count > disk_info.streaming_lba_count) {
40 		fprintf(stderr,
41 			"Read overrun: %" PRIu64 " + %" PRIu64
42 			" > %" PRIu64 "\n", lba_start,
43 			lba_count, disk_info.streaming_lba_count);
44 		return 1;
45 	}
46 
47 	if (0 != fseek(image_file, lba_start * disk_info.bytes_per_lba,
48 		       SEEK_SET) ||
49 	    1 != fread(buffer, lba_count * disk_info.bytes_per_lba, 1,
50 		       image_file)) {
51 		fprintf(stderr, "Read error.");
52 		return 1;
53 	}
54 	return VB2_SUCCESS;
55 }
56 
57 
VbExDiskWrite(vb2ex_disk_handle_t handle,uint64_t lba_start,uint64_t lba_count,const void * buffer)58 vb2_error_t VbExDiskWrite(vb2ex_disk_handle_t handle, uint64_t lba_start,
59 			  uint64_t lba_count, const void *buffer)
60 {
61 	printf("Write(%" PRIu64 ", %" PRIu64 ")\n", lba_start, lba_count);
62 
63 	if (lba_start >= disk_info.streaming_lba_count ||
64 	    lba_start + lba_count > disk_info.streaming_lba_count) {
65 		fprintf(stderr,
66 			"Read overrun: %" PRIu64 " + %" PRIu64
67 			" > %" PRIu64 "\n", lba_start, lba_count,
68 			disk_info.streaming_lba_count);
69 		return 1;
70 	}
71 
72 	/* TODO: enable writes, once we're sure it won't trash
73 	   our example file */
74 	return VB2_SUCCESS;
75 
76 	fseek(image_file, lba_start * disk_info.bytes_per_lba, SEEK_SET);
77 	if (1 != fwrite(buffer, lba_count * disk_info.bytes_per_lba, 1,
78 			image_file)) {
79 		fprintf(stderr, "Read error.");
80 		return 1;
81 	}
82 	return VB2_SUCCESS;
83 }
84 
85 
86 #define BOOT_FLAG_DEVELOPER (1 << 0)
87 #define BOOT_FLAG_RECOVERY (1 << 1)
88 
89 /* Main routine */
main(int argc,char * argv[])90 int main(int argc, char* argv[])
91 {
92 	const char* image_name;
93 	uint64_t key_size = 0;
94 	struct vb2_packed_key *key_blob = NULL;
95 	struct vb2_gbb_header* gbb;
96 	vb2_error_t rv;
97 	int c, argsleft;
98 	int errorcnt = 0;
99 	char *e = 0;
100 
101 	memset(&lkp, 0, sizeof(lkp));
102 	disk_info.bytes_per_lba = LBA_BYTES;
103 	int boot_flags = BOOT_FLAG_RECOVERY;
104 
105 	/* Parse options */
106 	opterr = 0;
107 	while ((c = getopt(argc, argv, ":b:")) != -1) {
108 		switch (c) {
109 		case 'b':
110 			boot_flags = strtoull(optarg, &e, 0);
111 			if (!*optarg || (e && *e)) {
112 				fprintf(stderr,
113 					"Invalid argument to -%c: \"%s\"\n",
114 					c, optarg);
115 				errorcnt++;
116 			}
117 			break;
118 		case '?':
119 			fprintf(stderr, "Unrecognized switch: -%c\n", optopt);
120 			errorcnt++;
121 			break;
122 		case ':':
123 			fprintf(stderr, "Missing argument to -%c\n", optopt);
124 			errorcnt++;
125 			break;
126 		default:
127 			errorcnt++;
128 			break;
129 		}
130 	}
131 
132 	/* Update argc */
133 	argsleft = argc - optind;
134 
135 	if (errorcnt || !argsleft) {
136 		fprintf(stderr,
137 			"usage: %s [options] <drive_image> [<sign_key>]\n",
138 			argv[0]);
139 		fprintf(stderr, "\noptions:\n");
140 		/* These cases are because uint64_t isn't necessarily the same
141 		   as ULL. */
142 		fprintf(stderr, "  -b NUM     boot flag bits (default %d):\n",
143 			BOOT_FLAG_RECOVERY);
144 		fprintf(stderr, "               %d = developer mode on\n",
145 			BOOT_FLAG_DEVELOPER);
146 		fprintf(stderr, "               %d = recovery mode on\n",
147 			BOOT_FLAG_RECOVERY);
148 		return 1;
149 	}
150 
151 	image_name = argv[optind];
152 
153 	/* Read header signing key blob */
154 	if (argsleft > 1) {
155 		key_blob = (struct vb2_packed_key *)
156 			ReadFile(argv[optind+1], &key_size);
157 		if (!key_blob) {
158 			fprintf(stderr, "Unable to read key file %s\n",
159 				argv[optind+1]);
160 			return 1;
161 		}
162 		printf("Read %" PRIu64 " bytes of key from %s\n", key_size,
163 		       argv[optind+1]);
164 		if (key_size > 16*1024*1024) {
165 			fprintf(stderr, "Key blob size=%" PRIu64
166 				" is ridiculous.\n", key_size);
167 			free(key_blob);
168 			return 1;
169 		}
170 	}
171 
172 	/* Initialize the GBB */
173 	uint32_t gbb_size = sizeof(struct vb2_gbb_header) + key_size;
174 	gbb = (struct vb2_gbb_header*)malloc(gbb_size);
175 	memset(gbb, 0, gbb_size);
176 	memcpy(gbb->signature, VB2_GBB_SIGNATURE, VB2_GBB_SIGNATURE_SIZE);
177 	gbb->major_version = VB2_GBB_MAJOR_VER;
178 	gbb->minor_version = VB2_GBB_MINOR_VER;
179 	gbb->header_size = sizeof(struct vb2_gbb_header);
180 	/* Fill in the given key, if any, for both root and recovery */
181 	if (key_blob) {
182 		gbb->rootkey_offset = gbb->header_size;
183 		gbb->rootkey_size = key_size;
184 		memcpy((uint8_t*)gbb + gbb->rootkey_offset, key_blob, key_size);
185 
186 		gbb->recovery_key_offset = gbb->rootkey_offset;
187 		gbb->recovery_key_size = key_size;
188 	}
189 
190 	printf("bootflags = %d\n", boot_flags);
191 
192 	/* Get image size */
193 	printf("Reading from image: %s\n", image_name);
194 	image_file = fopen(image_name, "rb");
195 	if (!image_file) {
196 		fprintf(stderr, "Unable to open image file %s\n", image_name);
197 		return 1;
198 	}
199 	fseek(image_file, 0, SEEK_END);
200 	disk_info.streaming_lba_count = (ftell(image_file) / LBA_BYTES);
201 	disk_info.lba_count = disk_info.streaming_lba_count;
202 	rewind(image_file);
203 	printf("Streaming LBA count: %" PRIu64 "\n",
204 	       disk_info.streaming_lba_count);
205 
206 	/* Allocate a buffer for the kernel */
207 	lkp.kernel_buffer = malloc(KERNEL_BUFFER_SIZE);
208 	if (!lkp.kernel_buffer) {
209 		fprintf(stderr, "Unable to allocate kernel buffer.\n");
210 		return 1;
211 	}
212 	lkp.kernel_buffer_size = KERNEL_BUFFER_SIZE;
213 
214 	/* Set up vboot context. */
215 	if (vb2api_init(&workbuf, sizeof(workbuf), &ctx)) {
216 		fprintf(stderr, "Can't initialize workbuf\n");
217 		return 1;
218 	}
219 	sd = vb2_get_sd(ctx);
220 
221 	/* Copy kernel subkey to workbuf, if any */
222 	if (key_blob) {
223 		struct vb2_workbuf wb;
224 		struct vb2_packed_key *dst;
225 		uint32_t kernkey_size =
226 			key_blob->key_offset + key_blob->key_size;
227 		vb2_workbuf_from_ctx(ctx, &wb);
228 		dst = vb2_workbuf_alloc(&wb, kernkey_size);
229 		memcpy(dst, key_blob, kernkey_size);
230 		vb2_set_workbuf_used(ctx, vb2_offset_of(sd, wb.buf));
231 		sd->kernel_key_offset = vb2_offset_of(sd, dst);
232 		sd->kernel_key_size = kernkey_size;
233 	}
234 
235 	/* Free the key blob, now that we're done with it */
236 	free(key_blob);
237 
238 	/* No need to initialize ctx->nvdata[]; defaults are fine */
239 	/* TODO(chromium:441893): support dev-mode flag and external gpt flag */
240 	if (boot_flags & BOOT_FLAG_RECOVERY)
241 		ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
242 	if (boot_flags & BOOT_FLAG_DEVELOPER)
243 		ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
244 
245 	/* Call vb2api_load_kernel() */
246 	rv = vb2api_load_kernel(ctx, &lkp, &disk_info);
247 	printf("vb2api_load_kernel() returned %d\n", rv);
248 
249 	if (VB2_SUCCESS == rv) {
250 		printf("Partition number:   %u\n", lkp.partition_number);
251 		printf("Bootloader offset: %" PRIu64 "\n",
252 		       lkp.bootloader_offset);
253 		printf("Bootloader size:    %u\n", lkp.bootloader_size);
254 		printf("Partition guid:	    "
255 		       "%02x%02x%02x%02x-%02x%02x-%02x%02x"
256 		       "-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
257 		       lkp.partition_guid[3],
258 		       lkp.partition_guid[2],
259 		       lkp.partition_guid[1],
260 		       lkp.partition_guid[0],
261 		       lkp.partition_guid[5],
262 		       lkp.partition_guid[4],
263 		       lkp.partition_guid[7],
264 		       lkp.partition_guid[6],
265 		       lkp.partition_guid[8],
266 		       lkp.partition_guid[9],
267 		       lkp.partition_guid[10],
268 		       lkp.partition_guid[11],
269 		       lkp.partition_guid[12],
270 		       lkp.partition_guid[13],
271 		       lkp.partition_guid[14],
272 		       lkp.partition_guid[15]);
273 	}
274 
275 	fclose(image_file);
276 	free(lkp.kernel_buffer);
277 	return rv != VB2_SUCCESS;
278 }
279