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 <stdlib.h>
30 #include <string.h>
31 #include <sys/stat.h>
32
33 #include <string>
34
35 #include <android-base/macros.h>
36 #include <android-base/strings.h>
37 #include <android-base/unique_fd.h>
38 #include <libavb/libavb.h>
39 #include <libdm/dm.h>
40 #include <utils/Compat.h>
41
42 #include "util.h"
43
44 using namespace std::literals;
45
46 namespace android {
47 namespace fs_mgr {
48
read_from_partition(AvbOps * ops,const char * partition,int64_t offset,size_t num_bytes,void * buffer,size_t * out_num_read)49 static AvbIOResult read_from_partition(AvbOps* ops, const char* partition, int64_t offset,
50 size_t num_bytes, void* buffer, size_t* out_num_read) {
51 return FsManagerAvbOps::GetInstanceFromAvbOps(ops)->ReadFromPartition(
52 partition, offset, num_bytes, buffer, out_num_read);
53 }
54
no_op_read_rollback_index(AvbOps * ops ATTRIBUTE_UNUSED,size_t rollback_index_location ATTRIBUTE_UNUSED,uint64_t * out_rollback_index)55 static AvbIOResult no_op_read_rollback_index(AvbOps* ops ATTRIBUTE_UNUSED,
56 size_t rollback_index_location ATTRIBUTE_UNUSED,
57 uint64_t* out_rollback_index) {
58 // rollback_index has been checked in bootloader phase.
59 // In user-space, returns the smallest value 0 to pass the check.
60 *out_rollback_index = 0;
61 return AVB_IO_RESULT_OK;
62 }
63
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)64 static AvbIOResult no_op_validate_vbmeta_public_key(
65 AvbOps* ops ATTRIBUTE_UNUSED, const uint8_t* public_key_data ATTRIBUTE_UNUSED,
66 size_t public_key_length ATTRIBUTE_UNUSED,
67 const uint8_t* public_key_metadata ATTRIBUTE_UNUSED,
68 size_t public_key_metadata_length ATTRIBUTE_UNUSED, bool* out_is_trusted) {
69 // vbmeta public key has been checked in bootloader phase.
70 // In user-space, returns true to pass the check.
71 //
72 // Addtionally, user-space should check
73 // androidboot.vbmeta.{hash_alg, size, digest} against the digest
74 // of all vbmeta images after invoking avb_slot_verify().
75 *out_is_trusted = true;
76 return AVB_IO_RESULT_OK;
77 }
78
no_op_read_is_device_unlocked(AvbOps * ops ATTRIBUTE_UNUSED,bool * out_is_unlocked)79 static AvbIOResult no_op_read_is_device_unlocked(AvbOps* ops ATTRIBUTE_UNUSED,
80 bool* out_is_unlocked) {
81 // The function is for bootloader to update the value into
82 // androidboot.vbmeta.device_state in kernel cmdline.
83 // In user-space, returns true as we don't need to update it anymore.
84 *out_is_unlocked = true;
85 return AVB_IO_RESULT_OK;
86 }
87
no_op_get_unique_guid_for_partition(AvbOps * ops ATTRIBUTE_UNUSED,const char * partition ATTRIBUTE_UNUSED,char * guid_buf,size_t guid_buf_size)88 static AvbIOResult no_op_get_unique_guid_for_partition(AvbOps* ops ATTRIBUTE_UNUSED,
89 const char* partition ATTRIBUTE_UNUSED,
90 char* guid_buf, size_t guid_buf_size) {
91 // The function is for bootloader to set the correct UUID
92 // for a given partition in kernel cmdline.
93 // In user-space, returns a faking one as we don't need to update
94 // it anymore.
95 snprintf(guid_buf, guid_buf_size, "1234-fake-guid-for:%s", partition);
96 return AVB_IO_RESULT_OK;
97 }
98
no_op_get_size_of_partition(AvbOps * ops ATTRIBUTE_UNUSED,const char * partition ATTRIBUTE_UNUSED,uint64_t * out_size_num_byte)99 static AvbIOResult no_op_get_size_of_partition(AvbOps* ops ATTRIBUTE_UNUSED,
100 const char* partition ATTRIBUTE_UNUSED,
101 uint64_t* out_size_num_byte) {
102 // The function is for bootloader to load entire content of AVB HASH partitions.
103 // In user-space, returns 0 as we only need to set up AVB HASHTHREE partitions.
104 *out_size_num_byte = 0;
105 return AVB_IO_RESULT_OK;
106 }
107
108 // Converts a partition name (with ab_suffix) to the corresponding mount point.
109 // e.g., "system_a" => "/system",
110 // e.g., "vendor_a" => "/vendor",
DeriveMountPoint(const std::string & partition_name)111 static std::string DeriveMountPoint(const std::string& partition_name) {
112 const std::string ab_suffix = fs_mgr_get_slot_suffix();
113 std::string mount_point(partition_name);
114 auto found = partition_name.rfind(ab_suffix);
115 if (found != std::string::npos) {
116 mount_point.erase(found); // converts system_a => system
117 }
118
119 return "/" + mount_point;
120 }
121
FsManagerAvbOps()122 FsManagerAvbOps::FsManagerAvbOps() {
123 // We only need to provide the implementation of read_from_partition()
124 // operation since that's all what is being used by the avb_slot_verify().
125 // Other I/O operations are only required in bootloader but not in
126 // user-space so we set them as no-op operations. Also zero the entire
127 // struct so operations added in the future will be set to NULL.
128 memset(&avb_ops_, 0, sizeof(AvbOps));
129 avb_ops_.read_from_partition = read_from_partition;
130 avb_ops_.read_rollback_index = no_op_read_rollback_index;
131 avb_ops_.validate_vbmeta_public_key = no_op_validate_vbmeta_public_key;
132 avb_ops_.read_is_device_unlocked = no_op_read_is_device_unlocked;
133 avb_ops_.get_unique_guid_for_partition = no_op_get_unique_guid_for_partition;
134 avb_ops_.get_size_of_partition = no_op_get_size_of_partition;
135
136 // Sets user_data for GetInstanceFromAvbOps() to convert it back to FsManagerAvbOps.
137 avb_ops_.user_data = this;
138 }
139
140 // Given a partition name (with ab_suffix), e.g., system_a, returns the corresponding
141 // dm-linear path for it. e.g., /dev/block/dm-0. If not found, returns an empty string.
142 // This assumes that the prefix of the partition name and the mount point are the same.
143 // e.g., partition vendor_a is mounted under /vendor, product_a is mounted under /product, etc.
144 // This might not be true for some special fstab files, e.g., fstab.postinstall.
145 // But it's good enough for the default fstab. Also note that the logical path is a
146 // fallback solution when the physical path (/dev/block/by-name/<partition>) cannot be found.
GetLogicalPath(const std::string & partition_name)147 std::string FsManagerAvbOps::GetLogicalPath(const std::string& partition_name) {
148 if (fstab_.empty() && !ReadDefaultFstab(&fstab_)) {
149 return "";
150 }
151
152 const auto mount_point = DeriveMountPoint(partition_name);
153 if (mount_point.empty()) return "";
154
155 auto fstab_entry = GetEntryForMountPoint(&fstab_, mount_point);
156 if (!fstab_entry) return "";
157
158 std::string device_path;
159 if (fstab_entry->fs_mgr_flags.logical) {
160 dm::DeviceMapper& dm = dm::DeviceMapper::Instance();
161 if (!dm.GetDmDevicePathByName(fstab_entry->blk_device, &device_path)) {
162 LERROR << "Failed to resolve logical device path for: " << fstab_entry->blk_device;
163 return "";
164 }
165 return device_path;
166 }
167
168 return "";
169 }
170
ReadFromPartition(const char * partition,int64_t offset,size_t num_bytes,void * buffer,size_t * out_num_read)171 AvbIOResult FsManagerAvbOps::ReadFromPartition(const char* partition, int64_t offset,
172 size_t num_bytes, void* buffer,
173 size_t* out_num_read) {
174 std::string path = "/dev/block/by-name/"s + partition;
175
176 // Ensures the device path (a symlink created by init) is ready to access.
177 if (!WaitForFile(path, 1s)) {
178 LERROR << "Device path not found: " << path;
179 // Falls back to logical path if the physical path is not found.
180 // This mostly only works for emulator (no bootloader). Because in normal
181 // device, bootloader is unable to read logical partitions. So if libavb in
182 // the bootloader failed to read a physical partition, it will failed to boot
183 // the HLOS and we won't reach the code here.
184 path = GetLogicalPath(partition);
185 if (path.empty() || !WaitForFile(path, 1s)) return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
186 LINFO << "Fallback to use logical device path: " << path;
187 }
188
189 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
190 if (fd < 0) {
191 PERROR << "Failed to open " << path;
192 return AVB_IO_RESULT_ERROR_IO;
193 }
194
195 // If offset is negative, interprets its absolute value as the
196 // number of bytes from the end of the partition.
197 if (offset < 0) {
198 off64_t total_size = lseek64(fd, 0, SEEK_END);
199 if (total_size == -1) {
200 PERROR << "Failed to lseek64 to end of the partition";
201 return AVB_IO_RESULT_ERROR_IO;
202 }
203 offset = total_size + offset;
204 // Repositions the offset to the beginning.
205 if (lseek64(fd, 0, SEEK_SET) == -1) {
206 PERROR << "Failed to lseek64 to the beginning of the partition";
207 return AVB_IO_RESULT_ERROR_IO;
208 }
209 }
210
211 // On Linux, we never get partial reads from block devices (except
212 // for EOF).
213 ssize_t num_read = TEMP_FAILURE_RETRY(pread64(fd, buffer, num_bytes, offset));
214 if (num_read < 0 || (size_t)num_read != num_bytes) {
215 PERROR << "Failed to read " << num_bytes << " bytes from " << path << " offset " << offset;
216 return AVB_IO_RESULT_ERROR_IO;
217 }
218
219 if (out_num_read != nullptr) {
220 *out_num_read = num_read;
221 }
222
223 return AVB_IO_RESULT_OK;
224 }
225
AvbSlotVerify(const std::string & ab_suffix,AvbSlotVerifyFlags flags,std::vector<VBMetaData> * out_vbmeta_images)226 AvbSlotVerifyResult FsManagerAvbOps::AvbSlotVerify(const std::string& ab_suffix,
227 AvbSlotVerifyFlags flags,
228 std::vector<VBMetaData>* out_vbmeta_images) {
229 // Invokes avb_slot_verify() to load and verify all vbmeta images.
230 // Sets requested_partitions to nullptr as it's to copy the contents
231 // of HASH partitions into handle>avb_slot_data_, which is not required as
232 // fs_mgr only deals with HASHTREE partitions.
233 const char* requested_partitions[] = {nullptr};
234
235 // Local resource to store vbmeta images from avb_slot_verify();
236 AvbSlotVerifyData* avb_slot_data;
237
238 // The |hashtree_error_mode| field doesn't matter as it only
239 // influences the generated kernel cmdline parameters.
240 auto verify_result =
241 avb_slot_verify(&avb_ops_, requested_partitions, ab_suffix.c_str(), flags,
242 AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, &avb_slot_data);
243
244 if (!avb_slot_data) return verify_result;
245 // Copies avb_slot_data->vbmeta_images[].
246 for (size_t i = 0; i < avb_slot_data->num_vbmeta_images; i++) {
247 out_vbmeta_images->emplace_back(VBMetaData(avb_slot_data->vbmeta_images[i].vbmeta_data,
248 avb_slot_data->vbmeta_images[i].vbmeta_size,
249 avb_slot_data->vbmeta_images[i].partition_name));
250 }
251
252 // Free the local resource.
253 avb_slot_verify_data_free(avb_slot_data);
254
255 return verify_result;
256 }
257
258 } // namespace fs_mgr
259 } // namespace android
260