• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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