bowgotsai | b51722b | 2017-01-11 22:21:38 +0800 | [diff] [blame] | 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 | |
Bowgo Tsai | 20651f6 | 2017-05-08 20:45:50 +0800 | [diff] [blame] | 25 | #include "fs_mgr_priv_avb_ops.h" |
| 26 | |
bowgotsai | b51722b | 2017-01-11 22:21:38 +0800 | [diff] [blame] | 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" |
bowgotsai | b51722b | 2017-01-11 22:21:38 +0800 | [diff] [blame] | 41 | #include "fs_mgr_priv.h" |
| 42 | |
Bowgo Tsai | 95c966a | 2017-03-30 18:42:54 +0800 | [diff] [blame] | 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); |
bowgotsai | b51722b | 2017-01-11 22:21:38 +0800 | [diff] [blame] | 47 | } |
| 48 | |
Bowgo Tsai | 4caf4c0 | 2017-02-16 21:35:09 +0800 | [diff] [blame] | 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) { |
bowgotsai | b51722b | 2017-01-11 22:21:38 +0800 | [diff] [blame] | 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 | |
| 58 | static AvbIOResult dummy_validate_vbmeta_public_key( |
Bowgo Tsai | 4caf4c0 | 2017-02-16 21:35:09 +0800 | [diff] [blame] | 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) { |
bowgotsai | b51722b | 2017-01-11 22:21:38 +0800 | [diff] [blame] | 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(). |
bowgotsai | b51722b | 2017-01-11 22:21:38 +0800 | [diff] [blame] | 68 | *out_is_trusted = true; |
| 69 | return AVB_IO_RESULT_OK; |
| 70 | } |
| 71 | |
Bowgo Tsai | 4caf4c0 | 2017-02-16 21:35:09 +0800 | [diff] [blame] | 72 | static AvbIOResult dummy_read_is_device_unlocked(AvbOps* ops ATTRIBUTE_UNUSED, |
| 73 | bool* out_is_unlocked) { |
bowgotsai | b51722b | 2017-01-11 22:21:38 +0800 | [diff] [blame] | 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 | |
Bowgo Tsai | 4caf4c0 | 2017-02-16 21:35:09 +0800 | [diff] [blame] | 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) { |
bowgotsai | b51722b | 2017-01-11 22:21:38 +0800 | [diff] [blame] | 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 | |
Bowgo Tsai | 60f19a0 | 2017-06-22 22:23:08 +0800 | [diff] [blame] | 92 | static AvbIOResult dummy_get_size_of_partition(AvbOps* ops ATTRIBUTE_UNUSED, |
| 93 | const char* partition ATTRIBUTE_UNUSED, |
| 94 | uint64_t* out_size_num_byte) { |
| 95 | // The function is for bootloader to load entire content of AVB HASH partitions. |
| 96 | // In user-space, returns 0 as we only need to set up AVB HASHTHREE partitions. |
| 97 | *out_size_num_byte = 0; |
| 98 | return AVB_IO_RESULT_OK; |
| 99 | } |
| 100 | |
Bowgo Tsai | 20651f6 | 2017-05-08 20:45:50 +0800 | [diff] [blame] | 101 | void FsManagerAvbOps::InitializeAvbOps() { |
Bowgo Tsai | 95c966a | 2017-03-30 18:42:54 +0800 | [diff] [blame] | 102 | // We only need to provide the implementation of read_from_partition() |
| 103 | // operation since that's all what is being used by the avb_slot_verify(). |
| 104 | // Other I/O operations are only required in bootloader but not in |
David Zeuthen | 16c6fd1 | 2017-05-01 12:43:34 -0400 | [diff] [blame] | 105 | // user-space so we set them as dummy operations. Also zero the entire |
| 106 | // struct so operations added in the future will be set to NULL. |
| 107 | memset(&avb_ops_, 0, sizeof(AvbOps)); |
Bowgo Tsai | 95c966a | 2017-03-30 18:42:54 +0800 | [diff] [blame] | 108 | avb_ops_.read_from_partition = read_from_partition; |
| 109 | avb_ops_.read_rollback_index = dummy_read_rollback_index; |
| 110 | avb_ops_.validate_vbmeta_public_key = dummy_validate_vbmeta_public_key; |
| 111 | avb_ops_.read_is_device_unlocked = dummy_read_is_device_unlocked; |
| 112 | avb_ops_.get_unique_guid_for_partition = dummy_get_unique_guid_for_partition; |
Bowgo Tsai | 60f19a0 | 2017-06-22 22:23:08 +0800 | [diff] [blame] | 113 | avb_ops_.get_size_of_partition = dummy_get_size_of_partition; |
bowgotsai | b51722b | 2017-01-11 22:21:38 +0800 | [diff] [blame] | 114 | |
Bowgo Tsai | 95c966a | 2017-03-30 18:42:54 +0800 | [diff] [blame] | 115 | // Sets user_data for GetInstanceFromAvbOps() to convert it back to FsManagerAvbOps. |
| 116 | avb_ops_.user_data = this; |
bowgotsai | b51722b | 2017-01-11 22:21:38 +0800 | [diff] [blame] | 117 | } |
| 118 | |
Bowgo Tsai | 20651f6 | 2017-05-08 20:45:50 +0800 | [diff] [blame] | 119 | FsManagerAvbOps::FsManagerAvbOps(std::map<std::string, std::string>&& by_name_symlink_map) |
| 120 | : by_name_symlink_map_(std::move(by_name_symlink_map)) { |
| 121 | InitializeAvbOps(); |
| 122 | } |
| 123 | |
| 124 | FsManagerAvbOps::FsManagerAvbOps(const fstab& fstab) { |
| 125 | // Constructs the by-name symlink map for each fstab record. |
| 126 | // /dev/block/platform/soc.0/7824900.sdhci/by-name/system_a => |
| 127 | // by_name_symlink_map_["system_a"] = "/dev/block/platform/soc.0/7824900.sdhci/by-name/system_a" |
| 128 | for (int i = 0; i < fstab.num_entries; i++) { |
| 129 | std::string partition_name = basename(fstab.recs[i].blk_device); |
| 130 | by_name_symlink_map_[partition_name] = fstab.recs[i].blk_device; |
| 131 | } |
| 132 | InitializeAvbOps(); |
| 133 | } |
| 134 | |
Bowgo Tsai | 95c966a | 2017-03-30 18:42:54 +0800 | [diff] [blame] | 135 | AvbIOResult FsManagerAvbOps::ReadFromPartition(const char* partition, int64_t offset, |
| 136 | size_t num_bytes, void* buffer, |
| 137 | size_t* out_num_read) { |
Bowgo Tsai | 20651f6 | 2017-05-08 20:45:50 +0800 | [diff] [blame] | 138 | const auto iter = by_name_symlink_map_.find(partition); |
| 139 | if (iter == by_name_symlink_map_.end()) { |
| 140 | LERROR << "by-name symlink not found for partition: '" << partition << "'"; |
| 141 | return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; |
| 142 | } |
| 143 | std::string path = iter->second; |
Bowgo Tsai | 95c966a | 2017-03-30 18:42:54 +0800 | [diff] [blame] | 144 | |
Jinguang Dong | 9d34496 | 2017-06-13 10:20:34 +0800 | [diff] [blame] | 145 | // Ensures the device path (a symlink created by init) is ready to access. |
| 146 | if (!fs_mgr_wait_for_file(path, 1s)) { |
Bowgo Tsai | 95c966a | 2017-03-30 18:42:54 +0800 | [diff] [blame] | 147 | return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; |
| 148 | } |
| 149 | |
| 150 | android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC))); |
| 151 | if (fd < 0) { |
Bowgo Tsai | 20651f6 | 2017-05-08 20:45:50 +0800 | [diff] [blame] | 152 | PERROR << "Failed to open " << path; |
Bowgo Tsai | 95c966a | 2017-03-30 18:42:54 +0800 | [diff] [blame] | 153 | return AVB_IO_RESULT_ERROR_IO; |
| 154 | } |
| 155 | |
| 156 | // If offset is negative, interprets its absolute value as the |
| 157 | // number of bytes from the end of the partition. |
| 158 | if (offset < 0) { |
| 159 | off64_t total_size = lseek64(fd, 0, SEEK_END); |
| 160 | if (total_size == -1) { |
Bowgo Tsai | 359bed3 | 2017-04-27 15:44:39 +0800 | [diff] [blame] | 161 | PERROR << "Failed to lseek64 to end of the partition"; |
Bowgo Tsai | 95c966a | 2017-03-30 18:42:54 +0800 | [diff] [blame] | 162 | return AVB_IO_RESULT_ERROR_IO; |
| 163 | } |
| 164 | offset = total_size + offset; |
| 165 | // Repositions the offset to the beginning. |
| 166 | if (lseek64(fd, 0, SEEK_SET) == -1) { |
Bowgo Tsai | 359bed3 | 2017-04-27 15:44:39 +0800 | [diff] [blame] | 167 | PERROR << "Failed to lseek64 to the beginning of the partition"; |
Bowgo Tsai | 95c966a | 2017-03-30 18:42:54 +0800 | [diff] [blame] | 168 | return AVB_IO_RESULT_ERROR_IO; |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | // On Linux, we never get partial reads from block devices (except |
| 173 | // for EOF). |
| 174 | ssize_t num_read = TEMP_FAILURE_RETRY(pread64(fd, buffer, num_bytes, offset)); |
| 175 | if (num_read < 0 || (size_t)num_read != num_bytes) { |
Bowgo Tsai | 20651f6 | 2017-05-08 20:45:50 +0800 | [diff] [blame] | 176 | PERROR << "Failed to read " << num_bytes << " bytes from " << path << " offset " << offset; |
Bowgo Tsai | 95c966a | 2017-03-30 18:42:54 +0800 | [diff] [blame] | 177 | return AVB_IO_RESULT_ERROR_IO; |
| 178 | } |
| 179 | |
| 180 | if (out_num_read != nullptr) { |
| 181 | *out_num_read = num_read; |
| 182 | } |
| 183 | |
| 184 | return AVB_IO_RESULT_OK; |
| 185 | } |
| 186 | |
| 187 | AvbSlotVerifyResult FsManagerAvbOps::AvbSlotVerify(const std::string& ab_suffix, |
David Zeuthen | 7ea2c28 | 2017-05-10 15:43:37 -0400 | [diff] [blame] | 188 | AvbSlotVerifyFlags flags, |
Bowgo Tsai | 95c966a | 2017-03-30 18:42:54 +0800 | [diff] [blame] | 189 | AvbSlotVerifyData** out_data) { |
| 190 | // Invokes avb_slot_verify() to load and verify all vbmeta images. |
| 191 | // Sets requested_partitions to nullptr as it's to copy the contents |
| 192 | // of HASH partitions into handle>avb_slot_data_, which is not required as |
| 193 | // fs_mgr only deals with HASHTREE partitions. |
| 194 | const char* requested_partitions[] = {nullptr}; |
David Zeuthen | 7ea2c28 | 2017-05-10 15:43:37 -0400 | [diff] [blame] | 195 | // The |hashtree_error_mode| field doesn't matter as it only |
| 196 | // influences the generated kernel cmdline parameters. |
| 197 | return avb_slot_verify(&avb_ops_, requested_partitions, ab_suffix.c_str(), flags, |
| 198 | AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE, out_data); |
Bowgo Tsai | 95c966a | 2017-03-30 18:42:54 +0800 | [diff] [blame] | 199 | } |