13ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra/*
23ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra * Copyright (C) 2013 The Android Open Source Project
33ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra *
43ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra * Licensed under the Apache License, Version 2.0 (the "License");
53ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra * you may not use this file except in compliance with the License.
63ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra * You may obtain a copy of the License at
73ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra *
83ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra *      http://www.apache.org/licenses/LICENSE-2.0
93ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra *
103ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra * Unless required by applicable law or agreed to in writing, software
113ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra * distributed under the License is distributed on an "AS IS" BASIS,
123ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra * See the License for the specific language governing permissions and
143ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra * limitations under the License.
153ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra */
163ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
17097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler#include <ctype.h>
18097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler#include <errno.h>
19097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler#include <fcntl.h>
20ccecf1425412beb2bc3bb38d470293fdc244d6f1Elliott Hughes#include <inttypes.h>
21097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler#include <libgen.h>
223ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <stdio.h>
233ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <stdlib.h>
243ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <string.h>
253ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <sys/mount.h>
263ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <sys/stat.h>
273ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <sys/types.h>
283ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <sys/wait.h>
293ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <time.h>
30097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler#include <unistd.h>
313ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
324f71319df011d796a60a43fc1bc68e16fbf7d321Elliott Hughes#include <android-base/file.h>
337ad3159db9be8fcb7246fbb750884f5a9edf368fBowgo Tsai#include <android-base/properties.h>
34dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella#include <android-base/strings.h>
352cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani#include <android-base/unique_fd.h>
36097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler#include <crypto_utils/android_pubkey.h>
3705699b3e3e05b976a3de50a634b18a6f5109cf95Geremy Condra#include <cutils/properties.h>
383ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include <logwrap/logwrap.h>
39097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler#include <openssl/obj_mac.h>
40097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler#include <openssl/rsa.h>
41097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler#include <openssl/sha.h>
423ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
4399e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen#include "fec/io.h"
443ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
45246c18caf5193e2243dfcbf434e6340039b64f8cElliott Hughes#include "fs_mgr.h"
463ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#include "fs_mgr_priv.h"
473de625d109f47e04bf7bf9d0db3cfc9f2718964dbowgotsai#include "fs_mgr_priv_dm_ioctl.h"
483ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
493ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra#define VERITY_TABLE_RSA_KEY "/verity_key"
501ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen#define VERITY_TABLE_HASH_IDX 8
511ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen#define VERITY_TABLE_SALT_IDX 9
523ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
5399e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen#define VERITY_TABLE_OPT_RESTART "restart_on_corruption"
5499e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen#define VERITY_TABLE_OPT_LOGGING "ignore_corruption"
5599e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen#define VERITY_TABLE_OPT_IGNZERO "ignore_zero_blocks"
5699e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen
5799e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen#define VERITY_TABLE_OPT_FEC_FORMAT \
5899e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    "use_fec_from_device %s fec_start %" PRIu64 " fec_blocks %" PRIu64 \
5999e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    " fec_roots %u " VERITY_TABLE_OPT_IGNZERO
6099e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen#define VERITY_TABLE_OPT_FEC_ARGS 9
6199e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen
62946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen#define METADATA_MAGIC 0x01564c54
63946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen#define METADATA_TAG_MAX_LENGTH 63
64946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen#define METADATA_EOD "eod"
65946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen
666122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen#define VERITY_LASTSIG_TAG "verity_lastsig"
676122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen
68946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen#define VERITY_STATE_TAG "verity_state"
6951bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen#define VERITY_STATE_HEADER 0x83c0ae9d
7051bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen#define VERITY_STATE_VERSION 1
7151bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
7251bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen#define VERITY_KMSG_RESTART "dm-verity device corrupted"
7351bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen#define VERITY_KMSG_BUFSIZE 1024
7451bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
752cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani#define READ_BUF_SIZE 4096
762cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani
77946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen#define __STRINGIFY(x) #x
78946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen#define STRINGIFY(x) __STRINGIFY(x)
79946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen
8051bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanenstruct verity_state {
8151bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    uint32_t header;
8251bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    uint32_t version;
8351bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    int32_t mode;
8451bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen};
8551bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
863ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condraextern struct fs_info info;
873ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
88097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nisslerstatic RSA *load_key(const char *path)
893ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra{
90097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler    uint8_t key_data[ANDROID_PUBKEY_ENCODED_SIZE];
913ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
92246c18caf5193e2243dfcbf434e6340039b64f8cElliott Hughes    FILE* f = fopen(path, "r");
933ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    if (!f) {
9447878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        LERROR << "Can't open " << path;
953ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra        return NULL;
963ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    }
973ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
98097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler    if (!fread(key_data, sizeof(key_data), 1, f)) {
9947878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        LERROR << "Could not read key!";
1003ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra        fclose(f);
1013ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra        return NULL;
1023ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    }
1033ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
104097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler    fclose(f);
105097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler
106097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler    RSA* key = NULL;
107097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler    if (!android_pubkey_decode(key_data, sizeof(key_data), &key)) {
10847878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        LERROR << "Could not parse key!";
1093ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra        return NULL;
1103ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    }
1113ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
1123ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    return key;
1133ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra}
1143ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
115097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nisslerstatic int verify_table(const uint8_t *signature, size_t signature_size,
116097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler        const char *table, uint32_t table_length)
1173ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra{
118097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler    RSA *key;
119097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler    uint8_t hash_buf[SHA256_DIGEST_LENGTH];
1203ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    int retval = -1;
1213ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
1223ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    // Hash the table
123097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler    SHA256((uint8_t*)table, table_length, hash_buf);
1243ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
1253ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    // Now get the public key from the keyfile
1263ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    key = load_key(VERITY_TABLE_RSA_KEY);
1273ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    if (!key) {
12847878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        LERROR << "Couldn't load verity keys";
1293ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra        goto out;
1303ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    }
1313ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
1323ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    // verify the result
133097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler    if (!RSA_verify(NID_sha256, hash_buf, sizeof(hash_buf), signature,
134097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler                    signature_size, key)) {
13547878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        LERROR << "Couldn't verify table";
1363ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra        goto out;
1373ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    }
1383ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
1393ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    retval = 0;
1403ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
1413ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condraout:
142097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler    RSA_free(key);
1433ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    return retval;
1443ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra}
1453ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
146830126637ae4e5198df075fba57c1e498624dab6Sami Tolvanenstatic int verify_verity_signature(const struct fec_verity_metadata& verity)
147830126637ae4e5198df075fba57c1e498624dab6Sami Tolvanen{
1484171b2b72423d0f6555ee4638dbfb7d95b023996Sami Tolvanen    if (verify_table(verity.signature, sizeof(verity.signature),
1494171b2b72423d0f6555ee4638dbfb7d95b023996Sami Tolvanen            verity.table, verity.table_length) == 0 ||
1504171b2b72423d0f6555ee4638dbfb7d95b023996Sami Tolvanen        verify_table(verity.ecc_signature, sizeof(verity.ecc_signature),
1514171b2b72423d0f6555ee4638dbfb7d95b023996Sami Tolvanen            verity.table, verity.table_length) == 0) {
152830126637ae4e5198df075fba57c1e498624dab6Sami Tolvanen        return 0;
153830126637ae4e5198df075fba57c1e498624dab6Sami Tolvanen    }
154830126637ae4e5198df075fba57c1e498624dab6Sami Tolvanen
155830126637ae4e5198df075fba57c1e498624dab6Sami Tolvanen    return -1;
156830126637ae4e5198df075fba57c1e498624dab6Sami Tolvanen}
157830126637ae4e5198df075fba57c1e498624dab6Sami Tolvanen
15899e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanenstatic int invalidate_table(char *table, size_t table_length)
1591ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen{
16099e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    size_t n = 0;
16199e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    size_t idx = 0;
16299e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    size_t cleared = 0;
1631ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen
1641ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen    while (n < table_length) {
1651ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen        if (table[n++] == ' ') {
1661ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen            ++idx;
1671ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen        }
1681ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen
1691ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen        if (idx != VERITY_TABLE_HASH_IDX && idx != VERITY_TABLE_SALT_IDX) {
1701ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen            continue;
1711ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen        }
1721ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen
1731ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen        while (n < table_length && table[n] != ' ') {
1741ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen            table[n++] = '0';
1751ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen        }
1761ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen
1771ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen        if (++cleared == 2) {
1781ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen            return 0;
1791ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen        }
1801ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen    }
1811ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen
1821ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen    return -1;
1831ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen}
1841ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen
18599e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanenstruct verity_table_params {
186dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella    char *table;
18799e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    int mode;
18899e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    struct fec_ecc_metadata ecc;
18999e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    const char *ecc_dev;
19099e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen};
19199e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen
19299e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanentypedef bool (*format_verity_table_func)(char *buf, const size_t bufsize,
19399e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen        const struct verity_table_params *params);
19499e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen
19599e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanenstatic bool format_verity_table(char *buf, const size_t bufsize,
19699e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen        const struct verity_table_params *params)
19799e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen{
19899e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    const char *mode_flag = NULL;
19999e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    int res = -1;
20099e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen
20199e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    if (params->mode == VERITY_MODE_RESTART) {
20299e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen        mode_flag = VERITY_TABLE_OPT_RESTART;
20399e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    } else if (params->mode == VERITY_MODE_LOGGING) {
20499e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen        mode_flag = VERITY_TABLE_OPT_LOGGING;
20599e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    }
20699e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen
20799e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    if (params->ecc.valid) {
20899e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen        if (mode_flag) {
20999e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen            res = snprintf(buf, bufsize,
21099e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen                    "%s %u %s " VERITY_TABLE_OPT_FEC_FORMAT,
21199e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen                    params->table, 1 + VERITY_TABLE_OPT_FEC_ARGS, mode_flag, params->ecc_dev,
21299e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen                    params->ecc.start / FEC_BLOCKSIZE, params->ecc.blocks, params->ecc.roots);
21399e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen        } else {
21499e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen            res = snprintf(buf, bufsize,
21599e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen                    "%s %u " VERITY_TABLE_OPT_FEC_FORMAT,
21699e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen                    params->table, VERITY_TABLE_OPT_FEC_ARGS, params->ecc_dev,
21799e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen                    params->ecc.start / FEC_BLOCKSIZE, params->ecc.blocks, params->ecc.roots);
21899e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen        }
21999e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    } else if (mode_flag) {
22099e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen        res = snprintf(buf, bufsize, "%s 2 " VERITY_TABLE_OPT_IGNZERO " %s", params->table,
22199e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen                    mode_flag);
22299e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    } else {
223ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen        res = snprintf(buf, bufsize, "%s 1 " VERITY_TABLE_OPT_IGNZERO, params->table);
22499e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    }
22599e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen
22699e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    if (res < 0 || (size_t)res >= bufsize) {
22747878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        LERROR << "Error building verity table; insufficient buffer size?";
22899e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen        return false;
22999e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    }
23099e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen
23199e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    return true;
23299e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen}
23399e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen
23499e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanenstatic bool format_legacy_verity_table(char *buf, const size_t bufsize,
23599e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen        const struct verity_table_params *params)
23699e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen{
23799e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    int res;
23899e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen
23999e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    if (params->mode == VERITY_MODE_EIO) {
24099e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen        res = strlcpy(buf, params->table, bufsize);
24199e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    } else {
24299e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen        res = snprintf(buf, bufsize, "%s %d", params->table, params->mode);
24399e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    }
24499e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen
24599e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    if (res < 0 || (size_t)res >= bufsize) {
24647878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        LERROR << "Error building verity table; insufficient buffer size?";
24799e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen        return false;
24899e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    }
24999e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen
25099e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    return true;
25199e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen}
25299e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen
25347aa2a75201b9cb53c6464304b82db492073d622bowgotsaistatic int load_verity_table(struct dm_ioctl *io, const std::string &name,
25447aa2a75201b9cb53c6464304b82db492073d622bowgotsai                             uint64_t device_size, int fd,
25599e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen        const struct verity_table_params *params, format_verity_table_func format)
2563ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra{
2573ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    char *verity_params;
2583ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    char *buffer = (char*) io;
25951bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    size_t bufsize;
2603ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
2613de625d109f47e04bf7bf9d0db3cfc9f2718964dbowgotsai    fs_mgr_verity_ioctl_init(io, name, DM_STATUS_TABLE_FLAG);
2623ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
2633ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    struct dm_target_spec *tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
2643ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
26599e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    // set tgt arguments
2663ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    io->target_count = 1;
26799e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    tgt->status = 0;
26899e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    tgt->sector_start = 0;
26999e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    tgt->length = device_size / 512;
2703ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    strcpy(tgt->target_type, "verity");
2713ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
27299e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    // build the verity params
2733ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    verity_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
27451bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    bufsize = DM_BUF_SIZE - (verity_params - buffer);
27551bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
27699e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    if (!format(verity_params, bufsize, params)) {
27747878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        LERROR << "Failed to format verity parameters";
27851bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        return -1;
27951bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    }
2803ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
28147878de7d12c7e438fcc584183b44893e91b4a28bowgotsai    LINFO << "loading verity table: '" << verity_params << "'";
28299e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen
2833ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    // set next target boundary
2843ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    verity_params += strlen(verity_params) + 1;
285ce25baf06fe8ba80b0a4c7ff65fba9e1b1b7a67fbowgotsai    verity_params = (char*)(((uintptr_t)verity_params + 7) & ~7);
2863ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    tgt->next = verity_params - buffer;
2873ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
2883ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    // send the ioctl to load the verity table
2893ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    if (ioctl(fd, DM_TABLE_LOAD, io)) {
29047878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        PERROR << "Error loading verity table";
2913ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra        return -1;
2923ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    }
2933ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
2943ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    return 0;
2953ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra}
2963ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
29751bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanenstatic int check_verity_restart(const char *fname)
29851bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen{
29951bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    char buffer[VERITY_KMSG_BUFSIZE + 1];
30051bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    int fd;
30151bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    int rc = 0;
30251bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    ssize_t size;
30351bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    struct stat s;
30451bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
30551bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
30651bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
30751bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    if (fd == -1) {
30851bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        if (errno != ENOENT) {
30947878de7d12c7e438fcc584183b44893e91b4a28bowgotsai            PERROR << "Failed to open " << fname;
31051bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        }
31151bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        goto out;
31251bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    }
31351bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
31451bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    if (fstat(fd, &s) == -1) {
31547878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        PERROR << "Failed to fstat " << fname;
31651bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        goto out;
31751bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    }
31851bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
31951bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    size = VERITY_KMSG_BUFSIZE;
32051bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
32151bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    if (size > s.st_size) {
32251bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        size = s.st_size;
32351bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    }
32451bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
32551bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    if (lseek(fd, s.st_size - size, SEEK_SET) == -1) {
32647878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        PERROR << "Failed to lseek " << (intmax_t)(s.st_size - size) << " " << fname;
32751bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        goto out;
32851bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    }
32951bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
33067b3cad9a0de47f0afd5aaf9471661383acd2531Johan Redestig    if (!android::base::ReadFully(fd, buffer, size)) {
33147878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        PERROR << "Failed to read " << size << " bytes from " << fname;
33251bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        goto out;
33351bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    }
33451bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
33551bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    buffer[size] = '\0';
33651bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
33751bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    if (strstr(buffer, VERITY_KMSG_RESTART) != NULL) {
33851bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        rc = 1;
33951bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    }
34051bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
34151bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanenout:
34251bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    if (fd != -1) {
34347b0134ec2b5e8c8b5b5671cd4a3e41261275532Elliott Hughes        close(fd);
34451bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    }
34551bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
34651bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    return rc;
34751bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen}
34851bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
34951bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanenstatic int was_verity_restart()
35051bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen{
351cab56c0ba53bf702a7df10eb39755af0b5525088Mark Salyzyn    static const char* files[] = {
352cab56c0ba53bf702a7df10eb39755af0b5525088Mark Salyzyn        // clang-format off
353cab56c0ba53bf702a7df10eb39755af0b5525088Mark Salyzyn        "/sys/fs/pstore/console-ramoops-0",
35451bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        "/sys/fs/pstore/console-ramoops",
35551bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        "/proc/last_kmsg",
35651bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        NULL
357cab56c0ba53bf702a7df10eb39755af0b5525088Mark Salyzyn        // clang-format on
35851bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    };
35951bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    int i;
36051bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
36151bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    for (i = 0; files[i]; ++i) {
36251bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        if (check_verity_restart(files[i])) {
36351bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen            return 1;
36451bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        }
36551bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    }
36651bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
36751bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    return 0;
36851bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen}
36951bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
370946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanenstatic int metadata_add(FILE *fp, long start, const char *tag,
371946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen        unsigned int length, off64_t *offset)
37251bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen{
3734d3ead9d7c08d2bb0f3af2166b72f57e6e1755e0Sami Tolvanen    if (fseek(fp, start, SEEK_SET) < 0 ||
3744d3ead9d7c08d2bb0f3af2166b72f57e6e1755e0Sami Tolvanen        fprintf(fp, "%s %u\n", tag, length) < 0) {
375946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen        return -1;
376946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    }
377946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen
378946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    *offset = ftell(fp);
379946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen
3804d3ead9d7c08d2bb0f3af2166b72f57e6e1755e0Sami Tolvanen    if (fseek(fp, length, SEEK_CUR) < 0 ||
3814d3ead9d7c08d2bb0f3af2166b72f57e6e1755e0Sami Tolvanen        fprintf(fp, METADATA_EOD " 0\n") < 0) {
382946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen        return -1;
383946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    }
384946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen
385946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    return 0;
386946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen}
387946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen
388946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanenstatic int metadata_find(const char *fname, const char *stag,
389946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen        unsigned int slength, off64_t *offset)
390946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen{
391946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    FILE *fp = NULL;
392946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    char tag[METADATA_TAG_MAX_LENGTH + 1];
39351bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    int rc = -1;
394946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    int n;
395946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    long start = 0x4000; /* skip cryptfs metadata area */
396946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    uint32_t magic;
397946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    unsigned int length = 0;
39851bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
399946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    if (!fname) {
400946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen        return -1;
401946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    }
40251bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
4034d3ead9d7c08d2bb0f3af2166b72f57e6e1755e0Sami Tolvanen    fp = fopen(fname, "r+");
40451bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
405946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    if (!fp) {
40647878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        PERROR << "Failed to open " << fname;
40751bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        goto out;
40851bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    }
40951bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
410946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    /* check magic */
4114d3ead9d7c08d2bb0f3af2166b72f57e6e1755e0Sami Tolvanen    if (fseek(fp, start, SEEK_SET) < 0 ||
4124d3ead9d7c08d2bb0f3af2166b72f57e6e1755e0Sami Tolvanen        fread(&magic, sizeof(magic), 1, fp) != 1) {
41347878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        PERROR << "Failed to read magic from " << fname;
41451bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        goto out;
41551bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    }
41651bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
417946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    if (magic != METADATA_MAGIC) {
418946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen        magic = METADATA_MAGIC;
419946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen
4204d3ead9d7c08d2bb0f3af2166b72f57e6e1755e0Sami Tolvanen        if (fseek(fp, start, SEEK_SET) < 0 ||
4214d3ead9d7c08d2bb0f3af2166b72f57e6e1755e0Sami Tolvanen            fwrite(&magic, sizeof(magic), 1, fp) != 1) {
42247878de7d12c7e438fcc584183b44893e91b4a28bowgotsai            PERROR << "Failed to write magic to " << fname;
423946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen            goto out;
424946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen        }
425946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen
426946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen        rc = metadata_add(fp, start + sizeof(magic), stag, slength, offset);
427946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen        if (rc < 0) {
42847878de7d12c7e438fcc584183b44893e91b4a28bowgotsai            PERROR << "Failed to add metadata to " << fname;
429946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen        }
430946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen
43151bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        goto out;
43251bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    }
43351bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
434946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    start += sizeof(magic);
435946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen
436946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    while (1) {
4374d3ead9d7c08d2bb0f3af2166b72f57e6e1755e0Sami Tolvanen        n = fscanf(fp, "%" STRINGIFY(METADATA_TAG_MAX_LENGTH) "s %u\n",
4384d3ead9d7c08d2bb0f3af2166b72f57e6e1755e0Sami Tolvanen                tag, &length);
439946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen
440946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen        if (n == 2 && strcmp(tag, METADATA_EOD)) {
441946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen            /* found a tag */
442946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen            start = ftell(fp);
443946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen
444946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen            if (!strcmp(tag, stag) && length == slength) {
445946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen                *offset = start;
446946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen                rc = 0;
447946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen                goto out;
448946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen            }
449946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen
450946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen            start += length;
451946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen
4524d3ead9d7c08d2bb0f3af2166b72f57e6e1755e0Sami Tolvanen            if (fseek(fp, length, SEEK_CUR) < 0) {
45347878de7d12c7e438fcc584183b44893e91b4a28bowgotsai                PERROR << "Failed to seek " << fname;
454946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen                goto out;
455946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen            }
456946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen        } else {
457946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen            rc = metadata_add(fp, start, stag, slength, offset);
458946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen            if (rc < 0) {
45947878de7d12c7e438fcc584183b44893e91b4a28bowgotsai                PERROR << "Failed to write metadata to " << fname;
460946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen            }
461946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen            goto out;
462946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen        }
463946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen   }
46451bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
46551bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanenout:
466946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    if (fp) {
4674d3ead9d7c08d2bb0f3af2166b72f57e6e1755e0Sami Tolvanen        fflush(fp);
4684d3ead9d7c08d2bb0f3af2166b72f57e6e1755e0Sami Tolvanen        fclose(fp);
46951bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    }
47051bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
47151bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    return rc;
47251bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen}
47351bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
474946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanenstatic int write_verity_state(const char *fname, off64_t offset, int32_t mode)
47551bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen{
476946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    int fd;
477946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    int rc = -1;
478946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    struct verity_state s = { VERITY_STATE_HEADER, VERITY_STATE_VERSION, mode };
47951bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
480946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    fd = TEMP_FAILURE_RETRY(open(fname, O_WRONLY | O_SYNC | O_CLOEXEC));
48151bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
482946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    if (fd == -1) {
48347878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        PERROR << "Failed to open " << fname;
484946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen        goto out;
48551bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    }
48651bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
487946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    if (TEMP_FAILURE_RETRY(pwrite64(fd, &s, sizeof(s), offset)) != sizeof(s)) {
48847878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        PERROR << "Failed to write " << sizeof(s) << " bytes to " << fname
48947878de7d12c7e438fcc584183b44893e91b4a28bowgotsai               << " to offset " << offset;
490946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen        goto out;
491946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    }
49251bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
493946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    rc = 0;
49451bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
495946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanenout:
496946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    if (fd != -1) {
49747b0134ec2b5e8c8b5b5671cd4a3e41261275532Elliott Hughes        close(fd);
49851bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    }
49951bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
500946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    return rc;
50151bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen}
50251bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
503454742392f72079dbdb0d23ea24e01b5703c1aa5Sami Tolvanenstatic int read_verity_state(const char *fname, off64_t offset, int *mode)
50451bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen{
50551bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    int fd = -1;
50651bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    int rc = -1;
50751bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    struct verity_state s;
50851bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
509454742392f72079dbdb0d23ea24e01b5703c1aa5Sami Tolvanen    fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
51051bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
51151bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    if (fd == -1) {
51247878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        PERROR << "Failed to open " << fname;
51351bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        goto out;
51451bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    }
51551bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
516946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen    if (TEMP_FAILURE_RETRY(pread64(fd, &s, sizeof(s), offset)) != sizeof(s)) {
51747878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        PERROR << "Failed to read " <<  sizeof(s) << " bytes from " << fname
51847878de7d12c7e438fcc584183b44893e91b4a28bowgotsai               << " offset " << offset;
51951bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        goto out;
52051bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    }
52151bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
52251bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    if (s.header != VERITY_STATE_HEADER) {
523946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen        /* space allocated, but no state written. write default state */
524946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen        *mode = VERITY_MODE_DEFAULT;
525454742392f72079dbdb0d23ea24e01b5703c1aa5Sami Tolvanen        rc = write_verity_state(fname, offset, *mode);
52651bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        goto out;
52751bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    }
52851bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
52951bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    if (s.version != VERITY_STATE_VERSION) {
53047878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        LERROR << "Unsupported verity state version (" << s.version << ")";
53151bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        goto out;
53251bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    }
53351bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
53451bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    if (s.mode < VERITY_MODE_EIO ||
53551bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        s.mode > VERITY_MODE_LAST) {
53647878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        LERROR << "Unsupported verity mode (" << s.mode << ")";
53751bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen        goto out;
53851bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    }
53951bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
54051bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    *mode = s.mode;
54151bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    rc = 0;
54251bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
54351bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanenout:
54451bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    if (fd != -1) {
54547b0134ec2b5e8c8b5b5671cd4a3e41261275532Elliott Hughes        close(fd);
54651bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    }
54751bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
54851bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    return rc;
54951bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen}
55051bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
5512cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malanistatic int read_partition(const char *path, uint64_t size)
5522cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani{
5532cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani    char buf[READ_BUF_SIZE];
5542cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani    ssize_t size_read;
5552cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC)));
5562cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani
5572cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani    if (fd == -1) {
55847878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        PERROR << "Failed to open " << path;
5592cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani        return -errno;
5602cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani    }
5612cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani
5622cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani    while (size) {
5632cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani        size_read = TEMP_FAILURE_RETRY(read(fd, buf, READ_BUF_SIZE));
5642cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani        if (size_read == -1) {
56547878de7d12c7e438fcc584183b44893e91b4a28bowgotsai            PERROR << "Error in reading partition " << path;
5662cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani            return -errno;
5672cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani        }
5682cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani        size -= size_read;
5692cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani    }
5702cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani
5712cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani    return 0;
5722cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani}
5732cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani
5746122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanenstatic int compare_last_signature(struct fstab_rec *fstab, int *match)
5756122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen{
5766122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    char tag[METADATA_TAG_MAX_LENGTH + 1];
5776122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    int fd = -1;
5786122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    int rc = -1;
57999e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    off64_t offset = 0;
58099e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    struct fec_handle *f = NULL;
58199e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    struct fec_verity_metadata verity;
582097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler    uint8_t curr[SHA256_DIGEST_LENGTH];
583097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler    uint8_t prev[SHA256_DIGEST_LENGTH];
5846122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen
5856122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    *match = 1;
5866122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen
58799e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE,
58899e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen            FEC_DEFAULT_ROOTS) == -1) {
58947878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        PERROR << "Failed to open '" << fstab->blk_device << "'";
59099e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen        return rc;
591030ef35966ab30bc36f1a047df4fd45e466427efMohamad Ayyash    }
592030ef35966ab30bc36f1a047df4fd45e466427efMohamad Ayyash
59399e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    // read verity metadata
59499e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    if (fec_verity_get_metadata(f, &verity) == -1) {
59547878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        PERROR << "Failed to get verity metadata '" << fstab->blk_device << "'";
5966122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen        goto out;
5976122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    }
5986122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen
599097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler    SHA256(verity.signature, sizeof(verity.signature), curr);
6006122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen
6016122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    if (snprintf(tag, sizeof(tag), VERITY_LASTSIG_TAG "_%s",
6026122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen            basename(fstab->mount_point)) >= (int)sizeof(tag)) {
60347878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        LERROR << "Metadata tag name too long for " << fstab->mount_point;
6046122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen        goto out;
6056122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    }
6066122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen
607097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler    if (metadata_find(fstab->verity_loc, tag, SHA256_DIGEST_LENGTH,
6086122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen            &offset) < 0) {
6096122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen        goto out;
6106122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    }
6116122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen
6126122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    fd = TEMP_FAILURE_RETRY(open(fstab->verity_loc, O_RDWR | O_SYNC | O_CLOEXEC));
6136122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen
6146122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    if (fd == -1) {
61547878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        PERROR << "Failed to open " << fstab->verity_loc;
6166122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen        goto out;
6176122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    }
6186122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen
6196122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    if (TEMP_FAILURE_RETRY(pread64(fd, prev, sizeof(prev),
6206122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen            offset)) != sizeof(prev)) {
62147878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        PERROR << "Failed to read " << sizeof(prev) << " bytes from "
62247878de7d12c7e438fcc584183b44893e91b4a28bowgotsai               << fstab->verity_loc << " offset " << offset;
6236122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen        goto out;
6246122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    }
6256122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen
626097b6bbc76231f4148c9dd28b6ea0c1189d40fc3Mattias Nissler    *match = !memcmp(curr, prev, SHA256_DIGEST_LENGTH);
6276122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen
6286122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    if (!*match) {
6296122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen        /* update current signature hash */
6306122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen        if (TEMP_FAILURE_RETRY(pwrite64(fd, curr, sizeof(curr),
6316122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen                offset)) != sizeof(curr)) {
63247878de7d12c7e438fcc584183b44893e91b4a28bowgotsai            PERROR << "Failed to write " << sizeof(curr) << " bytes to "
63347878de7d12c7e438fcc584183b44893e91b4a28bowgotsai                   << fstab->verity_loc << " offset " << offset;
6346122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen            goto out;
6356122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen        }
6366122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    }
6376122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen
6386122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    rc = 0;
6396122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen
6406122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanenout:
64199e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    fec_close(f);
6426122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    return rc;
6436122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen}
6446122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen
6456122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanenstatic int get_verity_state_offset(struct fstab_rec *fstab, off64_t *offset)
6466122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen{
6476122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    char tag[METADATA_TAG_MAX_LENGTH + 1];
6486122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen
6496122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    if (snprintf(tag, sizeof(tag), VERITY_STATE_TAG "_%s",
6506122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen            basename(fstab->mount_point)) >= (int)sizeof(tag)) {
65147878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        LERROR << "Metadata tag name too long for " << fstab->mount_point;
6526122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen        return -1;
6536122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    }
6546122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen
6556122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    return metadata_find(fstab->verity_loc, tag, sizeof(struct verity_state),
6566122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen                offset);
6576122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen}
6586122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen
659aaf70e77dc232fde152249bb6f66a227eab35a10Bowgo Tsaiint load_verity_state(struct fstab_rec* fstab, int* mode) {
6606122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    int match = 0;
661ac5c1224cfc959b96f7a34068a807db9aaab9358Sami Tolvanen    off64_t offset = 0;
662ac5c1224cfc959b96f7a34068a807db9aaab9358Sami Tolvanen
66390f52df257ab020934558a811bad2ba0bae33c5aSami Tolvanen    /* unless otherwise specified, use EIO mode */
66490f52df257ab020934558a811bad2ba0bae33c5aSami Tolvanen    *mode = VERITY_MODE_EIO;
66590f52df257ab020934558a811bad2ba0bae33c5aSami Tolvanen
666ac5c1224cfc959b96f7a34068a807db9aaab9358Sami Tolvanen    /* use the kernel parameter if set */
6679de748f74558abf047045302b6fc46af7629eedbSandeep Patil    std::string veritymode;
6689de748f74558abf047045302b6fc46af7629eedbSandeep Patil    if (fs_mgr_get_boot_config("veritymode", &veritymode)) {
66977cbfd6341a7a500fdb8e2f3cc4a4f721254f10eBowgo Tsai        if (veritymode == "enforcing") {
670ac5c1224cfc959b96f7a34068a807db9aaab9358Sami Tolvanen            *mode = VERITY_MODE_DEFAULT;
671ac5c1224cfc959b96f7a34068a807db9aaab9358Sami Tolvanen        }
67290f52df257ab020934558a811bad2ba0bae33c5aSami Tolvanen        return 0;
673ac5c1224cfc959b96f7a34068a807db9aaab9358Sami Tolvanen    }
674454742392f72079dbdb0d23ea24e01b5703c1aa5Sami Tolvanen
6756122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    if (get_verity_state_offset(fstab, &offset) < 0) {
676454742392f72079dbdb0d23ea24e01b5703c1aa5Sami Tolvanen        /* fall back to stateless behavior */
677454742392f72079dbdb0d23ea24e01b5703c1aa5Sami Tolvanen        return 0;
678454742392f72079dbdb0d23ea24e01b5703c1aa5Sami Tolvanen    }
679454742392f72079dbdb0d23ea24e01b5703c1aa5Sami Tolvanen
680454742392f72079dbdb0d23ea24e01b5703c1aa5Sami Tolvanen    if (was_verity_restart()) {
681454742392f72079dbdb0d23ea24e01b5703c1aa5Sami Tolvanen        /* device was restarted after dm-verity detected a corrupted
68290f52df257ab020934558a811bad2ba0bae33c5aSami Tolvanen         * block, so use EIO mode */
683454742392f72079dbdb0d23ea24e01b5703c1aa5Sami Tolvanen        return write_verity_state(fstab->verity_loc, offset, *mode);
684454742392f72079dbdb0d23ea24e01b5703c1aa5Sami Tolvanen    }
685454742392f72079dbdb0d23ea24e01b5703c1aa5Sami Tolvanen
6866122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    if (!compare_last_signature(fstab, &match) && !match) {
6876122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen        /* partition has been reflashed, reset dm-verity state */
6886122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen        *mode = VERITY_MODE_DEFAULT;
6896122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen        return write_verity_state(fstab->verity_loc, offset, *mode);
6906122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen    }
6916122edbac4d8740a221ced304c25d5a7a048d9f5Sami Tolvanen
692454742392f72079dbdb0d23ea24e01b5703c1aa5Sami Tolvanen    return read_verity_state(fstab->verity_loc, offset, mode);
693454742392f72079dbdb0d23ea24e01b5703c1aa5Sami Tolvanen}
694454742392f72079dbdb0d23ea24e01b5703c1aa5Sami Tolvanen
695c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai// Update the verity table using the actual block device path.
696c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai// Two cases:
697c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai// Case-1: verity table is shared for devices with different by-name prefix.
698c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai// Example:
699c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai//   verity table token:       /dev/block/bootdevice/by-name/vendor
700c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai//   blk_device-1 (non-A/B):   /dev/block/platform/soc.0/7824900.sdhci/by-name/vendor
701c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai//   blk_device-2 (A/B):       /dev/block/platform/soc.0/f9824900.sdhci/by-name/vendor_a
702c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai//
703c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai// Case-2: append A/B suffix in the verity table.
704c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai// Example:
705c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai//   verity table token: /dev/block/platform/soc.0/7824900.sdhci/by-name/vendor
706c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai//   blk_device:         /dev/block/platform/soc.0/7824900.sdhci/by-name/vendor_a
707c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsaistatic void update_verity_table_blk_device(const std::string& blk_device, char** table,
708c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai                                           bool slot_select) {
709c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai    bool updated = false;
710c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai    std::string result, ab_suffix;
711dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella    auto tokens = android::base::Split(*table, " ");
712dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella
713c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai    // If slot_select is set, it means blk_device is already updated with ab_suffix.
714c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai    if (slot_select) ab_suffix = fs_mgr_get_slot_suffix();
715c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai
71673da05d35403a0c3909edcf5744e99b8f786a61fChih-Hung Hsieh    for (const auto& token : tokens) {
717c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai        std::string new_token;
718c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai        if (android::base::StartsWith(token, "/dev/block/")) {
719c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai            if (token == blk_device) return;  // no need to update if they're already the same.
720c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai            std::size_t found1 = blk_device.find("by-name");
721c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai            std::size_t found2 = token.find("by-name");
722c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai            if (found1 != std::string::npos && found2 != std::string::npos &&
723c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai                blk_device.substr(found1) == token.substr(found2) + ab_suffix) {
724c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai                new_token = blk_device;
725c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai            }
726c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai        }
727c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai
728c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai        if (!new_token.empty()) {
729c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai            updated = true;
730c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai            LINFO << "Verity table: updated block device from '" << token << "' to '" << new_token
731c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai                  << "'";
732dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella        } else {
733c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai            new_token = token;
734dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella        }
735dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella
736dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella        if (result.empty()) {
737c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai            result = new_token;
738dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella        } else {
739c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai            result += " " + new_token;
740dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella        }
741dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella    }
742dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella
743c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai    if (!updated) {
744dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella        return;
745dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella    }
746dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella
747dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella    free(*table);
748dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella    *table = strdup(result.c_str());
749dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella}
750dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella
751d2462570b8dffd2e83dfb9c6e60f8f39697659b5Sandeep Patil// prepares the verity enabled (MF_VERIFY / MF_VERIFYATBOOT) fstab record for
752d2462570b8dffd2e83dfb9c6e60f8f39697659b5Sandeep Patil// mount. The 'wait_for_verity_dev' parameter makes this function wait for the
753d2462570b8dffd2e83dfb9c6e60f8f39697659b5Sandeep Patil// verity device to get created before return
754d2462570b8dffd2e83dfb9c6e60f8f39697659b5Sandeep Patilint fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev)
75599e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen{
75651bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    int retval = FS_MGR_SETUP_VERITY_FAIL;
757ec900bba20630934dc51a1b3a57d6d7a30fed325Paul Lawrence    int fd = -1;
75847aa2a75201b9cb53c6464304b82db492073d622bowgotsai    std::string verity_blk_name;
75999e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    struct fec_handle *f = NULL;
76099e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    struct fec_verity_metadata verity;
761dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella    struct verity_table_params params = { .table = NULL };
7623ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
763246c18caf5193e2243dfcbf434e6340039b64f8cElliott Hughes    alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
7643ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    struct dm_ioctl *io = (struct dm_ioctl *) buffer;
76547aa2a75201b9cb53c6464304b82db492073d622bowgotsai    const std::string mount_point(basename(fstab->mount_point));
7662cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani    bool verified_at_boot = false;
7673ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
768e7a1b3757faa3d354ad3f423fa078132a9a84dd4Sandeep Patil    // This is a public API and so deserves its own check to see if verity
769e7a1b3757faa3d354ad3f423fa078132a9a84dd4Sandeep Patil    // setup is needed at all.
770e7a1b3757faa3d354ad3f423fa078132a9a84dd4Sandeep Patil    if (!is_device_secure()) {
771e7a1b3757faa3d354ad3f423fa078132a9a84dd4Sandeep Patil        LINFO << "Verity setup skipped for " << mount_point;
77295366e97ddff7fcfc095481f69bbd7f699715c99Sandeep Patil        return FS_MGR_SETUP_VERITY_SKIPPED;
773e7a1b3757faa3d354ad3f423fa078132a9a84dd4Sandeep Patil    }
774e7a1b3757faa3d354ad3f423fa078132a9a84dd4Sandeep Patil
77599e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE,
77699e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen            FEC_DEFAULT_ROOTS) < 0) {
77747878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        PERROR << "Failed to open '" << fstab->blk_device << "'";
77805699b3e3e05b976a3de50a634b18a6f5109cf95Geremy Condra        return retval;
77905699b3e3e05b976a3de50a634b18a6f5109cf95Geremy Condra    }
78005699b3e3e05b976a3de50a634b18a6f5109cf95Geremy Condra
78199e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    // read verity metadata
78299e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    if (fec_verity_get_metadata(f, &verity) < 0) {
78347878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        PERROR << "Failed to get verity metadata '" << fstab->blk_device << "'";
7847ad3159db9be8fcb7246fbb750884f5a9edf368fBowgo Tsai        // Allow verity disabled when the device is unlocked without metadata
785d1fe3bdbd6bcdc7f268f045e6b3b77de4d837a21Bowgo Tsai        if (fs_mgr_is_device_unlocked()) {
786d1fe3bdbd6bcdc7f268f045e6b3b77de4d837a21Bowgo Tsai            retval = FS_MGR_SETUP_VERITY_SKIPPED;
7877ad3159db9be8fcb7246fbb750884f5a9edf368fBowgo Tsai            LWARNING << "Allow invalid metadata when the device is unlocked";
7887ad3159db9be8fcb7246fbb750884f5a9edf368fBowgo Tsai        }
78999e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen        goto out;
79099e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    }
79199e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen
79299e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen#ifdef ALLOW_ADBD_DISABLE_VERITY
79399e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    if (verity.disabled) {
79499e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen        retval = FS_MGR_SETUP_VERITY_DISABLED;
79547878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        LINFO << "Attempt to cleanly disable verity - only works in USERDEBUG";
796ec900bba20630934dc51a1b3a57d6d7a30fed325Paul Lawrence        goto out;
797ec900bba20630934dc51a1b3a57d6d7a30fed325Paul Lawrence    }
79899e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen#endif
79999e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen
80099e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    // read ecc metadata
80199e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    if (fec_ecc_get_metadata(f, &params.ecc) < 0) {
80299e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen        params.ecc.valid = false;
80399e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    }
804ec900bba20630934dc51a1b3a57d6d7a30fed325Paul Lawrence
80599e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    params.ecc_dev = fstab->blk_device;
80651bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
8073ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    // get the device mapper fd
8083ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
80947878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        PERROR << "Error opening device mapper";
81088a12fb381875639e5c381b333bcfeaf83b1efbfPaul Lawrence        goto out;
8113ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    }
8123ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
8133ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    // create the device
81447aa2a75201b9cb53c6464304b82db492073d622bowgotsai    if (!fs_mgr_create_verity_device(io, mount_point, fd)) {
81547878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        LERROR << "Couldn't create verity device!";
8163ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra        goto out;
8173ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    }
8183ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
8193ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    // get the name of the device file
82047aa2a75201b9cb53c6464304b82db492073d622bowgotsai    if (!fs_mgr_get_verity_device_name(io, mount_point, fd, &verity_blk_name)) {
82147878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        LERROR << "Couldn't get verity device number!";
8223ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra        goto out;
8233ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    }
8243ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
82599e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    if (load_verity_state(fstab, &params.mode) < 0) {
826946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen        /* if accessing or updating the state failed, switch to the default
827946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen         * safe mode. This makes sure the device won't end up in an endless
828946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen         * restart loop, and no corrupted data will be exposed to userspace
829946a0f3e1925c8cc9be08e3e34758d577cbe7f31Sami Tolvanen         * without a warning. */
83099e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen        params.mode = VERITY_MODE_EIO;
83151bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen    }
83251bf11ad95aa871e4131edf4d9d72cc7c7034cdcSami Tolvanen
833dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella    if (!verity.table) {
834dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella        goto out;
835dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella    }
836dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella
837dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella    params.table = strdup(verity.table);
838dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella    if (!params.table) {
839dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella        goto out;
840dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella    }
841dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella
8421ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen    // verify the signature on the table
843830126637ae4e5198df075fba57c1e498624dab6Sami Tolvanen    if (verify_verity_signature(verity) < 0) {
844b67489419911875d8791de87996c39b61740e781Bowgo Tsai        // Allow signature verification error when the device is unlocked
845b67489419911875d8791de87996c39b61740e781Bowgo Tsai        if (fs_mgr_is_device_unlocked()) {
846b67489419911875d8791de87996c39b61740e781Bowgo Tsai            retval = FS_MGR_SETUP_VERITY_SKIPPED;
847b67489419911875d8791de87996c39b61740e781Bowgo Tsai            LWARNING << "Allow signature verification error when the device is unlocked";
848b67489419911875d8791de87996c39b61740e781Bowgo Tsai            goto out;
849b67489419911875d8791de87996c39b61740e781Bowgo Tsai        }
85099e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen        if (params.mode == VERITY_MODE_LOGGING) {
8511ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen            // the user has been warned, allow mounting without dm-verity
852b67489419911875d8791de87996c39b61740e781Bowgo Tsai            retval = FS_MGR_SETUP_VERITY_SKIPPED;
8531ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen            goto out;
8541ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen        }
8551ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen
8561ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen        // invalidate root hash and salt to trigger device-specific recovery
857dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella        if (invalidate_table(params.table, verity.table_length) < 0) {
8581ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen            goto out;
8591ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen        }
8601ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen    }
8611ada14904d1e9e4d022195d5d7541b315076c970Sami Tolvanen
86247878de7d12c7e438fcc584183b44893e91b4a28bowgotsai    LINFO << "Enabling dm-verity for " << mount_point.c_str()
86347878de7d12c7e438fcc584183b44893e91b4a28bowgotsai          << " (mode " << params.mode << ")";
864acbf9bef43bc650ed84ba891183ebdf689dafb64Sami Tolvanen
865c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai    // Update the verity params using the actual block device path
866c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai    update_verity_table_blk_device(fstab->blk_device, &params.table,
867c3eca505cd169cfd0d5bef7ad365bad84ff8227bBowgo Tsai                                   fstab->fs_mgr_flags & MF_SLOTSELECT);
868dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella
8693ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    // load the verity mapping table
87099e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
871ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen            format_verity_table) == 0) {
872ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen        goto loaded;
8733ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    }
8743ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
875ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen    if (params.ecc.valid) {
876ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen        // kernel may not support error correction, try without
87747878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        LINFO << "Disabling error correction for " << mount_point.c_str();
878ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen        params.ecc.valid = false;
879ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen
880ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen        if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
881ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen                format_verity_table) == 0) {
882ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen            goto loaded;
883ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen        }
884ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen    }
885ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen
886ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen    // try the legacy format for backwards compatibility
887ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen    if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
888ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen            format_legacy_verity_table) == 0) {
889ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen        goto loaded;
890ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen    }
891ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen
892ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen    if (params.mode != VERITY_MODE_EIO) {
893ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen        // as a last resort, EIO mode should always be supported
89447878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        LINFO << "Falling back to EIO mode for " << mount_point.c_str();
895ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen        params.mode = VERITY_MODE_EIO;
896ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen
897ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen        if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
898ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen                format_legacy_verity_table) == 0) {
899ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen            goto loaded;
900ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen        }
901ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen    }
902ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen
90347878de7d12c7e438fcc584183b44893e91b4a28bowgotsai    LERROR << "Failed to load verity table for " << mount_point.c_str();
904ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen    goto out;
905ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen
906ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanenloaded:
907ff980d22d1c322173bed6289fd9448d8b5e58144Sami Tolvanen
9083ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    // activate the device
90947aa2a75201b9cb53c6464304b82db492073d622bowgotsai    if (!fs_mgr_resume_verity_table(io, mount_point, fd)) {
9103ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra        goto out;
9113ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    }
9123ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
913214f33b8c095feedfdbaa680ff6ffb763f47d375Sami Tolvanen    // mark the underlying block device as read-only
914214f33b8c095feedfdbaa680ff6ffb763f47d375Sami Tolvanen    fs_mgr_set_blk_ro(fstab->blk_device);
915214f33b8c095feedfdbaa680ff6ffb763f47d375Sami Tolvanen
9162cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani    // Verify the entire partition in one go
9172cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani    // If there is an error, allow it to mount as a normal verity partition.
9182cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani    if (fstab->fs_mgr_flags & MF_VERIFYATBOOT) {
91947878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        LINFO << "Verifying partition " << fstab->blk_device << " at boot";
92047aa2a75201b9cb53c6464304b82db492073d622bowgotsai        int err = read_partition(verity_blk_name.c_str(), verity.data_size);
9212cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani        if (!err) {
92247878de7d12c7e438fcc584183b44893e91b4a28bowgotsai            LINFO << "Verified verity partition "
92347878de7d12c7e438fcc584183b44893e91b4a28bowgotsai                  << fstab->blk_device << " at boot";
9242cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani            verified_at_boot = true;
9252cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani        }
9262cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani    }
9272cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani
9283ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    // assign the new verity block device as the block device
9292cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani    if (!verified_at_boot) {
9302cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani        free(fstab->blk_device);
93147aa2a75201b9cb53c6464304b82db492073d622bowgotsai        fstab->blk_device = strdup(verity_blk_name.c_str());
93247aa2a75201b9cb53c6464304b82db492073d622bowgotsai    } else if (!fs_mgr_destroy_verity_device(io, mount_point, fd)) {
93347878de7d12c7e438fcc584183b44893e91b4a28bowgotsai        LERROR << "Failed to remove verity device " << mount_point.c_str();
9342cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani        goto out;
9352cdc67eed50da046b1e78728f2563fc3db6f8927Prashant Malani    }
9363ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
937dba750e0e0d0cc996c70d7699cd35e34226565deWei Wang    // make sure we've set everything up properly
9389d344969b03fd19a6f5c485ddd7c8dd22b7d3a9dJinguang Dong    if (wait_for_verity_dev && !fs_mgr_wait_for_file(fstab->blk_device, 1s)) {
939dba750e0e0d0cc996c70d7699cd35e34226565deWei Wang        goto out;
940dba750e0e0d0cc996c70d7699cd35e34226565deWei Wang    }
941dba750e0e0d0cc996c70d7699cd35e34226565deWei Wang
94286cddf40741024961839dbbcfa005e908314e681Sami Tolvanen    retval = FS_MGR_SETUP_VERITY_SUCCESS;
9433ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra
9443ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condraout:
945ec900bba20630934dc51a1b3a57d6d7a30fed325Paul Lawrence    if (fd != -1) {
946ec900bba20630934dc51a1b3a57d6d7a30fed325Paul Lawrence        close(fd);
947ec900bba20630934dc51a1b3a57d6d7a30fed325Paul Lawrence    }
948ec900bba20630934dc51a1b3a57d6d7a30fed325Paul Lawrence
94999e3a927e89bd0fa67a13511071260fa02d13fa1Sami Tolvanen    fec_close(f);
950dfd2478bd172c3e6242cee5e0a7dcea2c4ee3056Jeremy Compostella    free(params.table);
951ec900bba20630934dc51a1b3a57d6d7a30fed325Paul Lawrence
9523ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra    return retval;
9533ad3d1c4b5856d4e314febc5671c74e78a76db00Geremy Condra}
954