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 "fs_mgr_priv_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 #include <string>
33 
34 #include <android-base/macros.h>
35 #include <android-base/strings.h>
36 #include <android-base/unique_fd.h>
37 #include <libavb/libavb.h>
38 #include <utils/Compat.h>
39 
40 #include "fs_mgr.h"
41 #include "fs_mgr_priv.h"
42 
read_from_partition(AvbOps * ops,const char * partition,int64_t offset,size_t num_bytes,void * buffer,size_t * out_num_read)43 static AvbIOResult read_from_partition(AvbOps* ops, const char* partition, int64_t offset,
44                                        size_t num_bytes, void* buffer, size_t* out_num_read) {
45     return FsManagerAvbOps::GetInstanceFromAvbOps(ops)->ReadFromPartition(
46         partition, offset, num_bytes, buffer, out_num_read);
47 }
48 
dummy_read_rollback_index(AvbOps * ops ATTRIBUTE_UNUSED,size_t rollback_index_location ATTRIBUTE_UNUSED,uint64_t * out_rollback_index)49 static AvbIOResult dummy_read_rollback_index(AvbOps* ops ATTRIBUTE_UNUSED,
50                                              size_t rollback_index_location ATTRIBUTE_UNUSED,
51                                              uint64_t* out_rollback_index) {
52     // rollback_index has been checked in bootloader phase.
53     // In user-space, returns the smallest value 0 to pass the check.
54     *out_rollback_index = 0;
55     return AVB_IO_RESULT_OK;
56 }
57 
dummy_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)58 static AvbIOResult dummy_validate_vbmeta_public_key(
59     AvbOps* ops ATTRIBUTE_UNUSED, const uint8_t* public_key_data ATTRIBUTE_UNUSED,
60     size_t public_key_length ATTRIBUTE_UNUSED, const uint8_t* public_key_metadata ATTRIBUTE_UNUSED,
61     size_t public_key_metadata_length ATTRIBUTE_UNUSED, bool* out_is_trusted) {
62     // vbmeta public key has been checked in bootloader phase.
63     // In user-space, returns true to pass the check.
64     //
65     // Addtionally, user-space should check
66     // androidboot.vbmeta.{hash_alg, size, digest} against the digest
67     // of all vbmeta images after invoking avb_slot_verify().
68     *out_is_trusted = true;
69     return AVB_IO_RESULT_OK;
70 }
71 
dummy_read_is_device_unlocked(AvbOps * ops ATTRIBUTE_UNUSED,bool * out_is_unlocked)72 static AvbIOResult dummy_read_is_device_unlocked(AvbOps* ops ATTRIBUTE_UNUSED,
73                                                  bool* out_is_unlocked) {
74     // The function is for bootloader to update the value into
75     // androidboot.vbmeta.device_state in kernel cmdline.
76     // In user-space, returns true as we don't need to update it anymore.
77     *out_is_unlocked = true;
78     return AVB_IO_RESULT_OK;
79 }
80 
dummy_get_unique_guid_for_partition(AvbOps * ops ATTRIBUTE_UNUSED,const char * partition ATTRIBUTE_UNUSED,char * guid_buf,size_t guid_buf_size)81 static AvbIOResult dummy_get_unique_guid_for_partition(AvbOps* ops ATTRIBUTE_UNUSED,
82                                                        const char* partition ATTRIBUTE_UNUSED,
83                                                        char* guid_buf, size_t guid_buf_size) {
84     // The function is for bootloader to set the correct UUID
85     // for a given partition in kernel cmdline.
86     // In user-space, returns a faking one as we don't need to update
87     // it anymore.
88     snprintf(guid_buf, guid_buf_size, "1234-fake-guid-for:%s", partition);
89     return AVB_IO_RESULT_OK;
90 }
91 
InitializeAvbOps()92 void FsManagerAvbOps::InitializeAvbOps() {
93     // We only need to provide the implementation of read_from_partition()
94     // operation since that's all what is being used by the avb_slot_verify().
95     // Other I/O operations are only required in bootloader but not in
96     // user-space so we set them as dummy operations.
97     avb_ops_.read_from_partition = read_from_partition;
98     avb_ops_.read_rollback_index = dummy_read_rollback_index;
99     avb_ops_.validate_vbmeta_public_key = dummy_validate_vbmeta_public_key;
100     avb_ops_.read_is_device_unlocked = dummy_read_is_device_unlocked;
101     avb_ops_.get_unique_guid_for_partition = dummy_get_unique_guid_for_partition;
102 
103     // Sets user_data for GetInstanceFromAvbOps() to convert it back to FsManagerAvbOps.
104     avb_ops_.user_data = this;
105 }
106 
FsManagerAvbOps(std::map<std::string,std::string> && by_name_symlink_map)107 FsManagerAvbOps::FsManagerAvbOps(std::map<std::string, std::string>&& by_name_symlink_map)
108     : by_name_symlink_map_(std::move(by_name_symlink_map)) {
109     InitializeAvbOps();
110 }
111 
FsManagerAvbOps(const fstab & fstab)112 FsManagerAvbOps::FsManagerAvbOps(const fstab& fstab) {
113     // Constructs the by-name symlink map for each fstab record.
114     // /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a =>
115     // by_name_symlink_map_["system_a"] = "/dev/block/platform/soc.0/7824900.sdhci/by-name/system_a"
116     for (int i = 0; i < fstab.num_entries; i++) {
117         std::string partition_name = basename(fstab.recs[i].blk_device);
118         by_name_symlink_map_[partition_name] = fstab.recs[i].blk_device;
119     }
120     InitializeAvbOps();
121 }
122 
ReadFromPartition(const char * partition,int64_t offset,size_t num_bytes,void * buffer,size_t * out_num_read)123 AvbIOResult FsManagerAvbOps::ReadFromPartition(const char* partition, int64_t offset,
124                                                size_t num_bytes, void* buffer,
125                                                size_t* out_num_read) {
126     const auto iter = by_name_symlink_map_.find(partition);
127     if (iter == by_name_symlink_map_.end()) {
128         LERROR << "by-name symlink not found for partition: '" << partition << "'";
129         return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
130     }
131     std::string path = iter->second;
132 
133     // Ensures the device path (a symlink created by init) is ready to
134     // access. fs_mgr_test_access() will test a few iterations if the
135     // path doesn't exist yet.
136     if (fs_mgr_test_access(path.c_str()) < 0) {
137         return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION;
138     }
139 
140     android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC)));
141     if (fd < 0) {
142         PERROR << "Failed to open " << path;
143         return AVB_IO_RESULT_ERROR_IO;
144     }
145 
146     // If offset is negative, interprets its absolute value as the
147     //  number of bytes from the end of the partition.
148     if (offset < 0) {
149         off64_t total_size = lseek64(fd, 0, SEEK_END);
150         if (total_size == -1) {
151             LERROR << "Failed to lseek64 to end of the partition";
152             return AVB_IO_RESULT_ERROR_IO;
153         }
154         offset = total_size + offset;
155         // Repositions the offset to the beginning.
156         if (lseek64(fd, 0, SEEK_SET) == -1) {
157             LERROR << "Failed to lseek64 to the beginning of the partition";
158             return AVB_IO_RESULT_ERROR_IO;
159         }
160     }
161 
162     // On Linux, we never get partial reads from block devices (except
163     // for EOF).
164     ssize_t num_read = TEMP_FAILURE_RETRY(pread64(fd, buffer, num_bytes, offset));
165     if (num_read < 0 || (size_t)num_read != num_bytes) {
166         PERROR << "Failed to read " << num_bytes << " bytes from " << path << " offset " << offset;
167         return AVB_IO_RESULT_ERROR_IO;
168     }
169 
170     if (out_num_read != nullptr) {
171         *out_num_read = num_read;
172     }
173 
174     return AVB_IO_RESULT_OK;
175 }
176 
AvbSlotVerify(const std::string & ab_suffix,bool allow_verification_error,AvbSlotVerifyData ** out_data)177 AvbSlotVerifyResult FsManagerAvbOps::AvbSlotVerify(const std::string& ab_suffix,
178                                                    bool allow_verification_error,
179                                                    AvbSlotVerifyData** out_data) {
180     // Invokes avb_slot_verify() to load and verify all vbmeta images.
181     // Sets requested_partitions to nullptr as it's to copy the contents
182     // of HASH partitions into handle>avb_slot_data_, which is not required as
183     // fs_mgr only deals with HASHTREE partitions.
184     const char* requested_partitions[] = {nullptr};
185     return avb_slot_verify(&avb_ops_, requested_partitions, ab_suffix.c_str(),
186                            allow_verification_error, out_data);
187 }
188