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