fs_mgr.c revision 28483d7ec497e06850be1d8f87d7fa522c8ab9d4
1/*
2 * Copyright (C) 2012 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#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <unistd.h>
21#include <fcntl.h>
22#include <ctype.h>
23#include <sys/mount.h>
24#include <sys/stat.h>
25#include <errno.h>
26#include <sys/types.h>
27#include <sys/wait.h>
28#include <libgen.h>
29#include <time.h>
30#include <sys/swap.h>
31
32#include <linux/loop.h>
33#include <private/android_filesystem_config.h>
34#include <cutils/partition_utils.h>
35#include <cutils/properties.h>
36#include <logwrap/logwrap.h>
37
38#include "mincrypt/rsa.h"
39#include "mincrypt/sha.h"
40#include "mincrypt/sha256.h"
41
42#include "fs_mgr_priv.h"
43#include "fs_mgr_priv_verity.h"
44
45#define KEY_LOC_PROP   "ro.crypto.keyfile.userdata"
46#define KEY_IN_FOOTER  "footer"
47
48#define E2FSCK_BIN      "/system/bin/e2fsck"
49#define MKSWAP_BIN      "/system/bin/mkswap"
50
51#define FSCK_LOG_FILE   "/dev/fscklogs/log"
52
53#define ZRAM_CONF_DEV   "/sys/block/zram0/disksize"
54
55#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
56
57/*
58 * gettime() - returns the time in seconds of the system's monotonic clock or
59 * zero on error.
60 */
61static time_t gettime(void)
62{
63    struct timespec ts;
64    int ret;
65
66    ret = clock_gettime(CLOCK_MONOTONIC, &ts);
67    if (ret < 0) {
68        ERROR("clock_gettime(CLOCK_MONOTONIC) failed: %s\n", strerror(errno));
69        return 0;
70    }
71
72    return ts.tv_sec;
73}
74
75static int wait_for_file(const char *filename, int timeout)
76{
77    struct stat info;
78    time_t timeout_time = gettime() + timeout;
79    int ret = -1;
80
81    while (gettime() < timeout_time && ((ret = stat(filename, &info)) < 0))
82        usleep(10000);
83
84    return ret;
85}
86
87static void check_fs(char *blk_device, char *fs_type, char *target)
88{
89    int status;
90    int ret;
91    long tmpmnt_flags = MS_NOATIME | MS_NOEXEC | MS_NOSUID;
92    char *tmpmnt_opts = "nomblk_io_submit,errors=remount-ro";
93    char *e2fsck_argv[] = {
94        E2FSCK_BIN,
95        "-y",
96        blk_device
97    };
98
99    /* Check for the types of filesystems we know how to check */
100    if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) {
101        /*
102         * First try to mount and unmount the filesystem.  We do this because
103         * the kernel is more efficient than e2fsck in running the journal and
104         * processing orphaned inodes, and on at least one device with a
105         * performance issue in the emmc firmware, it can take e2fsck 2.5 minutes
106         * to do what the kernel does in about a second.
107         *
108         * After mounting and unmounting the filesystem, run e2fsck, and if an
109         * error is recorded in the filesystem superblock, e2fsck will do a full
110         * check.  Otherwise, it does nothing.  If the kernel cannot mount the
111         * filesytsem due to an error, e2fsck is still run to do a full check
112         * fix the filesystem.
113         */
114        ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts);
115        if (!ret) {
116            umount(target);
117        }
118
119        /*
120         * Some system images do not have e2fsck for licensing reasons
121         * (e.g. recent SDK system images). Detect these and skip the check.
122         */
123        if (access(E2FSCK_BIN, X_OK)) {
124            INFO("Not running %s on %s (executable not in system image)\n",
125                 E2FSCK_BIN, blk_device);
126        } else {
127            INFO("Running %s on %s\n", E2FSCK_BIN, blk_device);
128
129            ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv), e2fsck_argv,
130                                        &status, true, LOG_KLOG | LOG_FILE,
131                                        true, FSCK_LOG_FILE);
132
133            if (ret < 0) {
134                /* No need to check for error in fork, we can't really handle it now */
135                ERROR("Failed trying to run %s\n", E2FSCK_BIN);
136            }
137        }
138    }
139
140    return;
141}
142
143static void remove_trailing_slashes(char *n)
144{
145    int len;
146
147    len = strlen(n) - 1;
148    while ((*(n + len) == '/') && len) {
149      *(n + len) = '\0';
150      len--;
151    }
152}
153
154/*
155 * Mark the given block device as read-only, using the BLKROSET ioctl.
156 * Return 0 on success, and -1 on error.
157 */
158static void fs_set_blk_ro(const char *blockdev)
159{
160    int fd;
161    int ON = 1;
162
163    fd = open(blockdev, O_RDONLY);
164    if (fd < 0) {
165        // should never happen
166        return;
167    }
168
169    ioctl(fd, BLKROSET, &ON);
170    close(fd);
171}
172
173/*
174 * __mount(): wrapper around the mount() system call which also
175 * sets the underlying block device to read-only if the mount is read-only.
176 * See "man 2 mount" for return values.
177 */
178static int __mount(const char *source, const char *target,
179                   const char *filesystemtype, unsigned long mountflags,
180                   const void *data)
181{
182    int ret = mount(source, target, filesystemtype, mountflags, data);
183
184    if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
185        fs_set_blk_ro(source);
186    }
187
188    return ret;
189}
190
191static int fs_match(char *in1, char *in2)
192{
193    char *n1;
194    char *n2;
195    int ret;
196
197    n1 = strdup(in1);
198    n2 = strdup(in2);
199
200    remove_trailing_slashes(n1);
201    remove_trailing_slashes(n2);
202
203    ret = !strcmp(n1, n2);
204
205    free(n1);
206    free(n2);
207
208    return ret;
209}
210
211int fs_mgr_mount_all(struct fstab *fstab)
212{
213    int i = 0;
214    int encrypted = 0;
215    int ret = -1;
216    int mret;
217    int mount_errno;
218
219    if (!fstab) {
220        return ret;
221    }
222
223    for (i = 0; i < fstab->num_entries; i++) {
224        /* Don't mount entries that are managed by vold */
225        if (fstab->recs[i].fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) {
226            continue;
227        }
228
229        /* Skip swap and raw partition entries such as boot, recovery, etc */
230        if (!strcmp(fstab->recs[i].fs_type, "swap") ||
231            !strcmp(fstab->recs[i].fs_type, "emmc") ||
232            !strcmp(fstab->recs[i].fs_type, "mtd")) {
233            continue;
234        }
235
236        if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
237            wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
238        }
239
240        if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
241            check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
242                     fstab->recs[i].mount_point);
243        }
244
245        if (fstab->recs[i].fs_mgr_flags & MF_VERIFY) {
246            if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) {
247                ERROR("Could not set up verified partition, skipping!");
248                continue;
249            }
250        }
251
252        mret = __mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point,
253                     fstab->recs[i].fs_type, fstab->recs[i].flags,
254                     fstab->recs[i].fs_options);
255
256        if (!mret) {
257            /* Success!  Go get the next one */
258            continue;
259        }
260
261        /* back up errno as partition_wipe clobbers the value */
262        mount_errno = errno;
263
264        /* mount(2) returned an error, check if it's encrypted and deal with it */
265        if ((fstab->recs[i].fs_mgr_flags & MF_CRYPT) &&
266            !partition_wiped(fstab->recs[i].blk_device)) {
267            /* Need to mount a tmpfs at this mountpoint for now, and set
268             * properties that vold will query later for decrypting
269             */
270            if (mount("tmpfs", fstab->recs[i].mount_point, "tmpfs",
271                  MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS) < 0) {
272                ERROR("Cannot mount tmpfs filesystem for encrypted fs at %s error: %s\n",
273                        fstab->recs[i].mount_point, strerror(errno));
274                goto out;
275            }
276            encrypted = 1;
277        } else {
278            ERROR("Failed to mount an un-encryptable or wiped partition on"
279                    "%s at %s options: %s error: %s\n",
280                    fstab->recs[i].blk_device, fstab->recs[i].mount_point,
281                    fstab->recs[i].fs_options, strerror(mount_errno));
282            goto out;
283        }
284    }
285
286    if (encrypted) {
287        ret = 1;
288    } else {
289        ret = 0;
290    }
291
292out:
293    return ret;
294}
295
296/* If tmp_mount_point is non-null, mount the filesystem there.  This is for the
297 * tmp mount we do to check the user password
298 */
299int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
300                    char *tmp_mount_point)
301{
302    int i = 0;
303    int ret = -1;
304    char *m;
305
306    if (!fstab) {
307        return ret;
308    }
309
310    for (i = 0; i < fstab->num_entries; i++) {
311        if (!fs_match(fstab->recs[i].mount_point, n_name)) {
312            continue;
313        }
314
315        /* We found our match */
316        /* If this swap or a raw partition, report an error */
317        if (!strcmp(fstab->recs[i].fs_type, "swap") ||
318            !strcmp(fstab->recs[i].fs_type, "emmc") ||
319            !strcmp(fstab->recs[i].fs_type, "mtd")) {
320            ERROR("Cannot mount filesystem of type %s on %s\n",
321                  fstab->recs[i].fs_type, n_blk_device);
322            goto out;
323        }
324
325        /* First check the filesystem if requested */
326        if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
327            wait_for_file(n_blk_device, WAIT_TIMEOUT);
328        }
329
330        if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
331            check_fs(n_blk_device, fstab->recs[i].fs_type,
332                     fstab->recs[i].mount_point);
333        }
334
335        if (fstab->recs[i].fs_mgr_flags & MF_VERIFY) {
336            if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) {
337                ERROR("Could not set up verified partition, skipping!");
338                continue;
339            }
340        }
341
342        /* Now mount it where requested */
343        if (tmp_mount_point) {
344            m = tmp_mount_point;
345        } else {
346            m = fstab->recs[i].mount_point;
347        }
348        if (__mount(n_blk_device, m, fstab->recs[i].fs_type,
349                    fstab->recs[i].flags, fstab->recs[i].fs_options)) {
350            ERROR("Cannot mount filesystem on %s at %s options: %s error: %s\n",
351                n_blk_device, m, fstab->recs[i].fs_options, strerror(errno));
352            goto out;
353        } else {
354            ret = 0;
355            goto out;
356        }
357    }
358
359    /* We didn't find a match, say so and return an error */
360    ERROR("Cannot find mount point %s in fstab\n", fstab->recs[i].mount_point);
361
362out:
363    return ret;
364}
365
366/*
367 * mount a tmpfs filesystem at the given point.
368 * return 0 on success, non-zero on failure.
369 */
370int fs_mgr_do_tmpfs_mount(char *n_name)
371{
372    int ret;
373
374    ret = mount("tmpfs", n_name, "tmpfs",
375                MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS);
376    if (ret < 0) {
377        ERROR("Cannot mount tmpfs filesystem at %s\n", n_name);
378        return -1;
379    }
380
381    /* Success */
382    return 0;
383}
384
385int fs_mgr_unmount_all(struct fstab *fstab)
386{
387    int i = 0;
388    int ret = 0;
389
390    if (!fstab) {
391        return -1;
392    }
393
394    while (fstab->recs[i].blk_device) {
395        if (umount(fstab->recs[i].mount_point)) {
396            ERROR("Cannot unmount filesystem at %s\n", fstab->recs[i].mount_point);
397            ret = -1;
398        }
399        i++;
400    }
401
402    return ret;
403}
404
405/* This must be called after mount_all, because the mkswap command needs to be
406 * available.
407 */
408int fs_mgr_swapon_all(struct fstab *fstab)
409{
410    int i = 0;
411    int flags = 0;
412    int err = 0;
413    int ret = 0;
414    int status;
415    char *mkswap_argv[2] = {
416        MKSWAP_BIN,
417        NULL
418    };
419
420    if (!fstab) {
421        return -1;
422    }
423
424    for (i = 0; i < fstab->num_entries; i++) {
425        /* Skip non-swap entries */
426        if (strcmp(fstab->recs[i].fs_type, "swap")) {
427            continue;
428        }
429
430        if (fstab->recs[i].zram_size > 0) {
431            /* A zram_size was specified, so we need to configure the
432             * device.  There is no point in having multiple zram devices
433             * on a system (all the memory comes from the same pool) so
434             * we can assume the device number is 0.
435             */
436            FILE *zram_fp;
437
438            zram_fp = fopen(ZRAM_CONF_DEV, "r+");
439            if (zram_fp == NULL) {
440                ERROR("Unable to open zram conf device " ZRAM_CONF_DEV);
441                ret = -1;
442                continue;
443            }
444            fprintf(zram_fp, "%d\n", fstab->recs[i].zram_size);
445            fclose(zram_fp);
446        }
447
448        if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
449            wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
450        }
451
452        /* Initialize the swap area */
453        mkswap_argv[1] = fstab->recs[i].blk_device;
454        err = android_fork_execvp_ext(ARRAY_SIZE(mkswap_argv), mkswap_argv,
455                                      &status, true, LOG_KLOG, false, NULL);
456        if (err) {
457            ERROR("mkswap failed for %s\n", fstab->recs[i].blk_device);
458            ret = -1;
459            continue;
460        }
461
462        /* If -1, then no priority was specified in fstab, so don't set
463         * SWAP_FLAG_PREFER or encode the priority */
464        if (fstab->recs[i].swap_prio >= 0) {
465            flags = (fstab->recs[i].swap_prio << SWAP_FLAG_PRIO_SHIFT) &
466                    SWAP_FLAG_PRIO_MASK;
467            flags |= SWAP_FLAG_PREFER;
468        } else {
469            flags = 0;
470        }
471        err = swapon(fstab->recs[i].blk_device, flags);
472        if (err) {
473            ERROR("swapon failed for %s\n", fstab->recs[i].blk_device);
474            ret = -1;
475        }
476    }
477
478    return ret;
479}
480
481/*
482 * key_loc must be at least PROPERTY_VALUE_MAX bytes long
483 *
484 * real_blk_device must be at least PROPERTY_VALUE_MAX bytes long
485 */
486int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, char *real_blk_device, int size)
487{
488    int i = 0;
489
490    if (!fstab) {
491        return -1;
492    }
493    /* Initialize return values to null strings */
494    if (key_loc) {
495        *key_loc = '\0';
496    }
497    if (real_blk_device) {
498        *real_blk_device = '\0';
499    }
500
501    /* Look for the encryptable partition to find the data */
502    for (i = 0; i < fstab->num_entries; i++) {
503        /* Don't deal with vold managed enryptable partitions here */
504        if (fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) {
505            continue;
506        }
507        if (!(fstab->recs[i].fs_mgr_flags & MF_CRYPT)) {
508            continue;
509        }
510
511        /* We found a match */
512        if (key_loc) {
513            strlcpy(key_loc, fstab->recs[i].key_loc, size);
514        }
515        if (real_blk_device) {
516            strlcpy(real_blk_device, fstab->recs[i].blk_device, size);
517        }
518        break;
519    }
520
521    return 0;
522}
523