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
write_at_offset(unsigned char * buffer,size_t size,int wfd,off64_t offset)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
add_block_to_ranges(int ** ranges,int * range_alloc,int * range_used,int new_block)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
read_fstab()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
find_block_device(const char * path,bool * encryptable,bool * encrypted)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.
find_uncrypt_package(std::string & 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
produce_block_map(const char * path,const char * map_file,const char * blk_dev,bool encrypted,int status_fd)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
wipe_misc()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
reboot_to_recovery()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
uncrypt(const char * input_path,const char * map_file,int status_fd)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
main(int argc,char ** argv)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