Zach Reizner | 317bb49 | 2015-02-20 14:55:02 -0800 | [diff] [blame] | 1 | /* Copyright 2015 The Chromium OS Authors. All rights reserved. |
| 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 | |
Randall Spangler | 939cc3a | 2016-06-21 15:23:32 -0700 | [diff] [blame] | 11 | #include "vb2_struct.h" |
Zach Reizner | 317bb49 | 2015-02-20 14:55:02 -0800 | [diff] [blame] | 12 | #include "vboot_struct.h" |
| 13 | |
| 14 | |
| 15 | int ExtractVmlinuz(void *kpart_data, size_t kpart_size, |
| 16 | void **vmlinuz_out, size_t *vmlinuz_size) { |
Randall Spangler | 939cc3a | 2016-06-21 15:23:32 -0700 | [diff] [blame] | 17 | size_t now = 0; |
Randall Spangler | 5c537e3 | 2016-06-30 14:52:30 -0700 | [diff] [blame] | 18 | struct vb2_kernel_preamble *preamble = NULL; |
Zach Reizner | 317bb49 | 2015-02-20 14:55:02 -0800 | [diff] [blame] | 19 | uint8_t *kblob_data = NULL; |
Randall Spangler | 5c537e3 | 2016-06-30 14:52:30 -0700 | [diff] [blame] | 20 | uint32_t kblob_size = 0; |
| 21 | uint32_t vmlinuz_header_size = 0; |
Zach Reizner | 317bb49 | 2015-02-20 14:55:02 -0800 | [diff] [blame] | 22 | uint64_t vmlinuz_header_address = 0; |
| 23 | uint64_t vmlinuz_header_offset = 0; |
| 24 | void *vmlinuz = NULL; |
| 25 | |
Randall Spangler | 939cc3a | 2016-06-21 15:23:32 -0700 | [diff] [blame] | 26 | struct vb2_keyblock *keyblock = (struct vb2_keyblock *)kpart_data; |
| 27 | now += keyblock->keyblock_size; |
Zach Reizner | 317bb49 | 2015-02-20 14:55:02 -0800 | [diff] [blame] | 28 | if (now > kpart_size) |
| 29 | return 1; |
| 30 | |
Randall Spangler | 5c537e3 | 2016-06-30 14:52:30 -0700 | [diff] [blame] | 31 | preamble = (struct vb2_kernel_preamble *)(kpart_data + now); |
Zach Reizner | 317bb49 | 2015-02-20 14:55:02 -0800 | [diff] [blame] | 32 | now += preamble->preamble_size; |
| 33 | if (now > kpart_size) |
| 34 | return 1; |
| 35 | |
| 36 | kblob_data = kpart_data + now; |
| 37 | kblob_size = preamble->body_signature.data_size; |
| 38 | |
| 39 | if (!kblob_data || (now + kblob_size) > kpart_size) |
| 40 | return 1; |
| 41 | |
| 42 | if (preamble->header_version_minor > 0) { |
| 43 | vmlinuz_header_address = preamble->vmlinuz_header_address; |
| 44 | vmlinuz_header_size = preamble->vmlinuz_header_size; |
| 45 | } |
| 46 | |
| 47 | if (!vmlinuz_header_size || |
Randall Spangler | 5c537e3 | 2016-06-30 14:52:30 -0700 | [diff] [blame] | 48 | kpart_data + vmlinuz_header_offset + vmlinuz_header_size > |
| 49 | kpart_data) { |
Zach Reizner | 317bb49 | 2015-02-20 14:55:02 -0800 | [diff] [blame] | 50 | return 1; |
| 51 | } |
| 52 | |
| 53 | // calculate the vmlinuz_header offset from |
| 54 | // the beginning of the kpart_data. The kblob doesn't |
| 55 | // include the body_load_offset, but does include |
| 56 | // the keyblock and preamble sections. |
| 57 | vmlinuz_header_offset = vmlinuz_header_address - |
| 58 | preamble->body_load_address + |
Randall Spangler | 939cc3a | 2016-06-21 15:23:32 -0700 | [diff] [blame] | 59 | keyblock->keyblock_size + |
Zach Reizner | 317bb49 | 2015-02-20 14:55:02 -0800 | [diff] [blame] | 60 | preamble->preamble_size; |
| 61 | |
| 62 | vmlinuz = malloc(vmlinuz_header_size + kblob_size); |
| 63 | if (vmlinuz == NULL) |
| 64 | return 1; |
| 65 | |
| 66 | memcpy(vmlinuz, kpart_data + vmlinuz_header_offset, |
| 67 | vmlinuz_header_size); |
| 68 | |
| 69 | memcpy(vmlinuz + vmlinuz_header_size, kblob_data, kblob_size); |
| 70 | |
| 71 | *vmlinuz_out = vmlinuz; |
| 72 | *vmlinuz_size = vmlinuz_header_size + kblob_size; |
| 73 | |
| 74 | return 0; |
| 75 | } |