1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "builder.h"
18 
19 #include <android-base/file.h>
20 #include <openssl/sha.h>
21 
22 #include "reader.h"
23 #include "utility.h"
24 #include "writer.h"
25 
26 using android::base::ErrnoError;
27 using android::base::Error;
28 using android::base::Result;
29 using android::base::unique_fd;
30 
31 namespace android {
32 namespace fs_mgr {
33 
SuperVBMetaBuilder()34 SuperVBMetaBuilder::SuperVBMetaBuilder() {}
35 
SuperVBMetaBuilder(const int super_vbmeta_fd,const std::map<std::string,std::string> & images_path)36 SuperVBMetaBuilder::SuperVBMetaBuilder(const int super_vbmeta_fd,
37                                        const std::map<std::string, std::string>& images_path)
38     : super_vbmeta_fd_(super_vbmeta_fd), images_path_(images_path) {}
39 
Build()40 Result<void> SuperVBMetaBuilder::Build() {
41     for (const auto& [vbmeta_name, file_path] : images_path_) {
42         Result<std::string> content = ReadVBMetaImageFromFile(file_path);
43         if (!content.ok()) {
44             return content.error();
45         }
46 
47         Result<uint8_t> vbmeta_index = AddVBMetaImage(vbmeta_name);
48         if (!vbmeta_index.ok()) {
49             return vbmeta_index.error();
50         }
51 
52         Result<void> rv_export_vbmeta_image =
53                 ExportVBMetaImageToFile(vbmeta_index.value(), content.value());
54         if (!rv_export_vbmeta_image.ok()) {
55             return rv_export_vbmeta_image;
56         }
57     }
58     return {};
59 }
60 
ReadVBMetaImageFromFile(const std::string & file)61 Result<std::string> SuperVBMetaBuilder::ReadVBMetaImageFromFile(const std::string& file) {
62     unique_fd source_fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC)));
63     if (source_fd < 0) {
64         return ErrnoError() << "Couldn't open vbmeta image file " << file;
65     }
66 
67     Result<uint64_t> file_size = GetFileSize(source_fd);
68     if (!file_size.ok()) {
69         return file_size.error();
70     }
71 
72     if (file_size.value() > VBMETA_IMAGE_MAX_SIZE) {
73         return Error() << "vbmeta image file size " << file_size.value() << " is too large";
74     }
75 
76     std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(VBMETA_IMAGE_MAX_SIZE);
77     if (!android::base::ReadFully(source_fd, buffer.get(), file_size.value())) {
78         return ErrnoError() << "Couldn't read vbmeta image file " << file;
79     }
80 
81     return std::string(reinterpret_cast<const char*>(buffer.get()), VBMETA_IMAGE_MAX_SIZE);
82 }
83 
GetEmptySlot()84 Result<uint8_t> SuperVBMetaBuilder::GetEmptySlot() {
85     for (uint8_t i = 0; i < VBMETA_IMAGE_MAX_NUM; ++i) {
86         if ((table_.header.in_use & (1 << i)) == 0) return i;
87     }
88     return Error() << "There isn't empty slot in super vbmeta";
89 }
90 
AddVBMetaImage(const std::string & vbmeta_name)91 Result<uint8_t> SuperVBMetaBuilder::AddVBMetaImage(const std::string& vbmeta_name) {
92     auto desc = std::find_if(
93             table_.descriptors.begin(), table_.descriptors.end(),
94             [&vbmeta_name](const auto& entry) { return entry.vbmeta_name == vbmeta_name; });
95 
96     uint8_t slot_number = 0;
97     if (desc != table_.descriptors.end()) {
98         slot_number = desc->vbmeta_index;
99     } else {
100         Result<uint8_t> new_slot = GetEmptySlot();
101         if (!new_slot.ok()) {
102             return new_slot;
103         }
104         slot_number = new_slot.value();
105 
106         // insert new descriptor into table
107         InternalVBMetaDescriptor new_desc;
108         new_desc.vbmeta_index = slot_number;
109         new_desc.vbmeta_name_length = vbmeta_name.length();
110         new_desc.vbmeta_name = vbmeta_name;
111         memset(new_desc.reserved, 0, sizeof(new_desc.reserved));
112         table_.descriptors.emplace_back(std::move(new_desc));
113 
114         // mark slot as in use
115         table_.header.in_use |= (1 << slot_number);
116     }
117 
118     return slot_number;
119 }
120 
DeleteVBMetaImage(const std::string & vbmeta_name)121 void SuperVBMetaBuilder::DeleteVBMetaImage(const std::string& vbmeta_name) {
122     auto desc = std::find_if(
123             table_.descriptors.begin(), table_.descriptors.end(),
124             [&vbmeta_name](const auto& entry) { return entry.vbmeta_name == vbmeta_name; });
125 
126     if (desc != table_.descriptors.end()) {
127         // mark slot as not in use
128         table_.header.in_use &= ~(1 << desc->vbmeta_index);
129 
130         // erase descriptor in table
131         table_.descriptors.erase(desc);
132     }
133 }
134 
ExportVBMetaTable()135 std::unique_ptr<VBMetaTable> SuperVBMetaBuilder::ExportVBMetaTable() {
136     // calculate descriptors size
137     uint32_t descriptors_size = 0;
138     for (const auto& desc : table_.descriptors) {
139         descriptors_size += SUPER_VBMETA_DESCRIPTOR_SIZE + desc.vbmeta_name_length * sizeof(char);
140     }
141 
142     // export header
143     table_.header.magic = SUPER_VBMETA_MAGIC;
144     table_.header.major_version = SUPER_VBMETA_MAJOR_VERSION;
145     table_.header.minor_version = SUPER_VBMETA_MINOR_VERSION;
146     table_.header.header_size = SUPER_VBMETA_HEADER_SIZE;
147     table_.header.total_size = SUPER_VBMETA_HEADER_SIZE + descriptors_size;
148     memset(table_.header.checksum, 0, sizeof(table_.header.checksum));
149     table_.header.descriptors_size = descriptors_size;
150     memset(table_.header.reserved, 0, sizeof(table_.header.reserved));
151     std::string serialized_table = SerializeVBMetaTable(table_);
152     ::SHA256(reinterpret_cast<const uint8_t*>(serialized_table.c_str()), table_.header.total_size,
153              &table_.header.checksum[0]);
154 
155     return std::make_unique<VBMetaTable>(table_);
156 }
157 
ExportVBMetaTableToFile()158 Result<void> SuperVBMetaBuilder::ExportVBMetaTableToFile() {
159     std::unique_ptr<VBMetaTable> table = ExportVBMetaTable();
160 
161     std::string serialized_table = SerializeVBMetaTable(*table);
162 
163     android::base::Result<void> rv_write_primary_vbmeta_table =
164             WritePrimaryVBMetaTable(super_vbmeta_fd_, serialized_table);
165     if (!rv_write_primary_vbmeta_table.ok()) {
166         return rv_write_primary_vbmeta_table;
167     }
168 
169     android::base::Result<void> rv_write_backup_vbmeta_table =
170             WriteBackupVBMetaTable(super_vbmeta_fd_, serialized_table);
171     return rv_write_backup_vbmeta_table;
172 }
173 
ExportVBMetaImageToFile(const uint8_t vbmeta_index,const std::string & vbmeta_image)174 Result<void> SuperVBMetaBuilder::ExportVBMetaImageToFile(const uint8_t vbmeta_index,
175                                                          const std::string& vbmeta_image) {
176     Result<void> rv_write_vbmeta_image =
177             WriteVBMetaImage(super_vbmeta_fd_, vbmeta_index, vbmeta_image);
178     if (!rv_write_vbmeta_image.ok()) {
179         return rv_write_vbmeta_image;
180     }
181 
182     Result<void> rv_validate_vbmeta_image =
183             ValidateVBMetaImage(super_vbmeta_fd_, vbmeta_index, vbmeta_image);
184     return rv_validate_vbmeta_image;
185 }
186 
WriteToSuperVBMetaFile(const std::string & super_vbmeta_file,const std::map<std::string,std::string> & images_path)187 bool WriteToSuperVBMetaFile(const std::string& super_vbmeta_file,
188                             const std::map<std::string, std::string>& images_path) {
189     unique_fd super_vbmeta_fd(TEMP_FAILURE_RETRY(
190             open(super_vbmeta_file.c_str(), O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, 0644)));
191     if (super_vbmeta_fd < 0) {
192         PERROR << "Couldn't open super vbmeta file " << super_vbmeta_file;
193         return false;
194     }
195 
196     SuperVBMetaBuilder builder(super_vbmeta_fd, images_path);
197 
198     Result<void> rv_build = builder.Build();
199     if (!rv_build.ok()) {
200         LERROR << rv_build.error();
201         return false;
202     }
203 
204     Result<void> rv_export = builder.ExportVBMetaTableToFile();
205     if (!rv_export.ok()) {
206         LERROR << rv_export.error();
207         return false;
208     }
209 
210     return true;
211 }
212 
213 }  // namespace fs_mgr
214 }  // namespace android
215