1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
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 "module_hvb_utils.h"
16
17 #include <fcntl.h>
18 #include <linux/fs.h>
19 #include <sys/ioctl.h>
20
21 #include "module_utils.h"
22 #include "log/log.h"
23 #include "scope_guard.h"
24 #include "securec.h"
25 #include "utils.h"
26
27 namespace OHOS {
28 namespace SysInstaller {
29 using namespace Updater;
30 using std::string;
31
32 namespace {
33 constexpr uint64_t DEFAULT_MODULE_HVB_INFO_SIZE = 4 * 1024; // 4K
34 }
35
GetBlockDeviceSize(int fd)36 uint64_t GetBlockDeviceSize(int fd)
37 {
38 uint64_t size = 0;
39 return (ioctl(fd, BLKGETSIZE64, &size) == 0) ? size : 0;
40 }
41
SetModuleFooterData(struct hvb_footer & footer,uint64_t blockSize,uint64_t cert_size)42 bool SetModuleFooterData(struct hvb_footer &footer, uint64_t blockSize, uint64_t cert_size)
43 {
44 if (memcpy_s(footer.magic, HVB_FOOTER_MAGIC_LEN, HVB_FOOTER_MAGIC, HVB_FOOTER_MAGIC_LEN) != EOK) {
45 LOG(ERROR) << "copy footer magic fail";
46 return false;
47 }
48 footer.cert_offset = blockSize - DEFAULT_MODULE_HVB_INFO_SIZE;
49 footer.cert_size = cert_size;
50 footer.image_size = blockSize - DEFAULT_MODULE_HVB_INFO_SIZE;
51 footer.partition_size = blockSize;
52 return true;
53 }
54
GetFooterFromImage(int fd,uint64_t imageSize,struct hvb_footer & footer)55 bool GetFooterFromImage(int fd, uint64_t imageSize, struct hvb_footer &footer)
56 {
57 if (imageSize <= HVB_FOOTER_SIZE) {
58 LOG(ERROR) << "image imageSize is too small, get footer fail";
59 return false;
60 }
61 uint64_t offset = imageSize - HVB_FOOTER_SIZE;
62 if (!ReadFullyAtOffset(fd, reinterpret_cast<uint8_t *>(&footer), HVB_FOOTER_SIZE, offset)) {
63 LOG(ERROR) << "read footer info fail";
64 return false;
65 }
66 return true;
67 }
68
GetCertDataFromImage(int fd,uint64_t imageSize,uint64_t offset,uint8_t * pubkey,uint64_t keySize)69 bool GetCertDataFromImage(int fd, uint64_t imageSize, uint64_t offset, uint8_t *pubkey, uint64_t keySize)
70 {
71 if (imageSize < offset + keySize) {
72 LOG(ERROR) << "image imageSize is too small, get pubkey fail";
73 return false;
74 }
75 if (!ReadFullyAtOffset(fd, pubkey, keySize, offset)) {
76 LOG(ERROR) << "read image info fail";
77 return false;
78 }
79 return true;
80 }
81
WriteModuleUpdateBlock(const struct hvb_buf & pubkey,const std::string & partition)82 bool WriteModuleUpdateBlock(const struct hvb_buf &pubkey, const std::string &partition)
83 {
84 if (pubkey.size + HVB_FOOTER_SIZE > DEFAULT_MODULE_HVB_INFO_SIZE) {
85 LOG(ERROR) << "the size of pubkey and footer is override";
86 return false;
87 }
88 std::string partitionPath = Utils::GetPartitionRealPath(partition);
89 if (partitionPath.empty()) {
90 LOG(ERROR) << "partition is empty, invalid";
91 return false;
92 }
93
94 auto fd = open(partitionPath.c_str(), O_RDWR);
95 if (fd < 0) {
96 LOG(ERROR) << "open partition fail, error = " << errno;
97 return false;
98 }
99 ON_SCOPE_EXIT(clear) {
100 close(fd);
101 };
102 // generate footer for module_update partition
103 uint64_t blockSize = GetBlockDeviceSize(fd);
104 if (blockSize < DEFAULT_MODULE_HVB_INFO_SIZE) {
105 LOG(ERROR) << "module update blockSize is too small, blockSize: " << blockSize;
106 return false;
107 }
108 struct hvb_footer footer;
109 if (!SetModuleFooterData(footer, blockSize, pubkey.size)) {
110 LOG(ERROR) << "set footer fail";
111 return false;
112 }
113 auto buffer = std::make_unique<uint8_t[]>(DEFAULT_MODULE_HVB_INFO_SIZE);
114 if (buffer == nullptr) {
115 LOG(ERROR) << "make_unique fail";
116 return false;
117 }
118 uint64_t footerOffset = DEFAULT_MODULE_HVB_INFO_SIZE - HVB_FOOTER_SIZE;
119 if (memcpy_s(buffer.get(), pubkey.size, pubkey.addr, pubkey.size) != EOK ||
120 memcpy_s(buffer.get() + footerOffset, HVB_FOOTER_SIZE, &footer, HVB_FOOTER_SIZE) != EOK) {
121 LOG(ERROR) << "copy footer or pubkey fail";
122 return false;
123 }
124
125 if (!WriteFullyAtOffset(fd, buffer.get(), DEFAULT_MODULE_HVB_INFO_SIZE, blockSize - DEFAULT_MODULE_HVB_INFO_SIZE)) {
126 LOG(ERROR) << "write fully hvb info fail";
127 return false;
128 }
129 return true;
130 }
131
DealModuleUpdateHvbInfo(const std::string & imagePath,uint64_t imageSize,const std::string & partition)132 bool DealModuleUpdateHvbInfo(const std::string &imagePath, uint64_t imageSize, const std::string &partition)
133 {
134 std::string realPath = GetRealPath(imagePath);
135 if (realPath.empty()) {
136 LOG(ERROR) << "invalid path " << imagePath;
137 return false;
138 }
139 auto fd = open(realPath.c_str(), O_RDWR);
140 if (fd < 0) {
141 LOG(ERROR) << "open partition "<< realPath << " fail, error = " << errno;
142 return false;
143 }
144 ON_SCOPE_EXIT(clear) {
145 close(fd);
146 };
147
148 struct hvb_footer footer;
149 if (!GetFooterFromImage(fd, imageSize, footer)) {
150 LOG(ERROR) << "get footer from image fail";
151 return false;
152 }
153
154 // get cert data by footer info
155 struct hvb_buf pubkey;
156 pubkey.size = footer.cert_size;
157 if (pubkey.size > DEFAULT_MODULE_HVB_INFO_SIZE - HVB_FOOTER_SIZE) {
158 LOG(ERROR) << "cert size in footer is override";
159 return false;
160 }
161 auto buffer = std::make_unique<uint8_t[]>(pubkey.size);
162 if (buffer == nullptr) {
163 LOG(ERROR) << "make_unique fail";
164 return false;
165 }
166 pubkey.addr = buffer.get();
167
168 if (!GetCertDataFromImage(fd, imageSize, footer.cert_offset, pubkey.addr, pubkey.size)) {
169 LOG(ERROR) << "get pubkey from image fail";
170 return false;
171 }
172
173 // generate new footer, write cert data and footer into partition
174 if (!WriteModuleUpdateBlock(pubkey, partition)) {
175 LOG(ERROR) << "write module update partition fail";
176 return false;
177 }
178 return true;
179 }
180 } // namespace SysInstaller
181 } // namespace OHOS