xref: /aosp_15_r20/system/core/fs_mgr/libfs_avb/avb_ops.cpp (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without
7  * restriction, including without limitation the rights to use, copy,
8  * modify, merge, publish, distribute, sublicense, and/or sell copies
9  * of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 
25 #include "avb_ops.h"
26 
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <linux/fs.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sys/ioctl.h>
33 #include <sys/stat.h>
34 
35 #include <string>
36 
37 #include <android-base/logging.h>
38 #include <android-base/macros.h>
39 #include <android-base/strings.h>
40 #include <android-base/unique_fd.h>
41 #include <libavb/libavb.h>
42 #include <libdm/dm.h>
43 #include <utils/Compat.h>
44 
45 #include "util.h"
46 
47 using namespace std::literals;
48 
49 namespace android {
50 namespace fs_mgr {
51 
read_from_partition(AvbOps * ops,const char * partition,int64_t offset,size_t num_bytes,void * buffer,size_t * out_num_read)52 static AvbIOResult read_from_partition(AvbOps* ops, const char* partition, int64_t offset,
53                                        size_t num_bytes, void* buffer, size_t* out_num_read) {
54     return FsManagerAvbOps::GetInstanceFromAvbOps(ops)->ReadFromPartition(
55             partition, offset, num_bytes, buffer, out_num_read);
56 }
57 
no_op_read_rollback_index(AvbOps * ops ATTRIBUTE_UNUSED,size_t rollback_index_location ATTRIBUTE_UNUSED,uint64_t * out_rollback_index)58 static AvbIOResult no_op_read_rollback_index(AvbOps* ops ATTRIBUTE_UNUSED,
59                                             size_t rollback_index_location ATTRIBUTE_UNUSED,
60                                             uint64_t* out_rollback_index) {
61     // rollback_index has been checked in bootloader phase.
62     // In user-space, returns the smallest value 0 to pass the check.
63     *out_rollback_index = 0;
64     return AVB_IO_RESULT_OK;
65 }
66 
no_op_validate_vbmeta_public_key(AvbOps * ops ATTRIBUTE_UNUSED,const uint8_t * public_key_data ATTRIBUTE_UNUSED,size_t public_key_length ATTRIBUTE_UNUSED,const uint8_t * public_key_metadata ATTRIBUTE_UNUSED,size_t public_key_metadata_length ATTRIBUTE_UNUSED,bool * out_is_trusted)67 static AvbIOResult no_op_validate_vbmeta_public_key(
68         AvbOps* ops ATTRIBUTE_UNUSED, const uint8_t* public_key_data ATTRIBUTE_UNUSED,
69         size_t public_key_length ATTRIBUTE_UNUSED,
70         const uint8_t* public_key_metadata ATTRIBUTE_UNUSED,
71         size_t public_key_metadata_length ATTRIBUTE_UNUSED, bool* out_is_trusted) {
72     // vbmeta public key has been checked in bootloader phase.
73     // In user-space, returns true to pass the check.
74     //
75     // Addtionally, user-space should check
76     // androidboot.vbmeta.{hash_alg, size, digest} against the digest
77     // of all vbmeta images after invoking avb_slot_verify().
78     *out_is_trusted = true;
79     return AVB_IO_RESULT_OK;
80 }
81 
no_op_read_is_device_unlocked(AvbOps * ops ATTRIBUTE_UNUSED,bool * out_is_unlocked)82 static AvbIOResult no_op_read_is_device_unlocked(AvbOps* ops ATTRIBUTE_UNUSED,
83                                                 bool* out_is_unlocked) {
84     // The function is for bootloader to update the value into
85     // androidboot.vbmeta.device_state in kernel cmdline.
86     // In user-space, returns true as we don't need to update it anymore.
87     *out_is_unlocked = true;
88     return AVB_IO_RESULT_OK;
89 }
90 
no_op_get_unique_guid_for_partition(AvbOps * ops ATTRIBUTE_UNUSED,const char * partition ATTRIBUTE_UNUSED,char * guid_buf,size_t guid_buf_size)91 static AvbIOResult no_op_get_unique_guid_for_partition(AvbOps* ops ATTRIBUTE_UNUSED,
92                                                       const char* partition ATTRIBUTE_UNUSED,
93                                                       char* guid_buf, size_t guid_buf_size) {
94     // The function is for bootloader to set the correct UUID
95     // for a given partition in kernel cmdline.
96     // In user-space, returns a faking one as we don't need to update
97     // it anymore.
98     snprintf(guid_buf, guid_buf_size, "1234-fake-guid-for:%s", partition);
99     return AVB_IO_RESULT_OK;
100 }
101 
get_size_of_partition(AvbOps * ops ATTRIBUTE_UNUSED,const char * partition ATTRIBUTE_UNUSED,uint64_t * out_size_num_byte)102 static AvbIOResult get_size_of_partition(AvbOps* ops ATTRIBUTE_UNUSED,
103                                          const char* partition ATTRIBUTE_UNUSED,
104                                          uint64_t* out_size_num_byte) {
105     return FsManagerAvbOps::GetInstanceFromAvbOps(ops)->GetSizeOfPartition(partition,
106                                                                            out_size_num_byte);
107 }
108 
109 // Converts a partition name (with ab_suffix) to the corresponding mount point.
110 // e.g., "system_a" => "/system",
111 // e.g., "vendor_a" => "/vendor",
DeriveMountPoint(const std::string & partition_name,const std::string & ab_suffix)112 static std::string DeriveMountPoint(const std::string& partition_name,
113                                     const std::string& ab_suffix) {
114     std::string mount_point(partition_name);
115     auto found = partition_name.rfind(ab_suffix);
116     if (found != std::string::npos) {
117         mount_point.erase(found);  // converts system_a => system
118     }
119 
120     return "/" + mount_point;
121 }
122 
FsManagerAvbOps(const std::string & slot_suffix)123 FsManagerAvbOps::FsManagerAvbOps(const std::string& slot_suffix) {
124     // We only need to provide the implementation of read_from_partition()
125     // operation since that's all what is being used by the avb_slot_verify().
126     // Other I/O operations are only required in bootloader but not in
127     // user-space so we set them as no-op operations. Also zero the entire
128     // struct so operations added in the future will be set to NULL.
129     memset(&avb_ops_, 0, sizeof(AvbOps));
130     avb_ops_.read_from_partition = read_from_partition;
131     avb_ops_.read_rollback_index = no_op_read_rollback_index;
132     avb_ops_.validate_vbmeta_public_key = no_op_validate_vbmeta_public_key;
133     avb_ops_.read_is_device_unlocked = no_op_read_is_device_unlocked;
134     avb_ops_.get_unique_guid_for_partition = no_op_get_unique_guid_for_partition;
135     avb_ops_.get_size_of_partition = get_size_of_partition;
136 
137     // Sets user_data for GetInstanceFromAvbOps() to convert it back to FsManagerAvbOps.
138     avb_ops_.user_data = this;
139 
140     slot_suffix_ = slot_suffix;
141     if (slot_suffix_.empty()) {
142         slot_suffix_ = fs_mgr_get_slot_suffix();
143     }
144 }
145 
146 // Given a partition name (with ab_suffix), e.g., system_a, returns the corresponding
147 // dm-linear path for it. e.g., /dev/block/dm-0. If not found, returns an empty string.
148 // This assumes that the prefix of the partition name and the mount point are the same.
149 // e.g., partition vendor_a is mounted under /vendor, product_a is mounted under /product, etc.
150 // This might not be true for some special fstab files, e.g., fstab.postinstall.
151 // But it's good enough for the default fstab. Also note that the logical path is a
152 // fallback solution when the physical path (/dev/block/by-name/<partition>) cannot be found.
GetLogicalPath(const std::string & partition_name)153 std::string FsManagerAvbOps::GetLogicalPath(const std::string& partition_name) {
154     if (fstab_.empty() && !ReadDefaultFstab(&fstab_)) {
155         return "";
156     }
157 
158     const auto mount_point = DeriveMountPoint(partition_name, slot_suffix_);
159     if (mount_point.empty()) return "";
160 
161     auto fstab_entry = GetEntryForMountPoint(&fstab_, mount_point);
162     if (!fstab_entry) return "";
163 
164     std::string device_path;
165     if (fstab_entry->fs_mgr_flags.logical) {
166         dm::DeviceMapper& dm = dm::DeviceMapper::Instance();
167         if (!dm.GetDmDevicePathByName(fstab_entry->blk_device, &device_path)) {
168             LERROR << "Failed to resolve logical device path for: " << fstab_entry->blk_device;
169             return "";
170         }
171         return device_path;
172     }
173 
174     return "";
175 }
GetPartitionPath(const char * partition)176 std::string FsManagerAvbOps::GetPartitionPath(const char* partition) {
177     std::string path = "/dev/block/by-name/"s + partition;
178     if (!WaitForFile(path, 1s)) {
179         LERROR << "Device path not found: " << path;
180         // Falls back to logical path if the physical path is not found.
181         // This mostly only works for emulator (no bootloader). Because in normal
182         // device, bootloader is unable to read logical partitions. So if libavb in
183         // the bootloader failed to read a physical partition, it will failed to boot
184         // the HLOS and we won't reach the code here.
185         path = GetLogicalPath(partition);
186         if (path.empty() || !WaitForFile(path, 1s)) return "";
187     }
188     return path;
189 }
190 
GetSizeOfPartition(const char * partition,uint64_t * out_size_num_byte)191 AvbIOResult FsManagerAvbOps::GetSizeOfPartition(const char* partition,
192                                                 uint64_t* out_size_num_byte) {
193     const auto path = GetPartitionPath(partition);
194     if (path.empty()) {
195         return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
196     }
197     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
198     if (fd < 0) {
199         PERROR << "Failed to open " << path;
200         return AVB_IO_RESULT_ERROR_IO;
201     }
202     int err = ioctl(fd, BLKGETSIZE64, out_size_num_byte);
203     if (err) {
204         *out_size_num_byte = 0;
205         return AVB_IO_RESULT_ERROR_IO;
206     }
207     return AVB_IO_RESULT_OK;
208 }
209 
ReadFromPartition(const char * partition,int64_t offset,size_t num_bytes,void * buffer,size_t * out_num_read)210 AvbIOResult FsManagerAvbOps::ReadFromPartition(const char* partition, int64_t offset,
211                                                size_t num_bytes, void* buffer,
212                                                size_t* out_num_read) {
213     std::string path = GetPartitionPath(partition);
214     if (path.empty()) {
215         return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
216     }
217 
218     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
219     if (fd < 0) {
220         PERROR << "Failed to open " << path;
221         return AVB_IO_RESULT_ERROR_IO;
222     }
223 
224     // If offset is negative, interprets its absolute value as the
225     //  number of bytes from the end of the partition.
226     if (offset < 0) {
227         off64_t total_size = lseek64(fd, 0, SEEK_END);
228         if (total_size == -1) {
229             PERROR << "Failed to lseek64 to end of the partition";
230             return AVB_IO_RESULT_ERROR_IO;
231         }
232         offset = total_size + offset;
233         // Repositions the offset to the beginning.
234         if (lseek64(fd, 0, SEEK_SET) == -1) {
235             PERROR << "Failed to lseek64 to the beginning of the partition";
236             return AVB_IO_RESULT_ERROR_IO;
237         }
238     }
239 
240     // On Linux, we never get partial reads from block devices (except
241     // for EOF).
242     ssize_t num_read = TEMP_FAILURE_RETRY(pread64(fd, buffer, num_bytes, offset));
243     if (num_read < 0 || (size_t)num_read != num_bytes) {
244         PERROR << "Failed to read " << num_bytes << " bytes from " << path << " offset " << offset;
245         return AVB_IO_RESULT_ERROR_IO;
246     }
247 
248     if (out_num_read != nullptr) {
249         *out_num_read = num_read;
250     }
251 
252     return AVB_IO_RESULT_OK;
253 }
254 
AvbSlotVerify(const std::string & ab_suffix,AvbSlotVerifyFlags flags,std::vector<VBMetaData> * out_vbmeta_images)255 AvbSlotVerifyResult FsManagerAvbOps::AvbSlotVerify(const std::string& ab_suffix,
256                                                    AvbSlotVerifyFlags flags,
257                                                    std::vector<VBMetaData>* out_vbmeta_images) {
258     // Invokes avb_slot_verify() to load and verify all vbmeta images.
259     // Sets requested_partitions to nullptr as it's to copy the contents
260     // of HASH partitions into handle>avb_slot_data_, which is not required as
261     // fs_mgr only deals with HASHTREE partitions.
262     const char* requested_partitions[] = {nullptr};
263 
264     // Local resource to store vbmeta images from avb_slot_verify();
265     AvbSlotVerifyData* avb_slot_data;
266 
267     // The |hashtree_error_mode| field doesn't matter as it only
268     // influences the generated kernel cmdline parameters.
269     auto verify_result =
270             avb_slot_verify(&avb_ops_, requested_partitions, ab_suffix.c_str(), flags,
271                             AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, &avb_slot_data);
272 
273     if (!avb_slot_data) return verify_result;
274     // Copies avb_slot_data->vbmeta_images[].
275     for (size_t i = 0; i < avb_slot_data->num_vbmeta_images; i++) {
276         out_vbmeta_images->emplace_back(VBMetaData(avb_slot_data->vbmeta_images[i].vbmeta_data,
277                                                    avb_slot_data->vbmeta_images[i].vbmeta_size,
278                                                    avb_slot_data->vbmeta_images[i].partition_name));
279     }
280 
281     // Free the local resource.
282     avb_slot_verify_data_free(avb_slot_data);
283 
284     return verify_result;
285 }
286 
287 }  // namespace fs_mgr
288 }  // namespace android
289