1 /* Copyright 2015 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 * Exports a vmlinuz from a kernel partition in memory.
6 */
7
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include "2common.h"
12 #include "2struct.h"
13 #include "vboot_host.h"
14 #include "vboot_struct.h"
15
ExtractVmlinuz(void * kpart_data,size_t kpart_size,void ** vmlinuz_out,size_t * vmlinuz_size)16 int ExtractVmlinuz(void *kpart_data, size_t kpart_size,
17 void **vmlinuz_out, size_t *vmlinuz_size) {
18 size_t now = 0;
19 struct vb2_kernel_preamble *preamble = NULL;
20 uint8_t *kblob_data = NULL;
21 uint32_t kblob_size = 0;
22 uint32_t vmlinuz_header_size = 0;
23 uint64_t vmlinuz_header_address = 0;
24 uint64_t vmlinuz_header_offset = 0;
25 void *vmlinuz = NULL;
26
27 struct vb2_keyblock *keyblock = (struct vb2_keyblock *)kpart_data;
28 now += keyblock->keyblock_size;
29 if (now > kpart_size)
30 return 1;
31
32 preamble = (struct vb2_kernel_preamble *)(kpart_data + now);
33 now += preamble->preamble_size;
34 if (now > kpart_size)
35 return 1;
36
37 kblob_data = kpart_data + now;
38 kblob_size = preamble->body_signature.data_size;
39
40 if (!kblob_data || (now + kblob_size) > kpart_size)
41 return 1;
42
43 if (preamble->header_version_minor > 0) {
44 vmlinuz_header_address = preamble->vmlinuz_header_address;
45 vmlinuz_header_size = preamble->vmlinuz_header_size;
46 }
47
48 if (!vmlinuz_header_size ||
49 kpart_data + vmlinuz_header_offset + vmlinuz_header_size >
50 kpart_data) {
51 return 1;
52 }
53
54 // calculate the vmlinuz_header offset from
55 // the beginning of the kpart_data. The kblob doesn't
56 // include the body_load_offset, but does include
57 // the keyblock and preamble sections.
58 vmlinuz_header_offset = vmlinuz_header_address -
59 preamble->body_load_address +
60 keyblock->keyblock_size +
61 preamble->preamble_size;
62
63 vmlinuz = malloc(vmlinuz_header_size + kblob_size);
64 if (vmlinuz == NULL)
65 return 1;
66
67 memcpy(vmlinuz, kpart_data + vmlinuz_header_offset,
68 vmlinuz_header_size);
69
70 memcpy(vmlinuz + vmlinuz_header_size, kblob_data, kblob_size);
71
72 *vmlinuz_out = vmlinuz;
73 *vmlinuz_size = vmlinuz_header_size + kblob_size;
74
75 return 0;
76 }
77