fs_mgr_verity.c 26.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

Elliott Hughes's avatar
Elliott Hughes committed
17
#include <inttypes.h>
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <libgen.h>
#include <time.h>

#include <private/android_filesystem_config.h>
33
#include <cutils/properties.h>
34 35 36 37 38 39
#include <logwrap/logwrap.h>

#include "mincrypt/rsa.h"
#include "mincrypt/sha.h"
#include "mincrypt/sha256.h"

40
#include "ext4_sb.h"
41
#include "squashfs_utils.h"
42 43 44 45

#include "fs_mgr_priv.h"
#include "fs_mgr_priv_verity.h"

46 47
#define FSTAB_PREFIX "/fstab."

48 49 50
#define VERITY_METADATA_SIZE 32768
#define VERITY_TABLE_RSA_KEY "/verity_key"

51 52 53 54
#define METADATA_MAGIC 0x01564c54
#define METADATA_TAG_MAX_LENGTH 63
#define METADATA_EOD "eod"

55 56
#define VERITY_LASTSIG_TAG "verity_lastsig"

57
#define VERITY_STATE_TAG "verity_state"
58 59 60 61 62 63
#define VERITY_STATE_HEADER 0x83c0ae9d
#define VERITY_STATE_VERSION 1

#define VERITY_KMSG_RESTART "dm-verity device corrupted"
#define VERITY_KMSG_BUFSIZE 1024

64 65 66
#define __STRINGIFY(x) #x
#define STRINGIFY(x) __STRINGIFY(x)

67 68 69 70 71 72
struct verity_state {
    uint32_t header;
    uint32_t version;
    int32_t mode;
};

73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
extern struct fs_info info;

static RSAPublicKey *load_key(char *path)
{
    FILE *f;
    RSAPublicKey *key;

    key = malloc(sizeof(RSAPublicKey));
    if (!key) {
        ERROR("Can't malloc key\n");
        return NULL;
    }

    f = fopen(path, "r");
    if (!f) {
        ERROR("Can't open '%s'\n", path);
        free(key);
        return NULL;
    }

    if (!fread(key, sizeof(*key), 1, f)) {
        ERROR("Could not read key!");
        fclose(f);
        free(key);
        return NULL;
    }

    if (key->len != RSANUMWORDS) {
        ERROR("Invalid key length %d\n", key->len);
        fclose(f);
        free(key);
        return NULL;
    }

    fclose(f);
    return key;
}

static int verify_table(char *signature, char *table, int table_length)
{
    RSAPublicKey *key;
114
    uint8_t hash_buf[SHA256_DIGEST_SIZE];
115 116 117
    int retval = -1;

    // Hash the table
118
    SHA256_hash((uint8_t*)table, table_length, hash_buf);
119 120 121 122 123 124 125 126 127 128 129 130 131

    // Now get the public key from the keyfile
    key = load_key(VERITY_TABLE_RSA_KEY);
    if (!key) {
        ERROR("Couldn't load verity keys");
        goto out;
    }

    // verify the result
    if (!RSA_verify(key,
                    (uint8_t*) signature,
                    RSANUMBYTES,
                    (uint8_t*) hash_buf,
132
                    SHA256_DIGEST_SIZE)) {
133 134 135 136 137 138 139 140 141 142 143
        ERROR("Couldn't verify table.");
        goto out;
    }

    retval = 0;

out:
    free(key);
    return retval;
}

144 145 146 147 148 149 150 151 152 153 154 155 156
static int squashfs_get_target_device_size(char *blk_device, uint64_t *device_size)
{
    struct squashfs_info sq_info;

    if (squashfs_parse_sb(blk_device, &sq_info) >= 0) {
        *device_size = sq_info.bytes_used_4K_padded;
        return 0;
    } else {
        return -1;
    }
}

static int ext4_get_target_device_size(char *blk_device, uint64_t *device_size)
157 158 159
{
    int data_device;
    struct ext4_super_block sb;
160 161 162
    struct fs_info info;

    info.len = 0;  /* Only len is set to 0 to ask the device for real size. */
163

164 165
    data_device = TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC));
    if (data_device == -1) {
166 167 168 169
        ERROR("Error opening block device (%s)", strerror(errno));
        return -1;
    }

170
    if (TEMP_FAILURE_RETRY(lseek64(data_device, 1024, SEEK_SET)) < 0) {
171
        ERROR("Error seeking to superblock");
172
        close(data_device);
173 174 175
        return -1;
    }

176
    if (TEMP_FAILURE_RETRY(read(data_device, &sb, sizeof(sb))) != sizeof(sb)) {
177
        ERROR("Error reading superblock");
178
        close(data_device);
179 180 181
        return -1;
    }

182
    ext4_parse_sb(&sb, &info);
183 184
    *device_size = info.len;

185
    close(data_device);
186 187 188
    return 0;
}

189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
static int get_fs_size(char *fs_type, char *blk_device, uint64_t *device_size) {
    if (!strcmp(fs_type, "ext4")) {
        if (ext4_get_target_device_size(blk_device, device_size) < 0) {
            ERROR("Failed to get ext4 fs size on %s.", blk_device);
            return -1;
        }
    } else if (!strcmp(fs_type, "squashfs")) {
        if (squashfs_get_target_device_size(blk_device, device_size) < 0) {
            ERROR("Failed to get squashfs fs size on %s.", blk_device);
            return -1;
        }
    } else {
        ERROR("%s: Unsupported filesystem for verity.", fs_type);
        return -1;
    }
    return 0;
}

static int read_verity_metadata(uint64_t device_size, char *block_device, char **signature,
        char **table)
209 210 211 212
{
    unsigned magic_number;
    unsigned table_length;
    int protocol_version;
213
    int device;
214
    int retval = FS_MGR_SETUP_VERITY_FAIL;
215 216 217 218 219 220

    *signature = NULL;

    if (table) {
        *table = NULL;
    }
221

222 223
    device = TEMP_FAILURE_RETRY(open(block_device, O_RDONLY | O_CLOEXEC));
    if (device == -1) {
224 225 226 227
        ERROR("Could not open block device %s (%s).\n", block_device, strerror(errno));
        goto out;
    }

228
    if (TEMP_FAILURE_RETRY(lseek64(device, device_size, SEEK_SET)) < 0) {
229 230 231 232 233
        ERROR("Could not seek to start of verity metadata block.\n");
        goto out;
    }

    // check the magic number
234 235
    if (TEMP_FAILURE_RETRY(read(device, &magic_number, sizeof(magic_number))) !=
            sizeof(magic_number)) {
236 237 238
        ERROR("Couldn't read magic number!\n");
        goto out;
    }
239 240 241 242 243 244 245 246 247

#ifdef ALLOW_ADBD_DISABLE_VERITY
    if (magic_number == VERITY_METADATA_MAGIC_DISABLE) {
        retval = FS_MGR_SETUP_VERITY_DISABLED;
        INFO("Attempt to cleanly disable verity - only works in USERDEBUG");
        goto out;
    }
#endif

248
    if (magic_number != VERITY_METADATA_MAGIC_NUMBER) {
249
        ERROR("Couldn't find verity metadata at offset %"PRIu64"!\n", device_size);
250 251 252 253
        goto out;
    }

    // check the protocol version
254 255
    if (TEMP_FAILURE_RETRY(read(device, &protocol_version,
            sizeof(protocol_version))) != sizeof(protocol_version)) {
256 257 258 259 260 261 262 263 264
        ERROR("Couldn't read verity metadata protocol version!\n");
        goto out;
    }
    if (protocol_version != 0) {
        ERROR("Got unknown verity metadata protocol version %d!\n", protocol_version);
        goto out;
    }

    // get the signature
265
    *signature = (char*) malloc(RSANUMBYTES);
266 267 268 269
    if (!*signature) {
        ERROR("Couldn't allocate memory for signature!\n");
        goto out;
    }
270
    if (TEMP_FAILURE_RETRY(read(device, *signature, RSANUMBYTES)) != RSANUMBYTES) {
271 272 273 274
        ERROR("Couldn't read signature from verity metadata!\n");
        goto out;
    }

275 276 277 278 279
    if (!table) {
        retval = FS_MGR_SETUP_VERITY_SUCCESS;
        goto out;
    }

280
    // get the size of the table
281 282
    if (TEMP_FAILURE_RETRY(read(device, &table_length, sizeof(table_length))) !=
            sizeof(table_length)) {
283 284 285 286 287
        ERROR("Couldn't get the size of the verity table from metadata!\n");
        goto out;
    }

    // get the table + null terminator
288 289
    *table = malloc(table_length + 1);
    if (!*table) {
290 291 292
        ERROR("Couldn't allocate memory for verity table!\n");
        goto out;
    }
293 294
    if (TEMP_FAILURE_RETRY(read(device, *table, table_length)) !=
            (ssize_t)table_length) {
295 296 297 298
        ERROR("Couldn't read the verity table from metadata!\n");
        goto out;
    }

299
    (*table)[table_length] = 0;
300
    retval = FS_MGR_SETUP_VERITY_SUCCESS;
301 302

out:
303
    if (device != -1)
304
        close(device);
305 306 307

    if (retval != FS_MGR_SETUP_VERITY_SUCCESS) {
        free(*signature);
308 309 310 311 312 313
        *signature = NULL;

        if (table) {
            free(*table);
            *table = NULL;
        }
314 315
    }

316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
    return retval;
}

static void verity_ioctl_init(struct dm_ioctl *io, char *name, unsigned flags)
{
    memset(io, 0, DM_BUF_SIZE);
    io->data_size = DM_BUF_SIZE;
    io->data_start = sizeof(struct dm_ioctl);
    io->version[0] = 4;
    io->version[1] = 0;
    io->version[2] = 0;
    io->flags = flags | DM_READONLY_FLAG;
    if (name) {
        strlcpy(io->name, name, sizeof(io->name));
    }
}

static int create_verity_device(struct dm_ioctl *io, char *name, int fd)
{
    verity_ioctl_init(io, name, 1);
    if (ioctl(fd, DM_DEV_CREATE, io)) {
        ERROR("Error creating device mapping (%s)", strerror(errno));
        return -1;
    }
    return 0;
}

static int get_verity_device_name(struct dm_ioctl *io, char *name, int fd, char **dev_name)
{
    verity_ioctl_init(io, name, 0);
    if (ioctl(fd, DM_DEV_STATUS, io)) {
        ERROR("Error fetching verity device number (%s)", strerror(errno));
        return -1;
    }
    int dev_num = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
    if (asprintf(dev_name, "/dev/block/dm-%u", dev_num) < 0) {
        ERROR("Error getting verity block device name (%s)", strerror(errno));
        return -1;
    }
    return 0;
}

358
static int load_verity_table(struct dm_ioctl *io, char *name, uint64_t device_size, int fd, char *table,
359
        int mode)
360 361 362
{
    char *verity_params;
    char *buffer = (char*) io;
363
    size_t bufsize;
364 365 366 367 368 369 370 371 372 373 374 375 376 377

    verity_ioctl_init(io, name, DM_STATUS_TABLE_FLAG);

    struct dm_target_spec *tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];

    // set tgt arguments here
    io->target_count = 1;
    tgt->status=0;
    tgt->sector_start=0;
    tgt->length=device_size/512;
    strcpy(tgt->target_type, "verity");

    // build the verity params here
    verity_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
378 379 380 381 382 383 384 385 386 387 388
    bufsize = DM_BUF_SIZE - (verity_params - buffer);

    if (mode == VERITY_MODE_EIO) {
        // allow operation with older dm-verity drivers that are unaware
        // of the mode parameter by omitting it; this also means that we
        // cannot use logging mode with these drivers, they always cause
        // an I/O error for corrupted blocks
        strcpy(verity_params, table);
    } else if (snprintf(verity_params, bufsize, "%s %d", table, mode) < 0) {
        return -1;
    }
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424

    // set next target boundary
    verity_params += strlen(verity_params) + 1;
    verity_params = (char*) (((unsigned long)verity_params + 7) & ~8);
    tgt->next = verity_params - buffer;

    // send the ioctl to load the verity table
    if (ioctl(fd, DM_TABLE_LOAD, io)) {
        ERROR("Error loading verity table (%s)", strerror(errno));
        return -1;
    }

    return 0;
}

static int resume_verity_table(struct dm_ioctl *io, char *name, int fd)
{
    verity_ioctl_init(io, name, 0);
    if (ioctl(fd, DM_DEV_SUSPEND, io)) {
        ERROR("Error activating verity device (%s)", strerror(errno));
        return -1;
    }
    return 0;
}

static int test_access(char *device) {
    int tries = 25;
    while (tries--) {
        if (!access(device, F_OK) || errno != ENOENT) {
            return 0;
        }
        usleep(40 * 1000);
    }
    return -1;
}

425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
static int check_verity_restart(const char *fname)
{
    char buffer[VERITY_KMSG_BUFSIZE + 1];
    int fd;
    int rc = 0;
    ssize_t size;
    struct stat s;

    fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));

    if (fd == -1) {
        if (errno != ENOENT) {
            ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
        }
        goto out;
    }

    if (fstat(fd, &s) == -1) {
        ERROR("Failed to fstat %s (%s)\n", fname, strerror(errno));
        goto out;
    }

    size = VERITY_KMSG_BUFSIZE;

    if (size > s.st_size) {
        size = s.st_size;
    }

    if (lseek(fd, s.st_size - size, SEEK_SET) == -1) {
Andreas Gampe's avatar
Andreas Gampe committed
454
        ERROR("Failed to lseek %jd %s (%s)\n", (intmax_t)(s.st_size - size), fname,
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
            strerror(errno));
        goto out;
    }

    if (TEMP_FAILURE_RETRY(read(fd, buffer, size)) != size) {
        ERROR("Failed to read %zd bytes from %s (%s)\n", size, fname,
            strerror(errno));
        goto out;
    }

    buffer[size] = '\0';

    if (strstr(buffer, VERITY_KMSG_RESTART) != NULL) {
        rc = 1;
    }

out:
    if (fd != -1) {
473
        close(fd);
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
    }

    return rc;
}

static int was_verity_restart()
{
    static const char *files[] = {
        "/sys/fs/pstore/console-ramoops",
        "/proc/last_kmsg",
        NULL
    };
    int i;

    for (i = 0; files[i]; ++i) {
        if (check_verity_restart(files[i])) {
            return 1;
        }
    }

    return 0;
}

497 498
static int metadata_add(FILE *fp, long start, const char *tag,
        unsigned int length, off64_t *offset)
499
{
Sami Tolvanen's avatar
Sami Tolvanen committed
500 501
    if (fseek(fp, start, SEEK_SET) < 0 ||
        fprintf(fp, "%s %u\n", tag, length) < 0) {
502 503 504 505 506
        return -1;
    }

    *offset = ftell(fp);

Sami Tolvanen's avatar
Sami Tolvanen committed
507 508
    if (fseek(fp, length, SEEK_CUR) < 0 ||
        fprintf(fp, METADATA_EOD " 0\n") < 0) {
509 510 511 512 513 514 515 516 517 518 519
        return -1;
    }

    return 0;
}

static int metadata_find(const char *fname, const char *stag,
        unsigned int slength, off64_t *offset)
{
    FILE *fp = NULL;
    char tag[METADATA_TAG_MAX_LENGTH + 1];
520
    int rc = -1;
521 522 523 524
    int n;
    long start = 0x4000; /* skip cryptfs metadata area */
    uint32_t magic;
    unsigned int length = 0;
525

526 527 528
    if (!fname) {
        return -1;
    }
529

Sami Tolvanen's avatar
Sami Tolvanen committed
530
    fp = fopen(fname, "r+");
531

532
    if (!fp) {
533 534 535 536
        ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
        goto out;
    }

537
    /* check magic */
Sami Tolvanen's avatar
Sami Tolvanen committed
538 539
    if (fseek(fp, start, SEEK_SET) < 0 ||
        fread(&magic, sizeof(magic), 1, fp) != 1) {
540
        ERROR("Failed to read magic from %s (%s)\n", fname, strerror(errno));
541 542 543
        goto out;
    }

544 545 546
    if (magic != METADATA_MAGIC) {
        magic = METADATA_MAGIC;

Sami Tolvanen's avatar
Sami Tolvanen committed
547 548
        if (fseek(fp, start, SEEK_SET) < 0 ||
            fwrite(&magic, sizeof(magic), 1, fp) != 1) {
549 550 551 552 553 554 555 556 557
            ERROR("Failed to write magic to %s (%s)\n", fname, strerror(errno));
            goto out;
        }

        rc = metadata_add(fp, start + sizeof(magic), stag, slength, offset);
        if (rc < 0) {
            ERROR("Failed to add metadata to %s: %s\n", fname, strerror(errno));
        }

558 559 560
        goto out;
    }

561 562 563
    start += sizeof(magic);

    while (1) {
Sami Tolvanen's avatar
Sami Tolvanen committed
564 565
        n = fscanf(fp, "%" STRINGIFY(METADATA_TAG_MAX_LENGTH) "s %u\n",
                tag, &length);
566 567 568 569 570 571 572 573 574 575 576 577 578

        if (n == 2 && strcmp(tag, METADATA_EOD)) {
            /* found a tag */
            start = ftell(fp);

            if (!strcmp(tag, stag) && length == slength) {
                *offset = start;
                rc = 0;
                goto out;
            }

            start += length;

Sami Tolvanen's avatar
Sami Tolvanen committed
579
            if (fseek(fp, length, SEEK_CUR) < 0) {
580 581 582 583 584 585 586 587 588 589 590 591
                ERROR("Failed to seek %s (%s)\n", fname, strerror(errno));
                goto out;
            }
        } else {
            rc = metadata_add(fp, start, stag, slength, offset);
            if (rc < 0) {
                ERROR("Failed to write metadata to %s: %s\n", fname,
                    strerror(errno));
            }
            goto out;
        }
   }
592 593

out:
594
    if (fp) {
Sami Tolvanen's avatar
Sami Tolvanen committed
595 596
        fflush(fp);
        fclose(fp);
597 598 599 600 601
    }

    return rc;
}

602
static int write_verity_state(const char *fname, off64_t offset, int32_t mode)
603
{
604 605 606
    int fd;
    int rc = -1;
    struct verity_state s = { VERITY_STATE_HEADER, VERITY_STATE_VERSION, mode };
607

608
    fd = TEMP_FAILURE_RETRY(open(fname, O_WRONLY | O_SYNC | O_CLOEXEC));
609

610 611 612
    if (fd == -1) {
        ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
        goto out;
613 614
    }

615 616 617 618 619
    if (TEMP_FAILURE_RETRY(pwrite64(fd, &s, sizeof(s), offset)) != sizeof(s)) {
        ERROR("Failed to write %zu bytes to %s to offset %" PRIu64 " (%s)\n",
            sizeof(s), fname, offset, strerror(errno));
        goto out;
    }
620

621
    rc = 0;
622

623 624
out:
    if (fd != -1) {
625
        close(fd);
626 627
    }

628
    return rc;
629 630
}

631
static int read_verity_state(const char *fname, off64_t offset, int *mode)
632 633 634 635 636
{
    int fd = -1;
    int rc = -1;
    struct verity_state s;

637
    fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
638 639

    if (fd == -1) {
640
        ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
641 642 643
        goto out;
    }

644 645
    if (TEMP_FAILURE_RETRY(pread64(fd, &s, sizeof(s), offset)) != sizeof(s)) {
        ERROR("Failed to read %zu bytes from %s offset %" PRIu64 " (%s)\n",
646
            sizeof(s), fname, offset, strerror(errno));
647 648 649 650
        goto out;
    }

    if (s.header != VERITY_STATE_HEADER) {
651 652
        /* space allocated, but no state written. write default state */
        *mode = VERITY_MODE_DEFAULT;
653
        rc = write_verity_state(fname, offset, *mode);
654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672
        goto out;
    }

    if (s.version != VERITY_STATE_VERSION) {
        ERROR("Unsupported verity state version (%u)\n", s.version);
        goto out;
    }

    if (s.mode < VERITY_MODE_EIO ||
        s.mode > VERITY_MODE_LAST) {
        ERROR("Unsupported verity mode (%u)\n", s.mode);
        goto out;
    }

    *mode = s.mode;
    rc = 0;

out:
    if (fd != -1) {
673
        close(fd);
674 675 676 677 678
    }

    return rc;
}

679 680 681 682 683 684 685 686 687
static int compare_last_signature(struct fstab_rec *fstab, int *match)
{
    char tag[METADATA_TAG_MAX_LENGTH + 1];
    char *signature = NULL;
    int fd = -1;
    int rc = -1;
    uint8_t curr[SHA256_DIGEST_SIZE];
    uint8_t prev[SHA256_DIGEST_SIZE];
    off64_t offset = 0;
688
    uint64_t device_size;
689 690 691

    *match = 1;

692 693 694 695 696 697 698
    // get verity filesystem size
    if (get_fs_size(fstab->fs_type, fstab->blk_device, &device_size) < 0) {
        ERROR("Failed to get filesystem size\n");
        goto out;
    }

    if (read_verity_metadata(device_size, fstab->blk_device, &signature, NULL) < 0) {
699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
        ERROR("Failed to read verity signature from %s\n", fstab->mount_point);
        goto out;
    }

    SHA256_hash(signature, RSANUMBYTES, curr);

    if (snprintf(tag, sizeof(tag), VERITY_LASTSIG_TAG "_%s",
            basename(fstab->mount_point)) >= (int)sizeof(tag)) {
        ERROR("Metadata tag name too long for %s\n", fstab->mount_point);
        goto out;
    }

    if (metadata_find(fstab->verity_loc, tag, SHA256_DIGEST_SIZE,
            &offset) < 0) {
        goto out;
    }

    fd = TEMP_FAILURE_RETRY(open(fstab->verity_loc, O_RDWR | O_SYNC | O_CLOEXEC));

    if (fd == -1) {
        ERROR("Failed to open %s: %s\n", fstab->verity_loc, strerror(errno));
        goto out;
    }

    if (TEMP_FAILURE_RETRY(pread64(fd, prev, sizeof(prev),
            offset)) != sizeof(prev)) {
        ERROR("Failed to read %zu bytes from %s offset %" PRIu64 " (%s)\n",
            sizeof(prev), fstab->verity_loc, offset, strerror(errno));
        goto out;
    }

    *match = !memcmp(curr, prev, SHA256_DIGEST_SIZE);

    if (!*match) {
        /* update current signature hash */
        if (TEMP_FAILURE_RETRY(pwrite64(fd, curr, sizeof(curr),
                offset)) != sizeof(curr)) {
            ERROR("Failed to write %zu bytes to %s offset %" PRIu64 " (%s)\n",
                sizeof(curr), fstab->verity_loc, offset, strerror(errno));
            goto out;
        }
    }

    rc = 0;

out:
    free(signature);

    if (fd != -1) {
748
        close(fd);
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
    }

    return rc;
}

static int get_verity_state_offset(struct fstab_rec *fstab, off64_t *offset)
{
    char tag[METADATA_TAG_MAX_LENGTH + 1];

    if (snprintf(tag, sizeof(tag), VERITY_STATE_TAG "_%s",
            basename(fstab->mount_point)) >= (int)sizeof(tag)) {
        ERROR("Metadata tag name too long for %s\n", fstab->mount_point);
        return -1;
    }

    return metadata_find(fstab->verity_loc, tag, sizeof(struct verity_state),
                offset);
}

768 769
static int load_verity_state(struct fstab_rec *fstab, int *mode)
{
770
    char propbuf[PROPERTY_VALUE_MAX];
771
    int match = 0;
772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787
    off64_t offset = 0;

    /* use the kernel parameter if set */
    property_get("ro.boot.veritymode", propbuf, "");

    if (*propbuf != '\0') {
        if (!strcmp(propbuf, "enforcing")) {
            *mode = VERITY_MODE_DEFAULT;
            return 0;
        } else if (!strcmp(propbuf, "logging")) {
            *mode = VERITY_MODE_LOGGING;
            return 0;
        } else {
            INFO("Unknown value %s for veritymode; ignoring", propbuf);
        }
    }
788

789
    if (get_verity_state_offset(fstab, &offset) < 0) {
790 791 792 793 794 795 796 797 798 799 800 801
        /* fall back to stateless behavior */
        *mode = VERITY_MODE_EIO;
        return 0;
    }

    if (was_verity_restart()) {
        /* device was restarted after dm-verity detected a corrupted
         * block, so switch to logging mode */
        *mode = VERITY_MODE_LOGGING;
        return write_verity_state(fstab->verity_loc, offset, *mode);
    }

802 803 804 805 806 807
    if (!compare_last_signature(fstab, &match) && !match) {
        /* partition has been reflashed, reset dm-verity state */
        *mode = VERITY_MODE_DEFAULT;
        return write_verity_state(fstab->verity_loc, offset, *mode);
    }

808 809 810
    return read_verity_state(fstab->verity_loc, offset, mode);
}

811 812 813 814 815 816
int fs_mgr_load_verity_state(int *mode)
{
    char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
    char propbuf[PROPERTY_VALUE_MAX];
    int rc = -1;
    int i;
817
    int current;
818 819
    struct fstab *fstab = NULL;

820 821
    /* return the default mode, unless any of the verified partitions are in
     * logging mode, in which case return that */
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838
    *mode = VERITY_MODE_DEFAULT;

    property_get("ro.hardware", propbuf, "");
    snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);

    fstab = fs_mgr_read_fstab(fstab_filename);

    if (!fstab) {
        ERROR("Failed to read %s\n", fstab_filename);
        goto out;
    }

    for (i = 0; i < fstab->num_entries; i++) {
        if (!fs_mgr_is_verified(&fstab->recs[i])) {
            continue;
        }

839
        rc = load_verity_state(&fstab->recs[i], &current);
840 841 842 843
        if (rc < 0) {
            continue;
        }

844 845
        if (current == VERITY_MODE_LOGGING) {
            *mode = current;
846 847 848 849 850 851 852 853 854 855 856 857 858
        }
    }

    rc = 0;

out:
    if (fstab) {
        fs_mgr_free_fstab(fstab);
    }

    return rc;
}

859
int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback)
860 861 862 863 864 865 866 867
{
    _Alignas(struct dm_ioctl) char buffer[DM_BUF_SIZE];
    char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
    char *mount_point;
    char propbuf[PROPERTY_VALUE_MAX];
    char *status;
    int fd = -1;
    int i;
868
    int mode;
869 870 871 872 873
    int rc = -1;
    off64_t offset = 0;
    struct dm_ioctl *io = (struct dm_ioctl *) buffer;
    struct fstab *fstab = NULL;

874 875 876 877 878 879 880
    /* check if we need to store the state */
    property_get("ro.boot.veritymode", propbuf, "");

    if (*propbuf != '\0') {
        return 0; /* state is kept by the bootloader */
    }

881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
    fd = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));

    if (fd == -1) {
        ERROR("Error opening device mapper (%s)\n", strerror(errno));
        goto out;
    }

    property_get("ro.hardware", propbuf, "");
    snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);

    fstab = fs_mgr_read_fstab(fstab_filename);

    if (!fstab) {
        ERROR("Failed to read %s\n", fstab_filename);
        goto out;
    }

    for (i = 0; i < fstab->num_entries; i++) {
        if (!fs_mgr_is_verified(&fstab->recs[i])) {
            continue;
        }

903 904
        if (get_verity_state_offset(&fstab->recs[i], &offset) < 0 ||
            read_verity_state(fstab->recs[i].verity_loc, offset, &mode) < 0) {
905 906 907
            continue;
        }

908 909 910 911 912 913
        mount_point = basename(fstab->recs[i].mount_point);
        verity_ioctl_init(io, mount_point, 0);

        if (ioctl(fd, DM_TABLE_STATUS, io)) {
            ERROR("Failed to query DM_TABLE_STATUS for %s (%s)\n", mount_point,
                strerror(errno));
914
            continue;
915 916 917 918 919
        }

        status = &buffer[io->data_start + sizeof(struct dm_target_spec)];

        if (*status == 'C') {
920 921 922
            if (write_verity_state(fstab->recs[i].verity_loc, offset,
                    VERITY_MODE_LOGGING) < 0) {
                continue;
923 924 925 926
            }
        }

        if (callback) {
927
            callback(&fstab->recs[i], mount_point, mode, *status);
928 929 930 931 932 933 934 935 936 937 938
        }
    }

    rc = 0;

out:
    if (fstab) {
        fs_mgr_free_fstab(fstab);
    }

    if (fd) {
939
        close(fd);
940 941 942 943 944
    }

    return rc;
}

945 946
int fs_mgr_setup_verity(struct fstab_rec *fstab) {

947
    int retval = FS_MGR_SETUP_VERITY_FAIL;
948
    int fd = -1;
949
    int mode;
950

951 952 953
    char *verity_blk_name = 0;
    char *verity_table = 0;
    char *verity_table_signature = 0;
954
    uint64_t device_size = 0;
955

956
    _Alignas(struct dm_ioctl) char buffer[DM_BUF_SIZE];
957 958 959 960 961 962 963
    struct dm_ioctl *io = (struct dm_ioctl *) buffer;
    char *mount_point = basename(fstab->mount_point);

    // set the dm_ioctl flags
    io->flags |= 1;
    io->target_count = 1;

964 965
    // get verity filesystem size
    if (get_fs_size(fstab->fs_type, fstab->blk_device, &device_size) < 0) {
966 967 968
        return retval;
    }

969 970
    // read the verity block at the end of the block device
    // send error code up the chain so we can detect attempts to disable verity
971 972
    retval = read_verity_metadata(device_size,
                                  fstab->blk_device,
973 974 975 976 977 978
                                  &verity_table_signature,
                                  &verity_table);
    if (retval < 0) {
        goto out;
    }

979 980
    retval = FS_MGR_SETUP_VERITY_FAIL;

981 982 983
    // get the device mapper fd
    if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
        ERROR("Error opening device mapper (%s)", strerror(errno));
Paul Lawrence's avatar
Paul Lawrence committed
984
        goto out;
985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
    }

    // create the device
    if (create_verity_device(io, mount_point, fd) < 0) {
        ERROR("Couldn't create verity device!");
        goto out;
    }

    // get the name of the device file
    if (get_verity_device_name(io, mount_point, fd, &verity_blk_name) < 0) {
        ERROR("Couldn't get verity device number!");
        goto out;
    }

    // verify the signature on the table
    if (verify_table(verity_table_signature,
                            verity_table,
                            strlen(verity_table)) < 0) {
        goto out;
    }

1006 1007 1008 1009 1010 1011
    if (load_verity_state(fstab, &mode) < 0) {
        /* if accessing or updating the state failed, switch to the default
         * safe mode. This makes sure the device won't end up in an endless
         * restart loop, and no corrupted data will be exposed to userspace
         * without a warning. */
        mode = VERITY_MODE_EIO;
1012 1013
    }

1014 1015
    INFO("Enabling dm-verity for %s (mode %d)\n",  mount_point, mode);

1016
    // load the verity mapping table
1017
    if (load_verity_table(io, mount_point, device_size, fd, verity_table,
1018
            mode) < 0) {
1019 1020 1021 1022 1023 1024 1025 1026
        goto out;
    }

    // activate the device
    if (resume_verity_table(io, mount_point, fd) < 0) {
        goto out;
    }

1027 1028 1029
    // mark the underlying block device as read-only
    fs_mgr_set_blk_ro(fstab->blk_device);

1030 1031 1032
    // assign the new verity block device as the block device
    free(fstab->blk_device);
    fstab->blk_device = verity_blk_name;
1033
    verity_blk_name = 0;
1034 1035 1036 1037 1038 1039

    // make sure we've set everything up properly
    if (test_access(fstab->blk_device) < 0) {
        goto out;
    }

1040
    retval = FS_MGR_SETUP_VERITY_SUCCESS;
1041 1042

out:
1043 1044 1045 1046
    if (fd != -1) {
        close(fd);
    }

Paul Lawrence's avatar
Paul Lawrence committed
1047 1048 1049
    free(verity_table);
    free(verity_table_signature);
    free(verity_blk_name);
1050

1051 1052
    return retval;
}