blob: 896b603132f2ccc6dd6dd3cfeacf54d807fd0af6 [file] [log] [blame]
Geremy Condra3ad3d1c2013-02-22 18:11:41 -08001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Mattias Nissler097b6bb2016-03-31 16:32:09 +020017#include <ctype.h>
18#include <errno.h>
19#include <fcntl.h>
Elliott Hughesccecf142014-01-16 10:53:11 -080020#include <inttypes.h>
Mattias Nissler097b6bb2016-03-31 16:32:09 +020021#include <libgen.h>
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080022#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080025#include <sys/mount.h>
26#include <sys/stat.h>
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080027#include <sys/types.h>
28#include <sys/wait.h>
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080029#include <time.h>
Mattias Nissler097b6bb2016-03-31 16:32:09 +020030#include <unistd.h>
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080031
Elliott Hughes4f713192015-12-04 22:00:26 -080032#include <android-base/file.h>
Bowgo Tsai7ad31592017-03-06 15:39:06 +080033#include <android-base/properties.h>
Jeremy Compostelladfd24782016-04-26 13:51:27 +020034#include <android-base/strings.h>
Prashant Malani2cdc67e2016-10-27 16:15:41 -070035#include <android-base/unique_fd.h>
Mattias Nissler097b6bb2016-03-31 16:32:09 +020036#include <crypto_utils/android_pubkey.h>
Geremy Condra05699b32014-03-17 14:46:51 -070037#include <cutils/properties.h>
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080038#include <logwrap/logwrap.h>
Mattias Nissler097b6bb2016-03-31 16:32:09 +020039#include <openssl/obj_mac.h>
40#include <openssl/rsa.h>
41#include <openssl/sha.h>
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080042
Sami Tolvanen99e3a922015-05-22 15:43:50 +010043#include "fec/io.h"
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080044
Elliott Hughes246c18c2015-10-09 11:52:00 -070045#include "fs_mgr.h"
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080046#include "fs_mgr_priv.h"
bowgotsai3de625d2016-11-11 21:05:44 +080047#include "fs_mgr_priv_dm_ioctl.h"
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080048
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080049#define VERITY_TABLE_RSA_KEY "/verity_key"
Sami Tolvanen1ada1492015-09-21 15:12:29 +010050#define VERITY_TABLE_HASH_IDX 8
51#define VERITY_TABLE_SALT_IDX 9
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080052
Sami Tolvanen99e3a922015-05-22 15:43:50 +010053#define VERITY_TABLE_OPT_RESTART "restart_on_corruption"
54#define VERITY_TABLE_OPT_LOGGING "ignore_corruption"
55#define VERITY_TABLE_OPT_IGNZERO "ignore_zero_blocks"
56
57#define VERITY_TABLE_OPT_FEC_FORMAT \
58 "use_fec_from_device %s fec_start %" PRIu64 " fec_blocks %" PRIu64 \
59 " fec_roots %u " VERITY_TABLE_OPT_IGNZERO
60#define VERITY_TABLE_OPT_FEC_ARGS 9
61
Sami Tolvanen946a0f32015-03-22 12:40:05 +000062#define METADATA_MAGIC 0x01564c54
63#define METADATA_TAG_MAX_LENGTH 63
64#define METADATA_EOD "eod"
65
Sami Tolvanen6122edb2015-03-31 14:36:03 +010066#define VERITY_LASTSIG_TAG "verity_lastsig"
67
Sami Tolvanen946a0f32015-03-22 12:40:05 +000068#define VERITY_STATE_TAG "verity_state"
Sami Tolvanen51bf11a2015-02-16 10:27:21 +000069#define VERITY_STATE_HEADER 0x83c0ae9d
70#define VERITY_STATE_VERSION 1
71
72#define VERITY_KMSG_RESTART "dm-verity device corrupted"
73#define VERITY_KMSG_BUFSIZE 1024
74
Prashant Malani2cdc67e2016-10-27 16:15:41 -070075#define READ_BUF_SIZE 4096
76
Sami Tolvanen946a0f32015-03-22 12:40:05 +000077#define __STRINGIFY(x) #x
78#define STRINGIFY(x) __STRINGIFY(x)
79
Sami Tolvanen51bf11a2015-02-16 10:27:21 +000080struct verity_state {
81 uint32_t header;
82 uint32_t version;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +000083 int32_t mode;
84};
85
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080086extern struct fs_info info;
87
Mattias Nissler097b6bb2016-03-31 16:32:09 +020088static RSA *load_key(const char *path)
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080089{
Mattias Nissler097b6bb2016-03-31 16:32:09 +020090 uint8_t key_data[ANDROID_PUBKEY_ENCODED_SIZE];
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080091
Elliott Hughes246c18c2015-10-09 11:52:00 -070092 FILE* f = fopen(path, "r");
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080093 if (!f) {
bowgotsai47878de2017-01-23 14:04:34 +080094 LERROR << "Can't open " << path;
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080095 return NULL;
96 }
97
Mattias Nissler097b6bb2016-03-31 16:32:09 +020098 if (!fread(key_data, sizeof(key_data), 1, f)) {
bowgotsai47878de2017-01-23 14:04:34 +080099 LERROR << "Could not read key!";
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800100 fclose(f);
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800101 return NULL;
102 }
103
104 fclose(f);
Mattias Nissler097b6bb2016-03-31 16:32:09 +0200105
106 RSA* key = NULL;
107 if (!android_pubkey_decode(key_data, sizeof(key_data), &key)) {
bowgotsai47878de2017-01-23 14:04:34 +0800108 LERROR << "Could not parse key!";
Mattias Nissler097b6bb2016-03-31 16:32:09 +0200109 return NULL;
110 }
111
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800112 return key;
113}
114
Mattias Nissler097b6bb2016-03-31 16:32:09 +0200115static int verify_table(const uint8_t *signature, size_t signature_size,
116 const char *table, uint32_t table_length)
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800117{
Mattias Nissler097b6bb2016-03-31 16:32:09 +0200118 RSA *key;
119 uint8_t hash_buf[SHA256_DIGEST_LENGTH];
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800120 int retval = -1;
121
122 // Hash the table
Mattias Nissler097b6bb2016-03-31 16:32:09 +0200123 SHA256((uint8_t*)table, table_length, hash_buf);
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800124
125 // Now get the public key from the keyfile
126 key = load_key(VERITY_TABLE_RSA_KEY);
127 if (!key) {
bowgotsai47878de2017-01-23 14:04:34 +0800128 LERROR << "Couldn't load verity keys";
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800129 goto out;
130 }
131
132 // verify the result
Mattias Nissler097b6bb2016-03-31 16:32:09 +0200133 if (!RSA_verify(NID_sha256, hash_buf, sizeof(hash_buf), signature,
134 signature_size, key)) {
bowgotsai47878de2017-01-23 14:04:34 +0800135 LERROR << "Couldn't verify table";
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800136 goto out;
137 }
138
139 retval = 0;
140
141out:
Mattias Nissler097b6bb2016-03-31 16:32:09 +0200142 RSA_free(key);
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800143 return retval;
144}
145
Sami Tolvanen83012662016-06-03 13:58:26 -0700146static int verify_verity_signature(const struct fec_verity_metadata& verity)
147{
Sami Tolvanen4171b2b2016-06-06 22:49:15 -0700148 if (verify_table(verity.signature, sizeof(verity.signature),
149 verity.table, verity.table_length) == 0 ||
150 verify_table(verity.ecc_signature, sizeof(verity.ecc_signature),
151 verity.table, verity.table_length) == 0) {
Sami Tolvanen83012662016-06-03 13:58:26 -0700152 return 0;
153 }
154
155 return -1;
156}
157
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100158static int invalidate_table(char *table, size_t table_length)
Sami Tolvanen1ada1492015-09-21 15:12:29 +0100159{
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100160 size_t n = 0;
161 size_t idx = 0;
162 size_t cleared = 0;
Sami Tolvanen1ada1492015-09-21 15:12:29 +0100163
164 while (n < table_length) {
165 if (table[n++] == ' ') {
166 ++idx;
167 }
168
169 if (idx != VERITY_TABLE_HASH_IDX && idx != VERITY_TABLE_SALT_IDX) {
170 continue;
171 }
172
173 while (n < table_length && table[n] != ' ') {
174 table[n++] = '0';
175 }
176
177 if (++cleared == 2) {
178 return 0;
179 }
180 }
181
182 return -1;
183}
184
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100185struct verity_table_params {
Jeremy Compostelladfd24782016-04-26 13:51:27 +0200186 char *table;
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100187 int mode;
188 struct fec_ecc_metadata ecc;
189 const char *ecc_dev;
190};
191
192typedef bool (*format_verity_table_func)(char *buf, const size_t bufsize,
193 const struct verity_table_params *params);
194
195static bool format_verity_table(char *buf, const size_t bufsize,
196 const struct verity_table_params *params)
197{
198 const char *mode_flag = NULL;
199 int res = -1;
200
201 if (params->mode == VERITY_MODE_RESTART) {
202 mode_flag = VERITY_TABLE_OPT_RESTART;
203 } else if (params->mode == VERITY_MODE_LOGGING) {
204 mode_flag = VERITY_TABLE_OPT_LOGGING;
205 }
206
207 if (params->ecc.valid) {
208 if (mode_flag) {
209 res = snprintf(buf, bufsize,
210 "%s %u %s " VERITY_TABLE_OPT_FEC_FORMAT,
211 params->table, 1 + VERITY_TABLE_OPT_FEC_ARGS, mode_flag, params->ecc_dev,
212 params->ecc.start / FEC_BLOCKSIZE, params->ecc.blocks, params->ecc.roots);
213 } else {
214 res = snprintf(buf, bufsize,
215 "%s %u " VERITY_TABLE_OPT_FEC_FORMAT,
216 params->table, VERITY_TABLE_OPT_FEC_ARGS, params->ecc_dev,
217 params->ecc.start / FEC_BLOCKSIZE, params->ecc.blocks, params->ecc.roots);
218 }
219 } else if (mode_flag) {
220 res = snprintf(buf, bufsize, "%s 2 " VERITY_TABLE_OPT_IGNZERO " %s", params->table,
221 mode_flag);
222 } else {
Sami Tolvanenff980d22015-12-10 00:04:10 +0000223 res = snprintf(buf, bufsize, "%s 1 " VERITY_TABLE_OPT_IGNZERO, params->table);
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100224 }
225
226 if (res < 0 || (size_t)res >= bufsize) {
bowgotsai47878de2017-01-23 14:04:34 +0800227 LERROR << "Error building verity table; insufficient buffer size?";
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100228 return false;
229 }
230
231 return true;
232}
233
234static bool format_legacy_verity_table(char *buf, const size_t bufsize,
235 const struct verity_table_params *params)
236{
237 int res;
238
239 if (params->mode == VERITY_MODE_EIO) {
240 res = strlcpy(buf, params->table, bufsize);
241 } else {
242 res = snprintf(buf, bufsize, "%s %d", params->table, params->mode);
243 }
244
245 if (res < 0 || (size_t)res >= bufsize) {
bowgotsai47878de2017-01-23 14:04:34 +0800246 LERROR << "Error building verity table; insufficient buffer size?";
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100247 return false;
248 }
249
250 return true;
251}
252
bowgotsai47aa2a72017-01-09 18:15:41 +0800253static int load_verity_table(struct dm_ioctl *io, const std::string &name,
254 uint64_t device_size, int fd,
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100255 const struct verity_table_params *params, format_verity_table_func format)
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800256{
257 char *verity_params;
258 char *buffer = (char*) io;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000259 size_t bufsize;
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800260
bowgotsai3de625d2016-11-11 21:05:44 +0800261 fs_mgr_verity_ioctl_init(io, name, DM_STATUS_TABLE_FLAG);
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800262
263 struct dm_target_spec *tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
264
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100265 // set tgt arguments
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800266 io->target_count = 1;
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100267 tgt->status = 0;
268 tgt->sector_start = 0;
269 tgt->length = device_size / 512;
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800270 strcpy(tgt->target_type, "verity");
271
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100272 // build the verity params
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800273 verity_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000274 bufsize = DM_BUF_SIZE - (verity_params - buffer);
275
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100276 if (!format(verity_params, bufsize, params)) {
bowgotsai47878de2017-01-23 14:04:34 +0800277 LERROR << "Failed to format verity parameters";
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000278 return -1;
279 }
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800280
bowgotsai47878de2017-01-23 14:04:34 +0800281 LINFO << "loading verity table: '" << verity_params << "'";
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100282
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800283 // set next target boundary
284 verity_params += strlen(verity_params) + 1;
bowgotsaice25baf2017-01-25 20:21:58 +0800285 verity_params = (char*)(((uintptr_t)verity_params + 7) & ~7);
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800286 tgt->next = verity_params - buffer;
287
288 // send the ioctl to load the verity table
289 if (ioctl(fd, DM_TABLE_LOAD, io)) {
bowgotsai47878de2017-01-23 14:04:34 +0800290 PERROR << "Error loading verity table";
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800291 return -1;
292 }
293
294 return 0;
295}
296
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000297static int check_verity_restart(const char *fname)
298{
299 char buffer[VERITY_KMSG_BUFSIZE + 1];
300 int fd;
301 int rc = 0;
302 ssize_t size;
303 struct stat s;
304
305 fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
306
307 if (fd == -1) {
308 if (errno != ENOENT) {
bowgotsai47878de2017-01-23 14:04:34 +0800309 PERROR << "Failed to open " << fname;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000310 }
311 goto out;
312 }
313
314 if (fstat(fd, &s) == -1) {
bowgotsai47878de2017-01-23 14:04:34 +0800315 PERROR << "Failed to fstat " << fname;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000316 goto out;
317 }
318
319 size = VERITY_KMSG_BUFSIZE;
320
321 if (size > s.st_size) {
322 size = s.st_size;
323 }
324
325 if (lseek(fd, s.st_size - size, SEEK_SET) == -1) {
bowgotsai47878de2017-01-23 14:04:34 +0800326 PERROR << "Failed to lseek " << (intmax_t)(s.st_size - size) << " " << fname;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000327 goto out;
328 }
329
Johan Redestig67b3cad2015-10-08 21:36:35 +0200330 if (!android::base::ReadFully(fd, buffer, size)) {
bowgotsai47878de2017-01-23 14:04:34 +0800331 PERROR << "Failed to read " << size << " bytes from " << fname;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000332 goto out;
333 }
334
335 buffer[size] = '\0';
336
337 if (strstr(buffer, VERITY_KMSG_RESTART) != NULL) {
338 rc = 1;
339 }
340
341out:
342 if (fd != -1) {
Elliott Hughes47b01342015-05-15 19:16:40 -0700343 close(fd);
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000344 }
345
346 return rc;
347}
348
349static int was_verity_restart()
350{
Mark Salyzyncab56c02017-06-27 09:03:37 -0700351 static const char* files[] = {
352 // clang-format off
353 "/sys/fs/pstore/console-ramoops-0",
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000354 "/sys/fs/pstore/console-ramoops",
355 "/proc/last_kmsg",
356 NULL
Mark Salyzyncab56c02017-06-27 09:03:37 -0700357 // clang-format on
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000358 };
359 int i;
360
361 for (i = 0; files[i]; ++i) {
362 if (check_verity_restart(files[i])) {
363 return 1;
364 }
365 }
366
367 return 0;
368}
369
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000370static int metadata_add(FILE *fp, long start, const char *tag,
371 unsigned int length, off64_t *offset)
372{
Sami Tolvanen4d3ead92015-03-26 08:07:45 +0000373 if (fseek(fp, start, SEEK_SET) < 0 ||
374 fprintf(fp, "%s %u\n", tag, length) < 0) {
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000375 return -1;
376 }
377
378 *offset = ftell(fp);
379
Sami Tolvanen4d3ead92015-03-26 08:07:45 +0000380 if (fseek(fp, length, SEEK_CUR) < 0 ||
381 fprintf(fp, METADATA_EOD " 0\n") < 0) {
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000382 return -1;
383 }
384
385 return 0;
386}
387
388static int metadata_find(const char *fname, const char *stag,
389 unsigned int slength, off64_t *offset)
390{
391 FILE *fp = NULL;
392 char tag[METADATA_TAG_MAX_LENGTH + 1];
393 int rc = -1;
394 int n;
395 long start = 0x4000; /* skip cryptfs metadata area */
396 uint32_t magic;
397 unsigned int length = 0;
398
399 if (!fname) {
400 return -1;
401 }
402
Sami Tolvanen4d3ead92015-03-26 08:07:45 +0000403 fp = fopen(fname, "r+");
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000404
405 if (!fp) {
bowgotsai47878de2017-01-23 14:04:34 +0800406 PERROR << "Failed to open " << fname;
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000407 goto out;
408 }
409
410 /* check magic */
Sami Tolvanen4d3ead92015-03-26 08:07:45 +0000411 if (fseek(fp, start, SEEK_SET) < 0 ||
412 fread(&magic, sizeof(magic), 1, fp) != 1) {
bowgotsai47878de2017-01-23 14:04:34 +0800413 PERROR << "Failed to read magic from " << fname;
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000414 goto out;
415 }
416
417 if (magic != METADATA_MAGIC) {
418 magic = METADATA_MAGIC;
419
Sami Tolvanen4d3ead92015-03-26 08:07:45 +0000420 if (fseek(fp, start, SEEK_SET) < 0 ||
421 fwrite(&magic, sizeof(magic), 1, fp) != 1) {
bowgotsai47878de2017-01-23 14:04:34 +0800422 PERROR << "Failed to write magic to " << fname;
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000423 goto out;
424 }
425
426 rc = metadata_add(fp, start + sizeof(magic), stag, slength, offset);
427 if (rc < 0) {
bowgotsai47878de2017-01-23 14:04:34 +0800428 PERROR << "Failed to add metadata to " << fname;
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000429 }
430
431 goto out;
432 }
433
434 start += sizeof(magic);
435
436 while (1) {
Sami Tolvanen4d3ead92015-03-26 08:07:45 +0000437 n = fscanf(fp, "%" STRINGIFY(METADATA_TAG_MAX_LENGTH) "s %u\n",
438 tag, &length);
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000439
440 if (n == 2 && strcmp(tag, METADATA_EOD)) {
441 /* found a tag */
442 start = ftell(fp);
443
444 if (!strcmp(tag, stag) && length == slength) {
445 *offset = start;
446 rc = 0;
447 goto out;
448 }
449
450 start += length;
451
Sami Tolvanen4d3ead92015-03-26 08:07:45 +0000452 if (fseek(fp, length, SEEK_CUR) < 0) {
bowgotsai47878de2017-01-23 14:04:34 +0800453 PERROR << "Failed to seek " << fname;
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000454 goto out;
455 }
456 } else {
457 rc = metadata_add(fp, start, stag, slength, offset);
458 if (rc < 0) {
bowgotsai47878de2017-01-23 14:04:34 +0800459 PERROR << "Failed to write metadata to " << fname;
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000460 }
461 goto out;
462 }
463 }
464
465out:
466 if (fp) {
Sami Tolvanen4d3ead92015-03-26 08:07:45 +0000467 fflush(fp);
468 fclose(fp);
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000469 }
470
471 return rc;
472}
473
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000474static int write_verity_state(const char *fname, off64_t offset, int32_t mode)
475{
476 int fd;
477 int rc = -1;
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000478 struct verity_state s = { VERITY_STATE_HEADER, VERITY_STATE_VERSION, mode };
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000479
480 fd = TEMP_FAILURE_RETRY(open(fname, O_WRONLY | O_SYNC | O_CLOEXEC));
481
482 if (fd == -1) {
bowgotsai47878de2017-01-23 14:04:34 +0800483 PERROR << "Failed to open " << fname;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000484 goto out;
485 }
486
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000487 if (TEMP_FAILURE_RETRY(pwrite64(fd, &s, sizeof(s), offset)) != sizeof(s)) {
bowgotsai47878de2017-01-23 14:04:34 +0800488 PERROR << "Failed to write " << sizeof(s) << " bytes to " << fname
489 << " to offset " << offset;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000490 goto out;
491 }
492
493 rc = 0;
494
495out:
496 if (fd != -1) {
Elliott Hughes47b01342015-05-15 19:16:40 -0700497 close(fd);
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000498 }
499
500 return rc;
501}
502
Sami Tolvanen45474232015-03-30 11:38:38 +0100503static int read_verity_state(const char *fname, off64_t offset, int *mode)
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000504{
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000505 int fd = -1;
506 int rc = -1;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000507 struct verity_state s;
508
Sami Tolvanen45474232015-03-30 11:38:38 +0100509 fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000510
511 if (fd == -1) {
bowgotsai47878de2017-01-23 14:04:34 +0800512 PERROR << "Failed to open " << fname;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000513 goto out;
514 }
515
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000516 if (TEMP_FAILURE_RETRY(pread64(fd, &s, sizeof(s), offset)) != sizeof(s)) {
bowgotsai47878de2017-01-23 14:04:34 +0800517 PERROR << "Failed to read " << sizeof(s) << " bytes from " << fname
518 << " offset " << offset;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000519 goto out;
520 }
521
522 if (s.header != VERITY_STATE_HEADER) {
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000523 /* space allocated, but no state written. write default state */
524 *mode = VERITY_MODE_DEFAULT;
Sami Tolvanen45474232015-03-30 11:38:38 +0100525 rc = write_verity_state(fname, offset, *mode);
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000526 goto out;
527 }
528
529 if (s.version != VERITY_STATE_VERSION) {
bowgotsai47878de2017-01-23 14:04:34 +0800530 LERROR << "Unsupported verity state version (" << s.version << ")";
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000531 goto out;
532 }
533
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000534 if (s.mode < VERITY_MODE_EIO ||
535 s.mode > VERITY_MODE_LAST) {
bowgotsai47878de2017-01-23 14:04:34 +0800536 LERROR << "Unsupported verity mode (" << s.mode << ")";
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000537 goto out;
538 }
539
540 *mode = s.mode;
541 rc = 0;
542
543out:
544 if (fd != -1) {
Elliott Hughes47b01342015-05-15 19:16:40 -0700545 close(fd);
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000546 }
547
548 return rc;
549}
550
Prashant Malani2cdc67e2016-10-27 16:15:41 -0700551static int read_partition(const char *path, uint64_t size)
552{
553 char buf[READ_BUF_SIZE];
554 ssize_t size_read;
555 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC)));
556
557 if (fd == -1) {
bowgotsai47878de2017-01-23 14:04:34 +0800558 PERROR << "Failed to open " << path;
Prashant Malani2cdc67e2016-10-27 16:15:41 -0700559 return -errno;
560 }
561
562 while (size) {
563 size_read = TEMP_FAILURE_RETRY(read(fd, buf, READ_BUF_SIZE));
564 if (size_read == -1) {
bowgotsai47878de2017-01-23 14:04:34 +0800565 PERROR << "Error in reading partition " << path;
Prashant Malani2cdc67e2016-10-27 16:15:41 -0700566 return -errno;
567 }
568 size -= size_read;
569 }
570
571 return 0;
572}
573
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100574static int compare_last_signature(struct fstab_rec *fstab, int *match)
575{
576 char tag[METADATA_TAG_MAX_LENGTH + 1];
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100577 int fd = -1;
578 int rc = -1;
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100579 off64_t offset = 0;
580 struct fec_handle *f = NULL;
581 struct fec_verity_metadata verity;
Mattias Nissler097b6bb2016-03-31 16:32:09 +0200582 uint8_t curr[SHA256_DIGEST_LENGTH];
583 uint8_t prev[SHA256_DIGEST_LENGTH];
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100584
585 *match = 1;
586
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100587 if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE,
588 FEC_DEFAULT_ROOTS) == -1) {
bowgotsai47878de2017-01-23 14:04:34 +0800589 PERROR << "Failed to open '" << fstab->blk_device << "'";
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100590 return rc;
591 }
592
593 // read verity metadata
594 if (fec_verity_get_metadata(f, &verity) == -1) {
bowgotsai47878de2017-01-23 14:04:34 +0800595 PERROR << "Failed to get verity metadata '" << fstab->blk_device << "'";
Mohamad Ayyash030ef3592015-04-08 17:59:19 -0700596 goto out;
597 }
598
Mattias Nissler097b6bb2016-03-31 16:32:09 +0200599 SHA256(verity.signature, sizeof(verity.signature), curr);
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100600
601 if (snprintf(tag, sizeof(tag), VERITY_LASTSIG_TAG "_%s",
602 basename(fstab->mount_point)) >= (int)sizeof(tag)) {
bowgotsai47878de2017-01-23 14:04:34 +0800603 LERROR << "Metadata tag name too long for " << fstab->mount_point;
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100604 goto out;
605 }
606
Mattias Nissler097b6bb2016-03-31 16:32:09 +0200607 if (metadata_find(fstab->verity_loc, tag, SHA256_DIGEST_LENGTH,
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100608 &offset) < 0) {
609 goto out;
610 }
611
612 fd = TEMP_FAILURE_RETRY(open(fstab->verity_loc, O_RDWR | O_SYNC | O_CLOEXEC));
613
614 if (fd == -1) {
bowgotsai47878de2017-01-23 14:04:34 +0800615 PERROR << "Failed to open " << fstab->verity_loc;
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100616 goto out;
617 }
618
619 if (TEMP_FAILURE_RETRY(pread64(fd, prev, sizeof(prev),
620 offset)) != sizeof(prev)) {
bowgotsai47878de2017-01-23 14:04:34 +0800621 PERROR << "Failed to read " << sizeof(prev) << " bytes from "
622 << fstab->verity_loc << " offset " << offset;
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100623 goto out;
624 }
625
Mattias Nissler097b6bb2016-03-31 16:32:09 +0200626 *match = !memcmp(curr, prev, SHA256_DIGEST_LENGTH);
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100627
628 if (!*match) {
629 /* update current signature hash */
630 if (TEMP_FAILURE_RETRY(pwrite64(fd, curr, sizeof(curr),
631 offset)) != sizeof(curr)) {
bowgotsai47878de2017-01-23 14:04:34 +0800632 PERROR << "Failed to write " << sizeof(curr) << " bytes to "
633 << fstab->verity_loc << " offset " << offset;
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100634 goto out;
635 }
636 }
637
638 rc = 0;
639
640out:
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100641 fec_close(f);
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100642 return rc;
643}
644
645static int get_verity_state_offset(struct fstab_rec *fstab, off64_t *offset)
646{
647 char tag[METADATA_TAG_MAX_LENGTH + 1];
648
649 if (snprintf(tag, sizeof(tag), VERITY_STATE_TAG "_%s",
650 basename(fstab->mount_point)) >= (int)sizeof(tag)) {
bowgotsai47878de2017-01-23 14:04:34 +0800651 LERROR << "Metadata tag name too long for " << fstab->mount_point;
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100652 return -1;
653 }
654
655 return metadata_find(fstab->verity_loc, tag, sizeof(struct verity_state),
656 offset);
657}
658
Bowgo Tsaiaaf70e72017-03-02 00:03:56 +0800659int load_verity_state(struct fstab_rec* fstab, int* mode) {
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100660 int match = 0;
Sami Tolvanenac5c1222015-06-03 12:33:07 +0100661 off64_t offset = 0;
662
Sami Tolvanen90f52df2015-12-02 14:23:09 +0000663 /* unless otherwise specified, use EIO mode */
664 *mode = VERITY_MODE_EIO;
665
Sami Tolvanenac5c1222015-06-03 12:33:07 +0100666 /* use the kernel parameter if set */
Sandeep Patil9de748f2017-02-16 19:15:29 -0800667 std::string veritymode;
668 if (fs_mgr_get_boot_config("veritymode", &veritymode)) {
Bowgo Tsai77cbfd62017-05-08 17:15:20 +0800669 if (veritymode == "enforcing") {
Sami Tolvanenac5c1222015-06-03 12:33:07 +0100670 *mode = VERITY_MODE_DEFAULT;
Sami Tolvanenac5c1222015-06-03 12:33:07 +0100671 }
Sami Tolvanen90f52df2015-12-02 14:23:09 +0000672 return 0;
Sami Tolvanenac5c1222015-06-03 12:33:07 +0100673 }
Sami Tolvanen45474232015-03-30 11:38:38 +0100674
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100675 if (get_verity_state_offset(fstab, &offset) < 0) {
Sami Tolvanen45474232015-03-30 11:38:38 +0100676 /* fall back to stateless behavior */
Sami Tolvanen45474232015-03-30 11:38:38 +0100677 return 0;
678 }
679
680 if (was_verity_restart()) {
681 /* device was restarted after dm-verity detected a corrupted
Sami Tolvanen90f52df2015-12-02 14:23:09 +0000682 * block, so use EIO mode */
Sami Tolvanen45474232015-03-30 11:38:38 +0100683 return write_verity_state(fstab->verity_loc, offset, *mode);
684 }
685
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100686 if (!compare_last_signature(fstab, &match) && !match) {
687 /* partition has been reflashed, reset dm-verity state */
688 *mode = VERITY_MODE_DEFAULT;
689 return write_verity_state(fstab->verity_loc, offset, *mode);
690 }
691
Sami Tolvanen45474232015-03-30 11:38:38 +0100692 return read_verity_state(fstab->verity_loc, offset, mode);
693}
694
Bowgo Tsaic3eca502017-06-08 15:16:52 +0800695// Update the verity table using the actual block device path.
696// Two cases:
697// Case-1: verity table is shared for devices with different by-name prefix.
698// Example:
699// verity table token: /dev/block/bootdevice/by-name/vendor
700// blk_device-1 (non-A/B): /dev/block/platform/soc.0/7824900.sdhci/by-name/vendor
701// blk_device-2 (A/B): /dev/block/platform/soc.0/f9824900.sdhci/by-name/vendor_a
702//
703// Case-2: append A/B suffix in the verity table.
704// Example:
705// verity table token: /dev/block/platform/soc.0/7824900.sdhci/by-name/vendor
706// blk_device: /dev/block/platform/soc.0/7824900.sdhci/by-name/vendor_a
707static void update_verity_table_blk_device(const std::string& blk_device, char** table,
708 bool slot_select) {
709 bool updated = false;
710 std::string result, ab_suffix;
Jeremy Compostelladfd24782016-04-26 13:51:27 +0200711 auto tokens = android::base::Split(*table, " ");
712
Bowgo Tsaic3eca502017-06-08 15:16:52 +0800713 // If slot_select is set, it means blk_device is already updated with ab_suffix.
714 if (slot_select) ab_suffix = fs_mgr_get_slot_suffix();
715
Chih-Hung Hsieh73da05d2016-07-27 16:12:54 -0700716 for (const auto& token : tokens) {
Bowgo Tsaic3eca502017-06-08 15:16:52 +0800717 std::string new_token;
718 if (android::base::StartsWith(token, "/dev/block/")) {
719 if (token == blk_device) return; // no need to update if they're already the same.
720 std::size_t found1 = blk_device.find("by-name");
721 std::size_t found2 = token.find("by-name");
722 if (found1 != std::string::npos && found2 != std::string::npos &&
723 blk_device.substr(found1) == token.substr(found2) + ab_suffix) {
724 new_token = blk_device;
725 }
726 }
727
728 if (!new_token.empty()) {
729 updated = true;
730 LINFO << "Verity table: updated block device from '" << token << "' to '" << new_token
731 << "'";
Jeremy Compostelladfd24782016-04-26 13:51:27 +0200732 } else {
Bowgo Tsaic3eca502017-06-08 15:16:52 +0800733 new_token = token;
Jeremy Compostelladfd24782016-04-26 13:51:27 +0200734 }
735
736 if (result.empty()) {
Bowgo Tsaic3eca502017-06-08 15:16:52 +0800737 result = new_token;
Jeremy Compostelladfd24782016-04-26 13:51:27 +0200738 } else {
Bowgo Tsaic3eca502017-06-08 15:16:52 +0800739 result += " " + new_token;
Jeremy Compostelladfd24782016-04-26 13:51:27 +0200740 }
741 }
742
Bowgo Tsaic3eca502017-06-08 15:16:52 +0800743 if (!updated) {
Jeremy Compostelladfd24782016-04-26 13:51:27 +0200744 return;
745 }
746
747 free(*table);
748 *table = strdup(result.c_str());
749}
750
Sandeep Patild2462572017-02-15 14:24:39 -0800751// prepares the verity enabled (MF_VERIFY / MF_VERIFYATBOOT) fstab record for
752// mount. The 'wait_for_verity_dev' parameter makes this function wait for the
753// verity device to get created before return
754int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev)
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100755{
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000756 int retval = FS_MGR_SETUP_VERITY_FAIL;
Paul Lawrenceec900bb2014-10-09 14:22:49 +0000757 int fd = -1;
bowgotsai47aa2a72017-01-09 18:15:41 +0800758 std::string verity_blk_name;
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100759 struct fec_handle *f = NULL;
760 struct fec_verity_metadata verity;
Jeremy Compostelladfd24782016-04-26 13:51:27 +0200761 struct verity_table_params params = { .table = NULL };
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800762
Elliott Hughes246c18c2015-10-09 11:52:00 -0700763 alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800764 struct dm_ioctl *io = (struct dm_ioctl *) buffer;
bowgotsai47aa2a72017-01-09 18:15:41 +0800765 const std::string mount_point(basename(fstab->mount_point));
Prashant Malani2cdc67e2016-10-27 16:15:41 -0700766 bool verified_at_boot = false;
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800767
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100768 if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE,
769 FEC_DEFAULT_ROOTS) < 0) {
bowgotsai47878de2017-01-23 14:04:34 +0800770 PERROR << "Failed to open '" << fstab->blk_device << "'";
Geremy Condra05699b32014-03-17 14:46:51 -0700771 return retval;
772 }
773
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100774 // read verity metadata
775 if (fec_verity_get_metadata(f, &verity) < 0) {
bowgotsai47878de2017-01-23 14:04:34 +0800776 PERROR << "Failed to get verity metadata '" << fstab->blk_device << "'";
Bowgo Tsai7ad31592017-03-06 15:39:06 +0800777 // Allow verity disabled when the device is unlocked without metadata
Bowgo Tsaid1fe3bd2017-07-05 15:37:15 +0800778 if (fs_mgr_is_device_unlocked()) {
779 retval = FS_MGR_SETUP_VERITY_SKIPPED;
Bowgo Tsai7ad31592017-03-06 15:39:06 +0800780 LWARNING << "Allow invalid metadata when the device is unlocked";
781 }
Paul Lawrenceec900bb2014-10-09 14:22:49 +0000782 goto out;
783 }
784
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100785#ifdef ALLOW_ADBD_DISABLE_VERITY
786 if (verity.disabled) {
787 retval = FS_MGR_SETUP_VERITY_DISABLED;
Bowgo Tsai744361f2017-10-11 14:58:40 +0800788 LINFO << "Attempt to cleanly disable verity - only works in USERDEBUG/ENG";
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100789 goto out;
790 }
791#endif
792
793 // read ecc metadata
794 if (fec_ecc_get_metadata(f, &params.ecc) < 0) {
795 params.ecc.valid = false;
796 }
797
798 params.ecc_dev = fstab->blk_device;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000799
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800800 // get the device mapper fd
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800801 if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
bowgotsai47878de2017-01-23 14:04:34 +0800802 PERROR << "Error opening device mapper";
Paul Lawrence88a12fb2014-10-09 09:37:00 -0700803 goto out;
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800804 }
805
806 // create the device
bowgotsai47aa2a72017-01-09 18:15:41 +0800807 if (!fs_mgr_create_verity_device(io, mount_point, fd)) {
bowgotsai47878de2017-01-23 14:04:34 +0800808 LERROR << "Couldn't create verity device!";
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800809 goto out;
810 }
811
812 // get the name of the device file
bowgotsai47aa2a72017-01-09 18:15:41 +0800813 if (!fs_mgr_get_verity_device_name(io, mount_point, fd, &verity_blk_name)) {
bowgotsai47878de2017-01-23 14:04:34 +0800814 LERROR << "Couldn't get verity device number!";
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800815 goto out;
816 }
817
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100818 if (load_verity_state(fstab, &params.mode) < 0) {
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000819 /* if accessing or updating the state failed, switch to the default
820 * safe mode. This makes sure the device won't end up in an endless
821 * restart loop, and no corrupted data will be exposed to userspace
822 * without a warning. */
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100823 params.mode = VERITY_MODE_EIO;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000824 }
825
Jeremy Compostelladfd24782016-04-26 13:51:27 +0200826 if (!verity.table) {
827 goto out;
828 }
829
830 params.table = strdup(verity.table);
831 if (!params.table) {
832 goto out;
833 }
834
Sami Tolvanen1ada1492015-09-21 15:12:29 +0100835 // verify the signature on the table
Sami Tolvanen83012662016-06-03 13:58:26 -0700836 if (verify_verity_signature(verity) < 0) {
Bowgo Tsaib6748942017-07-19 17:27:18 +0800837 // Allow signature verification error when the device is unlocked
838 if (fs_mgr_is_device_unlocked()) {
839 retval = FS_MGR_SETUP_VERITY_SKIPPED;
840 LWARNING << "Allow signature verification error when the device is unlocked";
841 goto out;
842 }
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100843 if (params.mode == VERITY_MODE_LOGGING) {
Sami Tolvanen1ada1492015-09-21 15:12:29 +0100844 // the user has been warned, allow mounting without dm-verity
Bowgo Tsaib6748942017-07-19 17:27:18 +0800845 retval = FS_MGR_SETUP_VERITY_SKIPPED;
Sami Tolvanen1ada1492015-09-21 15:12:29 +0100846 goto out;
847 }
848
849 // invalidate root hash and salt to trigger device-specific recovery
Jeremy Compostelladfd24782016-04-26 13:51:27 +0200850 if (invalidate_table(params.table, verity.table_length) < 0) {
Sami Tolvanen1ada1492015-09-21 15:12:29 +0100851 goto out;
852 }
853 }
854
bowgotsai47878de2017-01-23 14:04:34 +0800855 LINFO << "Enabling dm-verity for " << mount_point.c_str()
856 << " (mode " << params.mode << ")";
Sami Tolvanenacbf9be2015-03-19 10:00:34 +0000857
Bowgo Tsaic3eca502017-06-08 15:16:52 +0800858 // Update the verity params using the actual block device path
859 update_verity_table_blk_device(fstab->blk_device, &params.table,
860 fstab->fs_mgr_flags & MF_SLOTSELECT);
Jeremy Compostelladfd24782016-04-26 13:51:27 +0200861
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800862 // load the verity mapping table
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100863 if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
Sami Tolvanenff980d22015-12-10 00:04:10 +0000864 format_verity_table) == 0) {
865 goto loaded;
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800866 }
867
Sami Tolvanenff980d22015-12-10 00:04:10 +0000868 if (params.ecc.valid) {
869 // kernel may not support error correction, try without
bowgotsai47878de2017-01-23 14:04:34 +0800870 LINFO << "Disabling error correction for " << mount_point.c_str();
Sami Tolvanenff980d22015-12-10 00:04:10 +0000871 params.ecc.valid = false;
872
873 if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
874 format_verity_table) == 0) {
875 goto loaded;
876 }
877 }
878
879 // try the legacy format for backwards compatibility
880 if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
881 format_legacy_verity_table) == 0) {
882 goto loaded;
883 }
884
885 if (params.mode != VERITY_MODE_EIO) {
886 // as a last resort, EIO mode should always be supported
bowgotsai47878de2017-01-23 14:04:34 +0800887 LINFO << "Falling back to EIO mode for " << mount_point.c_str();
Sami Tolvanenff980d22015-12-10 00:04:10 +0000888 params.mode = VERITY_MODE_EIO;
889
890 if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
891 format_legacy_verity_table) == 0) {
892 goto loaded;
893 }
894 }
895
bowgotsai47878de2017-01-23 14:04:34 +0800896 LERROR << "Failed to load verity table for " << mount_point.c_str();
Sami Tolvanenff980d22015-12-10 00:04:10 +0000897 goto out;
898
899loaded:
900
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800901 // activate the device
bowgotsai47aa2a72017-01-09 18:15:41 +0800902 if (!fs_mgr_resume_verity_table(io, mount_point, fd)) {
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800903 goto out;
904 }
905
Sami Tolvanen214f33b2014-12-18 16:15:30 +0000906 // mark the underlying block device as read-only
907 fs_mgr_set_blk_ro(fstab->blk_device);
908
Prashant Malani2cdc67e2016-10-27 16:15:41 -0700909 // Verify the entire partition in one go
910 // If there is an error, allow it to mount as a normal verity partition.
911 if (fstab->fs_mgr_flags & MF_VERIFYATBOOT) {
bowgotsai47878de2017-01-23 14:04:34 +0800912 LINFO << "Verifying partition " << fstab->blk_device << " at boot";
bowgotsai47aa2a72017-01-09 18:15:41 +0800913 int err = read_partition(verity_blk_name.c_str(), verity.data_size);
Prashant Malani2cdc67e2016-10-27 16:15:41 -0700914 if (!err) {
bowgotsai47878de2017-01-23 14:04:34 +0800915 LINFO << "Verified verity partition "
916 << fstab->blk_device << " at boot";
Prashant Malani2cdc67e2016-10-27 16:15:41 -0700917 verified_at_boot = true;
918 }
919 }
920
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800921 // assign the new verity block device as the block device
Prashant Malani2cdc67e2016-10-27 16:15:41 -0700922 if (!verified_at_boot) {
923 free(fstab->blk_device);
bowgotsai47aa2a72017-01-09 18:15:41 +0800924 fstab->blk_device = strdup(verity_blk_name.c_str());
925 } else if (!fs_mgr_destroy_verity_device(io, mount_point, fd)) {
bowgotsai47878de2017-01-23 14:04:34 +0800926 LERROR << "Failed to remove verity device " << mount_point.c_str();
Prashant Malani2cdc67e2016-10-27 16:15:41 -0700927 goto out;
928 }
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800929
Wei Wangdba750e2016-10-26 13:35:27 -0700930 // make sure we've set everything up properly
Jinguang Dong9d344962017-06-13 10:20:34 +0800931 if (wait_for_verity_dev && !fs_mgr_wait_for_file(fstab->blk_device, 1s)) {
Wei Wangdba750e2016-10-26 13:35:27 -0700932 goto out;
933 }
934
Sami Tolvanen86cddf42015-03-05 00:02:28 +0000935 retval = FS_MGR_SETUP_VERITY_SUCCESS;
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800936
937out:
Paul Lawrenceec900bb2014-10-09 14:22:49 +0000938 if (fd != -1) {
939 close(fd);
940 }
941
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100942 fec_close(f);
Jeremy Compostelladfd24782016-04-26 13:51:27 +0200943 free(params.table);
Paul Lawrenceec900bb2014-10-09 14:22:49 +0000944
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800945 return retval;
946}