1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 // This program takes a file on an ext4 filesystem and produces a list 18 // of the blocks that file occupies, which enables the file contents 19 // to be read directly from the block device without mounting the 20 // filesystem. 21 // 22 // If the filesystem is using an encrypted block device, it will also 23 // read the file and rewrite it to the same blocks of the underlying 24 // (unencrypted) block device, so the file contents can be read 25 // without the need for the decryption key. 26 // 27 // The output of this program is a "block map" which looks like this: 28 // 29 // /dev/block/platform/msm_sdcc.1/by-name/userdata # block device 30 // 49652 4096 # file size in bytes, block size 31 // 3 # count of block ranges 32 // 1000 1008 # block range 0 33 // 2100 2102 # ... block range 1 34 // 30 33 # ... block range 2 35 // 36 // Each block range represents a half-open interval; the line "30 33" 37 // reprents the blocks [30, 31, 32]. 38 // 39 // Recovery can take this block map file and retrieve the underlying 40 // file data to use as an update package. 41 42 #include <errno.h> 43 #include <fcntl.h> 44 #include <linux/fs.h> 45 #include <stdarg.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <sys/mman.h> 50 #include <sys/stat.h> 51 #include <sys/types.h> 52 #include <unistd.h> 53 54 #include <base/file.h> 55 #include <base/strings.h> 56 #include <cutils/properties.h> 57 #include <fs_mgr.h> 58 #define LOG_TAG "uncrypt" 59 #include <log/log.h> 60 61 #define WINDOW_SIZE 5 62 63 static const std::string cache_block_map = "/cache/recovery/block.map"; 64 static const std::string status_file = "/cache/recovery/uncrypt_status"; 65 static const std::string uncrypt_file = "/cache/recovery/uncrypt_file"; 66 67 static struct fstab* fstab = NULL; 68 69 static int write_at_offset(unsigned char* buffer, size_t size, int wfd, off64_t offset) { 70 if (TEMP_FAILURE_RETRY(lseek64(wfd, offset, SEEK_SET)) == -1) { 71 ALOGE("error seeking to offset %lld: %s\n", offset, strerror(errno)); 72 return -1; 73 } 74 size_t written = 0; 75 while (written < size) { 76 ssize_t wrote = TEMP_FAILURE_RETRY(write(wfd, buffer + written, size - written)); 77 if (wrote == -1) { 78 ALOGE("error writing offset %lld: %s\n", (offset + written), strerror(errno)); 79 return -1; 80 } 81 written += wrote; 82 } 83 return 0; 84 } 85 86 static void add_block_to_ranges(int** ranges, int* range_alloc, int* range_used, int new_block) { 87 // If the current block start is < 0, set the start to the new 88 // block. (This only happens for the very first block of the very 89 // first range.) 90 if ((*ranges)[*range_used*2-2] < 0) { 91 (*ranges)[*range_used*2-2] = new_block; 92 (*ranges)[*range_used*2-1] = new_block; 93 } 94 95 if (new_block == (*ranges)[*range_used*2-1]) { 96 // If the new block comes immediately after the current range, 97 // all we have to do is extend the current range. 98 ++(*ranges)[*range_used*2-1]; 99 } else { 100 // We need to start a new range. 101 102 // If there isn't enough room in the array, we need to expand it. 103 if (*range_used >= *range_alloc) { 104 *range_alloc *= 2; 105 *ranges = reinterpret_cast<int*>(realloc(*ranges, *range_alloc * 2 * sizeof(int))); 106 } 107 108 ++*range_used; 109 (*ranges)[*range_used*2-2] = new_block; 110 (*ranges)[*range_used*2-1] = new_block+1; 111 } 112 } 113 114 static struct fstab* read_fstab() { 115 fstab = NULL; 116 117 // The fstab path is always "/fstab.${ro.hardware}". 118 char fstab_path[PATH_MAX+1] = "/fstab."; 119 if (!property_get("ro.hardware", fstab_path+strlen(fstab_path), "")) { 120 ALOGE("failed to get ro.hardware\n"); 121 return NULL; 122 } 123 124 fstab = fs_mgr_read_fstab(fstab_path); 125 if (!fstab) { 126 ALOGE("failed to read %s\n", fstab_path); 127 return NULL; 128 } 129 130 return fstab; 131 } 132 133 static const char* find_block_device(const char* path, bool* encryptable, bool* encrypted) { 134 // Look for a volume whose mount point is the prefix of path and 135 // return its block device. Set encrypted if it's currently 136 // encrypted. 137 for (int i = 0; i < fstab->num_entries; ++i) { 138 struct fstab_rec* v = &fstab->recs[i]; 139 if (!v->mount_point) { 140 continue; 141 } 142 int len = strlen(v->mount_point); 143 if (strncmp(path, v->mount_point, len) == 0 && 144 (path[len] == '/' || path[len] == 0)) { 145 *encrypted = false; 146 *encryptable = false; 147 if (fs_mgr_is_encryptable(v)) { 148 *encryptable = true; 149 char buffer[PROPERTY_VALUE_MAX+1]; 150 if (property_get("ro.crypto.state", buffer, "") && 151 strcmp(buffer, "encrypted") == 0) { 152 *encrypted = true; 153 } 154 } 155 return v->blk_device; 156 } 157 } 158 159 return NULL; 160 } 161 162 // Parse uncrypt_file to find the update package name. 163 static bool find_uncrypt_package(std::string& package_name) 164 { 165 if (!android::base::ReadFileToString(uncrypt_file, &package_name)) { 166 ALOGE("failed to open \"%s\": %s\n", uncrypt_file.c_str(), strerror(errno)); 167 return false; 168 } 169 170 // Remove the trailing '\n' if present. 171 package_name = android::base::Trim(package_name); 172 173 return true; 174 } 175 176 static int produce_block_map(const char* path, const char* map_file, const char* blk_dev, 177 bool encrypted, int status_fd) { 178 int mapfd = open(map_file, O_WRONLY | O_CREAT | O_SYNC, S_IRUSR | S_IWUSR); 179 if (mapfd == -1) { 180 ALOGE("failed to open %s\n", map_file); 181 return -1; 182 } 183 FILE* mapf = fdopen(mapfd, "w"); 184 185 // Make sure we can write to the status_file. 186 if (!android::base::WriteStringToFd("0\n", status_fd)) { 187 ALOGE("failed to update \"%s\"\n", status_file.c_str()); 188 return -1; 189 } 190 191 struct stat sb; 192 int ret = stat(path, &sb); 193 if (ret != 0) { 194 ALOGE("failed to stat %s\n", path); 195 return -1; 196 } 197 198 ALOGI(" block size: %ld bytes\n", (long)sb.st_blksize); 199 200 int blocks = ((sb.st_size-1) / sb.st_blksize) + 1; 201 ALOGI(" file size: %lld bytes, %d blocks\n", (long long)sb.st_size, blocks); 202 203 int range_alloc = 1; 204 int range_used = 1; 205 int* ranges = reinterpret_cast<int*>(malloc(range_alloc * 2 * sizeof(int))); 206 ranges[0] = -1; 207 ranges[1] = -1; 208 209 fprintf(mapf, "%s\n%lld %lu\n", blk_dev, (long long)sb.st_size, (unsigned long)sb.st_blksize); 210 211 unsigned char* buffers[WINDOW_SIZE]; 212 if (encrypted) { 213 for (size_t i = 0; i < WINDOW_SIZE; ++i) { 214 buffers[i] = reinterpret_cast<unsigned char*>(malloc(sb.st_blksize)); 215 } 216 } 217 int head_block = 0; 218 int head = 0, tail = 0; 219 size_t pos = 0; 220 221 int fd = open(path, O_RDONLY); 222 if (fd < 0) { 223 ALOGE("failed to open fd for reading: %s\n", strerror(errno)); 224 return -1; 225 } 226 227 int wfd = -1; 228 if (encrypted) { 229 wfd = open(blk_dev, O_WRONLY | O_SYNC); 230 if (wfd < 0) { 231 ALOGE("failed to open fd for writing: %s\n", strerror(errno)); 232 return -1; 233 } 234 } 235 236 int last_progress = 0; 237 while (pos < sb.st_size) { 238 // Update the status file, progress must be between [0, 99]. 239 int progress = static_cast<int>(100 * (double(pos) / double(sb.st_size))); 240 if (progress > last_progress) { 241 last_progress = progress; 242 android::base::WriteStringToFd(std::to_string(progress) + "\n", status_fd); 243 } 244 245 if ((tail+1) % WINDOW_SIZE == head) { 246 // write out head buffer 247 int block = head_block; 248 ret = ioctl(fd, FIBMAP, &block); 249 if (ret != 0) { 250 ALOGE("failed to find block %d\n", head_block); 251 return -1; 252 } 253 add_block_to_ranges(&ranges, &range_alloc, &range_used, block); 254 if (encrypted) { 255 if (write_at_offset(buffers[head], sb.st_blksize, wfd, 256 (off64_t)sb.st_blksize * block) != 0) { 257 return -1; 258 } 259 } 260 head = (head + 1) % WINDOW_SIZE; 261 ++head_block; 262 } 263 264 // read next block to tail 265 if (encrypted) { 266 size_t so_far = 0; 267 while (so_far < sb.st_blksize && pos < sb.st_size) { 268 ssize_t this_read = 269 TEMP_FAILURE_RETRY(read(fd, buffers[tail] + so_far, sb.st_blksize - so_far)); 270 if (this_read == -1) { 271 ALOGE("failed to read: %s\n", strerror(errno)); 272 return -1; 273 } 274 so_far += this_read; 275 pos += this_read; 276 } 277 } else { 278 // If we're not encrypting; we don't need to actually read 279 // anything, just skip pos forward as if we'd read a 280 // block. 281 pos += sb.st_blksize; 282 } 283 tail = (tail+1) % WINDOW_SIZE; 284 } 285 286 while (head != tail) { 287 // write out head buffer 288 int block = head_block; 289 ret = ioctl(fd, FIBMAP, &block); 290 if (ret != 0) { 291 ALOGE("failed to find block %d\n", head_block); 292 return -1; 293 } 294 add_block_to_ranges(&ranges, &range_alloc, &range_used, block); 295 if (encrypted) { 296 if (write_at_offset(buffers[head], sb.st_blksize, wfd, 297 (off64_t)sb.st_blksize * block) != 0) { 298 return -1; 299 } 300 } 301 head = (head + 1) % WINDOW_SIZE; 302 ++head_block; 303 } 304 305 fprintf(mapf, "%d\n", range_used); 306 for (int i = 0; i < range_used; ++i) { 307 fprintf(mapf, "%d %d\n", ranges[i*2], ranges[i*2+1]); 308 } 309 310 if (fsync(mapfd) == -1) { 311 ALOGE("failed to fsync \"%s\": %s\n", map_file, strerror(errno)); 312 return -1; 313 } 314 fclose(mapf); 315 close(fd); 316 if (encrypted) { 317 if (fsync(wfd) == -1) { 318 ALOGE("failed to fsync \"%s\": %s\n", blk_dev, strerror(errno)); 319 return -1; 320 } 321 close(wfd); 322 } 323 324 return 0; 325 } 326 327 static void wipe_misc() { 328 ALOGI("removing old commands from misc"); 329 for (int i = 0; i < fstab->num_entries; ++i) { 330 struct fstab_rec* v = &fstab->recs[i]; 331 if (!v->mount_point) continue; 332 if (strcmp(v->mount_point, "/misc") == 0) { 333 int fd = open(v->blk_device, O_WRONLY | O_SYNC); 334 uint8_t zeroes[1088]; // sizeof(bootloader_message) from recovery 335 memset(zeroes, 0, sizeof(zeroes)); 336 337 size_t written = 0; 338 size_t size = sizeof(zeroes); 339 while (written < size) { 340 ssize_t w = TEMP_FAILURE_RETRY(write(fd, zeroes, size-written)); 341 if (w == -1) { 342 ALOGE("zero write failed: %s\n", strerror(errno)); 343 return; 344 } else { 345 written += w; 346 } 347 } 348 if (fsync(fd) == -1) { 349 ALOGE("failed to fsync \"%s\": %s\n", v->blk_device, strerror(errno)); 350 close(fd); 351 return; 352 } 353 close(fd); 354 } 355 } 356 } 357 358 static void reboot_to_recovery() { 359 ALOGI("rebooting to recovery"); 360 property_set("sys.powerctl", "reboot,recovery"); 361 sleep(10); 362 ALOGE("reboot didn't succeed?"); 363 } 364 365 int uncrypt(const char* input_path, const char* map_file, int status_fd) { 366 367 ALOGI("update package is \"%s\"", input_path); 368 369 // Turn the name of the file we're supposed to convert into an 370 // absolute path, so we can find what filesystem it's on. 371 char path[PATH_MAX+1]; 372 if (realpath(input_path, path) == NULL) { 373 ALOGE("failed to convert \"%s\" to absolute path: %s", input_path, strerror(errno)); 374 return 1; 375 } 376 377 if (read_fstab() == NULL) { 378 return 1; 379 } 380 381 bool encryptable; 382 bool encrypted; 383 const char* blk_dev = find_block_device(path, &encryptable, &encrypted); 384 if (blk_dev == NULL) { 385 ALOGE("failed to find block device for %s", path); 386 return 1; 387 } 388 389 // If the filesystem it's on isn't encrypted, we only produce the 390 // block map, we don't rewrite the file contents (it would be 391 // pointless to do so). 392 ALOGI("encryptable: %s\n", encryptable ? "yes" : "no"); 393 ALOGI(" encrypted: %s\n", encrypted ? "yes" : "no"); 394 395 // Recovery supports installing packages from 3 paths: /cache, 396 // /data, and /sdcard. (On a particular device, other locations 397 // may work, but those are three we actually expect.) 398 // 399 // On /data we want to convert the file to a block map so that we 400 // can read the package without mounting the partition. On /cache 401 // and /sdcard we leave the file alone. 402 if (strncmp(path, "/data/", 6) == 0) { 403 ALOGI("writing block map %s", map_file); 404 if (produce_block_map(path, map_file, blk_dev, encrypted, status_fd) != 0) { 405 return 1; 406 } 407 } 408 409 return 0; 410 } 411 412 int main(int argc, char** argv) { 413 const char* input_path; 414 const char* map_file; 415 416 if (argc != 3 && argc != 1 && (argc == 2 && strcmp(argv[1], "--reboot") != 0)) { 417 fprintf(stderr, "usage: %s [--reboot] [<transform_path> <map_file>]\n", argv[0]); 418 return 2; 419 } 420 421 // When uncrypt is started with "--reboot", it wipes misc and reboots. 422 // Otherwise it uncrypts the package and writes the block map. 423 if (argc == 2) { 424 if (read_fstab() == NULL) { 425 return 1; 426 } 427 wipe_misc(); 428 reboot_to_recovery(); 429 } else { 430 // The pipe has been created by the system server. 431 int status_fd = open(status_file.c_str(), O_WRONLY | O_CREAT | O_SYNC, S_IRUSR | S_IWUSR); 432 if (status_fd == -1) { 433 ALOGE("failed to open pipe \"%s\": %s\n", status_file.c_str(), strerror(errno)); 434 return 1; 435 } 436 437 if (argc == 3) { 438 // when command-line args are given this binary is being used 439 // for debugging. 440 input_path = argv[1]; 441 map_file = argv[2]; 442 } else { 443 std::string package; 444 if (!find_uncrypt_package(package)) { 445 android::base::WriteStringToFd("-1\n", status_fd); 446 close(status_fd); 447 return 1; 448 } 449 input_path = package.c_str(); 450 map_file = cache_block_map.c_str(); 451 } 452 453 int status = uncrypt(input_path, map_file, status_fd); 454 if (status != 0) { 455 android::base::WriteStringToFd("-1\n", status_fd); 456 close(status_fd); 457 return 1; 458 } 459 460 android::base::WriteStringToFd("100\n", status_fd); 461 close(status_fd); 462 } 463 464 return 0; 465 } 466