1 /* 2 * Copyright (C) 2017 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_user.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 #include <sys/types.h> 35 #include <unistd.h> 36 37 #include <cutils/properties.h> 38 #include <fs_mgr.h> 39 40 #include <libavb_ab/libavb_ab.h> 41 42 using android::fs_mgr::Fstab; 43 using android::fs_mgr::GetEntryForMountPoint; 44 using android::fs_mgr::ReadDefaultFstab; 45 using android::fs_mgr::ReadFstabFromFile; 46 47 /* Open the appropriate fstab file and fallback to /fstab.device if 48 * that's what's being used. 49 */ 50 static bool open_fstab(Fstab* fstab) { 51 return ReadDefaultFstab(fstab) || ReadFstabFromFile("/fstab.device", fstab); 52 } 53 54 static int open_partition(const char* name, int flags) { 55 char* path; 56 int fd; 57 58 /* Per https://android-review.googlesource.com/c/platform/system/core/+/674989 59 * Android now supports /dev/block/by-name/<partition_name> ... try that 60 * first. 61 */ 62 path = avb_strdupv("/dev/block/by-name/", name, NULL); 63 if (path != NULL) { 64 fd = open(path, flags); 65 avb_free(path); 66 if (fd != -1) { 67 return fd; 68 } 69 } 70 71 /* OK, so /dev/block/by-name/<partition_name> didn't work... so we're 72 * falling back to what we used to do before that: 73 * 74 * We can't use fs_mgr to look up |name| because fstab doesn't list 75 * every slot partition (it uses the slotselect option to mask the 76 * suffix) and |slot| is expected to be of that form, e.g. boot_a. 77 * 78 * We can however assume that there's an entry for the /misc mount 79 * point and use that to get the device file for the misc 80 * partition. From there we'll assume that a by-name scheme is used 81 * so we can just replace the trailing "misc" by the given |name|, 82 * e.g. 83 * 84 * /dev/block/platform/soc.0/7824900.sdhci/by-name/misc -> 85 * /dev/block/platform/soc.0/7824900.sdhci/by-name/boot_a 86 * 87 * If needed, it's possible to relax this assumption in the future 88 * by trawling /sys/block looking for the appropriate sibling of 89 * misc and then finding an entry in /dev matching the sysfs entry. 90 */ 91 92 Fstab fstab; 93 if (!open_fstab(&fstab)) { 94 return -1; 95 } 96 auto record = GetEntryForMountPoint(&fstab, "/misc"); 97 if (record == nullptr) { 98 return -1; 99 } 100 if (strcmp(name, "misc") == 0) { 101 path = strdup(record->blk_device.c_str()); 102 } else { 103 size_t trimmed_len, name_len; 104 const char* end_slash = strrchr(record->blk_device.c_str(), '/'); 105 if (end_slash == NULL) { 106 return -1; 107 } 108 trimmed_len = end_slash - record->blk_device.c_str() + 1; 109 name_len = strlen(name); 110 path = static_cast<char*>(calloc(trimmed_len + name_len + 1, 1)); 111 strncpy(path, record->blk_device.c_str(), trimmed_len); 112 strncpy(path + trimmed_len, name, name_len); 113 } 114 115 fd = open(path, flags); 116 free(path); 117 118 return fd; 119 } 120 121 static AvbIOResult read_from_partition(AvbOps* ops, 122 const char* partition, 123 int64_t offset, 124 size_t num_bytes, 125 void* buffer, 126 size_t* out_num_read) { 127 int fd; 128 off_t where; 129 ssize_t num_read; 130 AvbIOResult ret; 131 132 fd = open_partition(partition, O_RDONLY); 133 if (fd == -1) { 134 ret = AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; 135 goto out; 136 } 137 138 if (offset < 0) { 139 uint64_t partition_size; 140 if (ioctl(fd, BLKGETSIZE64, &partition_size) != 0) { 141 avb_errorv( 142 "Error getting size of \"", partition, "\" partition.\n", NULL); 143 ret = AVB_IO_RESULT_ERROR_IO; 144 goto out; 145 } 146 offset = partition_size - (-offset); 147 } 148 149 where = lseek(fd, offset, SEEK_SET); 150 if (where == -1) { 151 avb_error("Error seeking to offset.\n"); 152 ret = AVB_IO_RESULT_ERROR_IO; 153 goto out; 154 } 155 if (where != offset) { 156 avb_error("Error seeking to offset.\n"); 157 ret = AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION; 158 goto out; 159 } 160 161 /* On Linux, we never get partial reads from block devices (except 162 * for EOF). 163 */ 164 num_read = read(fd, buffer, num_bytes); 165 if (num_read == -1) { 166 avb_error("Error reading data.\n"); 167 ret = AVB_IO_RESULT_ERROR_IO; 168 goto out; 169 } 170 if (out_num_read != NULL) { 171 *out_num_read = num_read; 172 } 173 174 ret = AVB_IO_RESULT_OK; 175 176 out: 177 if (fd != -1) { 178 if (close(fd) != 0) { 179 avb_error("Error closing file descriptor.\n"); 180 } 181 } 182 return ret; 183 } 184 185 static AvbIOResult write_to_partition(AvbOps* ops, 186 const char* partition, 187 int64_t offset, 188 size_t num_bytes, 189 const void* buffer) { 190 int fd; 191 off_t where; 192 ssize_t num_written; 193 AvbIOResult ret; 194 195 fd = open_partition(partition, O_WRONLY); 196 if (fd == -1) { 197 avb_errorv("Error opening \"", partition, "\" partition.\n", NULL); 198 ret = AVB_IO_RESULT_ERROR_IO; 199 goto out; 200 } 201 202 where = lseek(fd, offset, SEEK_SET); 203 if (where == -1) { 204 avb_error("Error seeking to offset.\n"); 205 ret = AVB_IO_RESULT_ERROR_IO; 206 goto out; 207 } 208 if (where != offset) { 209 avb_error("Error seeking to offset.\n"); 210 ret = AVB_IO_RESULT_ERROR_RANGE_OUTSIDE_PARTITION; 211 goto out; 212 } 213 214 /* On Linux, we never get partial writes on block devices. */ 215 num_written = write(fd, buffer, num_bytes); 216 if (num_written == -1) { 217 avb_error("Error writing data.\n"); 218 ret = AVB_IO_RESULT_ERROR_IO; 219 goto out; 220 } 221 222 ret = AVB_IO_RESULT_OK; 223 224 out: 225 if (fd != -1) { 226 if (close(fd) != 0) { 227 avb_error("Error closing file descriptor.\n"); 228 } 229 } 230 return ret; 231 } 232 233 static AvbIOResult validate_vbmeta_public_key( 234 AvbOps* ops, 235 const uint8_t* public_key_data, 236 size_t public_key_length, 237 const uint8_t* public_key_metadata, 238 size_t public_key_metadata_length, 239 bool* out_is_trusted) { 240 if (out_is_trusted != NULL) { 241 *out_is_trusted = true; 242 } 243 return AVB_IO_RESULT_OK; 244 } 245 246 static AvbIOResult read_rollback_index(AvbOps* ops, 247 size_t rollback_index_location, 248 uint64_t* out_rollback_index) { 249 if (out_rollback_index != NULL) { 250 *out_rollback_index = 0; 251 } 252 return AVB_IO_RESULT_OK; 253 } 254 255 static AvbIOResult write_rollback_index(AvbOps* ops, 256 size_t rollback_index_location, 257 uint64_t rollback_index) { 258 return AVB_IO_RESULT_OK; 259 } 260 261 static AvbIOResult read_is_device_unlocked(AvbOps* ops, bool* out_is_unlocked) { 262 if (out_is_unlocked != NULL) { 263 *out_is_unlocked = true; 264 } 265 return AVB_IO_RESULT_OK; 266 } 267 268 static AvbIOResult get_size_of_partition(AvbOps* ops, 269 const char* partition, 270 uint64_t* out_size_in_bytes) { 271 int fd; 272 AvbIOResult ret; 273 274 fd = open_partition(partition, O_WRONLY); 275 if (fd == -1) { 276 avb_errorv("Error opening \"", partition, "\" partition.\n", NULL); 277 ret = AVB_IO_RESULT_ERROR_IO; 278 goto out; 279 } 280 281 if (out_size_in_bytes != NULL) { 282 if (ioctl(fd, BLKGETSIZE64, out_size_in_bytes) != 0) { 283 avb_errorv( 284 "Error getting size of \"", partition, "\" partition.\n", NULL); 285 ret = AVB_IO_RESULT_ERROR_IO; 286 goto out; 287 } 288 } 289 290 ret = AVB_IO_RESULT_OK; 291 292 out: 293 if (fd != -1) { 294 if (close(fd) != 0) { 295 avb_error("Error closing file descriptor.\n"); 296 } 297 } 298 return ret; 299 } 300 301 static AvbIOResult get_unique_guid_for_partition(AvbOps* ops, 302 const char* partition, 303 char* guid_buf, 304 size_t guid_buf_size) { 305 if (guid_buf != NULL && guid_buf_size > 0) { 306 guid_buf[0] = '\0'; 307 } 308 return AVB_IO_RESULT_OK; 309 } 310 311 AvbOps* avb_ops_user_new(void) { 312 AvbOps* ops; 313 314 ops = static_cast<AvbOps*>(calloc(1, sizeof(AvbOps))); 315 if (ops == NULL) { 316 avb_error("Error allocating memory for AvbOps.\n"); 317 goto out; 318 } 319 320 ops->ab_ops = static_cast<AvbABOps*>(calloc(1, sizeof(AvbABOps))); 321 if (ops->ab_ops == NULL) { 322 avb_error("Error allocating memory for AvbABOps.\n"); 323 free(ops); 324 goto out; 325 } 326 ops->ab_ops->ops = ops; 327 328 ops->read_from_partition = read_from_partition; 329 ops->write_to_partition = write_to_partition; 330 ops->validate_vbmeta_public_key = validate_vbmeta_public_key; 331 ops->read_rollback_index = read_rollback_index; 332 ops->write_rollback_index = write_rollback_index; 333 ops->read_is_device_unlocked = read_is_device_unlocked; 334 ops->get_unique_guid_for_partition = get_unique_guid_for_partition; 335 ops->get_size_of_partition = get_size_of_partition; 336 ops->ab_ops->read_ab_metadata = avb_ab_data_read; 337 ops->ab_ops->write_ab_metadata = avb_ab_data_write; 338 339 out: 340 return ops; 341 } 342 343 void avb_ops_user_free(AvbOps* ops) { 344 free(ops->ab_ops); 345 free(ops); 346 } 347