blob: 6983b72f676f03296e395f995b21328449b5fbf8 [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
Elliott Hughesccecf142014-01-16 10:53:11 -080017#include <inttypes.h>
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080018#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <unistd.h>
22#include <fcntl.h>
23#include <ctype.h>
24#include <sys/mount.h>
25#include <sys/stat.h>
26#include <errno.h>
27#include <sys/types.h>
28#include <sys/wait.h>
29#include <libgen.h>
30#include <time.h>
31
Johan Redestig67b3cad2015-10-08 21:36:35 +020032#include <base/file.h>
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080033#include <private/android_filesystem_config.h>
Geremy Condra05699b32014-03-17 14:46:51 -070034#include <cutils/properties.h>
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080035#include <logwrap/logwrap.h>
36
37#include "mincrypt/rsa.h"
38#include "mincrypt/sha.h"
39#include "mincrypt/sha256.h"
40
Sami Tolvanen99e3a922015-05-22 15:43:50 +010041#include "fec/io.h"
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080042
Elliott Hughes246c18c2015-10-09 11:52:00 -070043#include "fs_mgr.h"
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080044#include "fs_mgr_priv.h"
45#include "fs_mgr_priv_verity.h"
46
Sami Tolvanen51bf11a2015-02-16 10:27:21 +000047#define FSTAB_PREFIX "/fstab."
48
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
Sami Tolvanen946a0f32015-03-22 12:40:05 +000075#define __STRINGIFY(x) #x
76#define STRINGIFY(x) __STRINGIFY(x)
77
Sami Tolvanen51bf11a2015-02-16 10:27:21 +000078struct verity_state {
79 uint32_t header;
80 uint32_t version;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +000081 int32_t mode;
82};
83
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080084extern struct fs_info info;
85
Elliott Hughes246c18c2015-10-09 11:52:00 -070086static RSAPublicKey *load_key(const char *path)
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080087{
Elliott Hughes246c18c2015-10-09 11:52:00 -070088 RSAPublicKey* key = static_cast<RSAPublicKey*>(malloc(sizeof(RSAPublicKey)));
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080089 if (!key) {
90 ERROR("Can't malloc key\n");
91 return NULL;
92 }
93
Elliott Hughes246c18c2015-10-09 11:52:00 -070094 FILE* f = fopen(path, "r");
Geremy Condra3ad3d1c2013-02-22 18:11:41 -080095 if (!f) {
96 ERROR("Can't open '%s'\n", path);
97 free(key);
98 return NULL;
99 }
100
101 if (!fread(key, sizeof(*key), 1, f)) {
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100102 ERROR("Could not read key!\n");
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800103 fclose(f);
104 free(key);
105 return NULL;
106 }
107
108 if (key->len != RSANUMWORDS) {
109 ERROR("Invalid key length %d\n", key->len);
110 fclose(f);
111 free(key);
112 return NULL;
113 }
114
115 fclose(f);
116 return key;
117}
118
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100119static int verify_table(const uint8_t *signature, const char *table,
120 uint32_t table_length)
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800121{
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800122 RSAPublicKey *key;
Sami Tolvanen9573a132014-11-06 20:33:07 -0800123 uint8_t hash_buf[SHA256_DIGEST_SIZE];
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800124 int retval = -1;
125
126 // Hash the table
Sami Tolvanen9573a132014-11-06 20:33:07 -0800127 SHA256_hash((uint8_t*)table, table_length, hash_buf);
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800128
129 // Now get the public key from the keyfile
130 key = load_key(VERITY_TABLE_RSA_KEY);
131 if (!key) {
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100132 ERROR("Couldn't load verity keys\n");
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800133 goto out;
134 }
135
136 // verify the result
137 if (!RSA_verify(key,
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100138 signature,
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800139 RSANUMBYTES,
140 (uint8_t*) hash_buf,
Sami Tolvanen9573a132014-11-06 20:33:07 -0800141 SHA256_DIGEST_SIZE)) {
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100142 ERROR("Couldn't verify table\n");
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800143 goto out;
144 }
145
146 retval = 0;
147
148out:
149 free(key);
150 return retval;
151}
152
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100153static int invalidate_table(char *table, size_t table_length)
Sami Tolvanen1ada1492015-09-21 15:12:29 +0100154{
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100155 size_t n = 0;
156 size_t idx = 0;
157 size_t cleared = 0;
Sami Tolvanen1ada1492015-09-21 15:12:29 +0100158
159 while (n < table_length) {
160 if (table[n++] == ' ') {
161 ++idx;
162 }
163
164 if (idx != VERITY_TABLE_HASH_IDX && idx != VERITY_TABLE_SALT_IDX) {
165 continue;
166 }
167
168 while (n < table_length && table[n] != ' ') {
169 table[n++] = '0';
170 }
171
172 if (++cleared == 2) {
173 return 0;
174 }
175 }
176
177 return -1;
178}
179
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800180static void verity_ioctl_init(struct dm_ioctl *io, char *name, unsigned flags)
181{
182 memset(io, 0, DM_BUF_SIZE);
183 io->data_size = DM_BUF_SIZE;
184 io->data_start = sizeof(struct dm_ioctl);
185 io->version[0] = 4;
186 io->version[1] = 0;
187 io->version[2] = 0;
188 io->flags = flags | DM_READONLY_FLAG;
189 if (name) {
190 strlcpy(io->name, name, sizeof(io->name));
191 }
192}
193
194static int create_verity_device(struct dm_ioctl *io, char *name, int fd)
195{
196 verity_ioctl_init(io, name, 1);
197 if (ioctl(fd, DM_DEV_CREATE, io)) {
198 ERROR("Error creating device mapping (%s)", strerror(errno));
199 return -1;
200 }
201 return 0;
202}
203
204static int get_verity_device_name(struct dm_ioctl *io, char *name, int fd, char **dev_name)
205{
206 verity_ioctl_init(io, name, 0);
207 if (ioctl(fd, DM_DEV_STATUS, io)) {
208 ERROR("Error fetching verity device number (%s)", strerror(errno));
209 return -1;
210 }
211 int dev_num = (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00);
212 if (asprintf(dev_name, "/dev/block/dm-%u", dev_num) < 0) {
213 ERROR("Error getting verity block device name (%s)", strerror(errno));
214 return -1;
215 }
216 return 0;
217}
218
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100219struct verity_table_params {
220 const char *table;
221 int mode;
222 struct fec_ecc_metadata ecc;
223 const char *ecc_dev;
224};
225
226typedef bool (*format_verity_table_func)(char *buf, const size_t bufsize,
227 const struct verity_table_params *params);
228
229static bool format_verity_table(char *buf, const size_t bufsize,
230 const struct verity_table_params *params)
231{
232 const char *mode_flag = NULL;
233 int res = -1;
234
235 if (params->mode == VERITY_MODE_RESTART) {
236 mode_flag = VERITY_TABLE_OPT_RESTART;
237 } else if (params->mode == VERITY_MODE_LOGGING) {
238 mode_flag = VERITY_TABLE_OPT_LOGGING;
239 }
240
241 if (params->ecc.valid) {
242 if (mode_flag) {
243 res = snprintf(buf, bufsize,
244 "%s %u %s " VERITY_TABLE_OPT_FEC_FORMAT,
245 params->table, 1 + VERITY_TABLE_OPT_FEC_ARGS, mode_flag, params->ecc_dev,
246 params->ecc.start / FEC_BLOCKSIZE, params->ecc.blocks, params->ecc.roots);
247 } else {
248 res = snprintf(buf, bufsize,
249 "%s %u " VERITY_TABLE_OPT_FEC_FORMAT,
250 params->table, VERITY_TABLE_OPT_FEC_ARGS, params->ecc_dev,
251 params->ecc.start / FEC_BLOCKSIZE, params->ecc.blocks, params->ecc.roots);
252 }
253 } else if (mode_flag) {
254 res = snprintf(buf, bufsize, "%s 2 " VERITY_TABLE_OPT_IGNZERO " %s", params->table,
255 mode_flag);
256 } else {
257 res = strlcpy(buf, params->table, bufsize);
258 }
259
260 if (res < 0 || (size_t)res >= bufsize) {
261 ERROR("Error building verity table; insufficient buffer size?\n");
262 return false;
263 }
264
265 return true;
266}
267
268static bool format_legacy_verity_table(char *buf, const size_t bufsize,
269 const struct verity_table_params *params)
270{
271 int res;
272
273 if (params->mode == VERITY_MODE_EIO) {
274 res = strlcpy(buf, params->table, bufsize);
275 } else {
276 res = snprintf(buf, bufsize, "%s %d", params->table, params->mode);
277 }
278
279 if (res < 0 || (size_t)res >= bufsize) {
280 ERROR("Error building verity table; insufficient buffer size?\n");
281 return false;
282 }
283
284 return true;
285}
286
287static int load_verity_table(struct dm_ioctl *io, char *name, uint64_t device_size, int fd,
288 const struct verity_table_params *params, format_verity_table_func format)
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800289{
290 char *verity_params;
291 char *buffer = (char*) io;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000292 size_t bufsize;
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800293
294 verity_ioctl_init(io, name, DM_STATUS_TABLE_FLAG);
295
296 struct dm_target_spec *tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
297
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100298 // set tgt arguments
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800299 io->target_count = 1;
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100300 tgt->status = 0;
301 tgt->sector_start = 0;
302 tgt->length = device_size / 512;
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800303 strcpy(tgt->target_type, "verity");
304
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100305 // build the verity params
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800306 verity_params = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000307 bufsize = DM_BUF_SIZE - (verity_params - buffer);
308
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100309 if (!format(verity_params, bufsize, params)) {
310 ERROR("Failed to format verity parameters\n");
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000311 return -1;
312 }
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800313
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100314 INFO("loading verity table: '%s'", verity_params);
315
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800316 // set next target boundary
317 verity_params += strlen(verity_params) + 1;
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100318 verity_params = (char*)(((unsigned long)verity_params + 7) & ~8);
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800319 tgt->next = verity_params - buffer;
320
321 // send the ioctl to load the verity table
322 if (ioctl(fd, DM_TABLE_LOAD, io)) {
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100323 ERROR("Error loading verity table (%s)\n", strerror(errno));
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800324 return -1;
325 }
326
327 return 0;
328}
329
330static int resume_verity_table(struct dm_ioctl *io, char *name, int fd)
331{
332 verity_ioctl_init(io, name, 0);
333 if (ioctl(fd, DM_DEV_SUSPEND, io)) {
334 ERROR("Error activating verity device (%s)", strerror(errno));
335 return -1;
336 }
337 return 0;
338}
339
340static int test_access(char *device) {
341 int tries = 25;
342 while (tries--) {
343 if (!access(device, F_OK) || errno != ENOENT) {
344 return 0;
345 }
346 usleep(40 * 1000);
347 }
348 return -1;
349}
350
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000351static int check_verity_restart(const char *fname)
352{
353 char buffer[VERITY_KMSG_BUFSIZE + 1];
354 int fd;
355 int rc = 0;
356 ssize_t size;
357 struct stat s;
358
359 fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
360
361 if (fd == -1) {
362 if (errno != ENOENT) {
363 ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
364 }
365 goto out;
366 }
367
368 if (fstat(fd, &s) == -1) {
369 ERROR("Failed to fstat %s (%s)\n", fname, strerror(errno));
370 goto out;
371 }
372
373 size = VERITY_KMSG_BUFSIZE;
374
375 if (size > s.st_size) {
376 size = s.st_size;
377 }
378
379 if (lseek(fd, s.st_size - size, SEEK_SET) == -1) {
Andreas Gampeeb69e852015-03-04 13:29:12 -0800380 ERROR("Failed to lseek %jd %s (%s)\n", (intmax_t)(s.st_size - size), fname,
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000381 strerror(errno));
382 goto out;
383 }
384
Johan Redestig67b3cad2015-10-08 21:36:35 +0200385 if (!android::base::ReadFully(fd, buffer, size)) {
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000386 ERROR("Failed to read %zd bytes from %s (%s)\n", size, fname,
387 strerror(errno));
388 goto out;
389 }
390
391 buffer[size] = '\0';
392
393 if (strstr(buffer, VERITY_KMSG_RESTART) != NULL) {
394 rc = 1;
395 }
396
397out:
398 if (fd != -1) {
Elliott Hughes47b01342015-05-15 19:16:40 -0700399 close(fd);
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000400 }
401
402 return rc;
403}
404
405static int was_verity_restart()
406{
407 static const char *files[] = {
408 "/sys/fs/pstore/console-ramoops",
409 "/proc/last_kmsg",
410 NULL
411 };
412 int i;
413
414 for (i = 0; files[i]; ++i) {
415 if (check_verity_restart(files[i])) {
416 return 1;
417 }
418 }
419
420 return 0;
421}
422
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000423static int metadata_add(FILE *fp, long start, const char *tag,
424 unsigned int length, off64_t *offset)
425{
Sami Tolvanen4d3ead92015-03-26 08:07:45 +0000426 if (fseek(fp, start, SEEK_SET) < 0 ||
427 fprintf(fp, "%s %u\n", tag, length) < 0) {
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000428 return -1;
429 }
430
431 *offset = ftell(fp);
432
Sami Tolvanen4d3ead92015-03-26 08:07:45 +0000433 if (fseek(fp, length, SEEK_CUR) < 0 ||
434 fprintf(fp, METADATA_EOD " 0\n") < 0) {
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000435 return -1;
436 }
437
438 return 0;
439}
440
441static int metadata_find(const char *fname, const char *stag,
442 unsigned int slength, off64_t *offset)
443{
444 FILE *fp = NULL;
445 char tag[METADATA_TAG_MAX_LENGTH + 1];
446 int rc = -1;
447 int n;
448 long start = 0x4000; /* skip cryptfs metadata area */
449 uint32_t magic;
450 unsigned int length = 0;
451
452 if (!fname) {
453 return -1;
454 }
455
Sami Tolvanen4d3ead92015-03-26 08:07:45 +0000456 fp = fopen(fname, "r+");
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000457
458 if (!fp) {
459 ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
460 goto out;
461 }
462
463 /* check magic */
Sami Tolvanen4d3ead92015-03-26 08:07:45 +0000464 if (fseek(fp, start, SEEK_SET) < 0 ||
465 fread(&magic, sizeof(magic), 1, fp) != 1) {
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000466 ERROR("Failed to read magic from %s (%s)\n", fname, strerror(errno));
467 goto out;
468 }
469
470 if (magic != METADATA_MAGIC) {
471 magic = METADATA_MAGIC;
472
Sami Tolvanen4d3ead92015-03-26 08:07:45 +0000473 if (fseek(fp, start, SEEK_SET) < 0 ||
474 fwrite(&magic, sizeof(magic), 1, fp) != 1) {
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000475 ERROR("Failed to write magic to %s (%s)\n", fname, strerror(errno));
476 goto out;
477 }
478
479 rc = metadata_add(fp, start + sizeof(magic), stag, slength, offset);
480 if (rc < 0) {
481 ERROR("Failed to add metadata to %s: %s\n", fname, strerror(errno));
482 }
483
484 goto out;
485 }
486
487 start += sizeof(magic);
488
489 while (1) {
Sami Tolvanen4d3ead92015-03-26 08:07:45 +0000490 n = fscanf(fp, "%" STRINGIFY(METADATA_TAG_MAX_LENGTH) "s %u\n",
491 tag, &length);
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000492
493 if (n == 2 && strcmp(tag, METADATA_EOD)) {
494 /* found a tag */
495 start = ftell(fp);
496
497 if (!strcmp(tag, stag) && length == slength) {
498 *offset = start;
499 rc = 0;
500 goto out;
501 }
502
503 start += length;
504
Sami Tolvanen4d3ead92015-03-26 08:07:45 +0000505 if (fseek(fp, length, SEEK_CUR) < 0) {
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000506 ERROR("Failed to seek %s (%s)\n", fname, strerror(errno));
507 goto out;
508 }
509 } else {
510 rc = metadata_add(fp, start, stag, slength, offset);
511 if (rc < 0) {
512 ERROR("Failed to write metadata to %s: %s\n", fname,
513 strerror(errno));
514 }
515 goto out;
516 }
517 }
518
519out:
520 if (fp) {
Sami Tolvanen4d3ead92015-03-26 08:07:45 +0000521 fflush(fp);
522 fclose(fp);
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000523 }
524
525 return rc;
526}
527
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000528static int write_verity_state(const char *fname, off64_t offset, int32_t mode)
529{
530 int fd;
531 int rc = -1;
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000532 struct verity_state s = { VERITY_STATE_HEADER, VERITY_STATE_VERSION, mode };
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000533
534 fd = TEMP_FAILURE_RETRY(open(fname, O_WRONLY | O_SYNC | O_CLOEXEC));
535
536 if (fd == -1) {
537 ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
538 goto out;
539 }
540
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000541 if (TEMP_FAILURE_RETRY(pwrite64(fd, &s, sizeof(s), offset)) != sizeof(s)) {
542 ERROR("Failed to write %zu bytes to %s to offset %" PRIu64 " (%s)\n",
543 sizeof(s), fname, offset, strerror(errno));
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000544 goto out;
545 }
546
547 rc = 0;
548
549out:
550 if (fd != -1) {
Elliott Hughes47b01342015-05-15 19:16:40 -0700551 close(fd);
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000552 }
553
554 return rc;
555}
556
Sami Tolvanen45474232015-03-30 11:38:38 +0100557static int read_verity_state(const char *fname, off64_t offset, int *mode)
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000558{
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000559 int fd = -1;
560 int rc = -1;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000561 struct verity_state s;
562
Sami Tolvanen45474232015-03-30 11:38:38 +0100563 fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000564
565 if (fd == -1) {
Sami Tolvanen45474232015-03-30 11:38:38 +0100566 ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000567 goto out;
568 }
569
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000570 if (TEMP_FAILURE_RETRY(pread64(fd, &s, sizeof(s), offset)) != sizeof(s)) {
571 ERROR("Failed to read %zu bytes from %s offset %" PRIu64 " (%s)\n",
Sami Tolvanen45474232015-03-30 11:38:38 +0100572 sizeof(s), fname, offset, strerror(errno));
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000573 goto out;
574 }
575
576 if (s.header != VERITY_STATE_HEADER) {
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000577 /* space allocated, but no state written. write default state */
578 *mode = VERITY_MODE_DEFAULT;
Sami Tolvanen45474232015-03-30 11:38:38 +0100579 rc = write_verity_state(fname, offset, *mode);
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000580 goto out;
581 }
582
583 if (s.version != VERITY_STATE_VERSION) {
584 ERROR("Unsupported verity state version (%u)\n", s.version);
585 goto out;
586 }
587
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000588 if (s.mode < VERITY_MODE_EIO ||
589 s.mode > VERITY_MODE_LAST) {
590 ERROR("Unsupported verity mode (%u)\n", s.mode);
591 goto out;
592 }
593
594 *mode = s.mode;
595 rc = 0;
596
597out:
598 if (fd != -1) {
Elliott Hughes47b01342015-05-15 19:16:40 -0700599 close(fd);
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000600 }
601
602 return rc;
603}
604
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100605static int compare_last_signature(struct fstab_rec *fstab, int *match)
606{
607 char tag[METADATA_TAG_MAX_LENGTH + 1];
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100608 int fd = -1;
609 int rc = -1;
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100610 off64_t offset = 0;
611 struct fec_handle *f = NULL;
612 struct fec_verity_metadata verity;
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100613 uint8_t curr[SHA256_DIGEST_SIZE];
614 uint8_t prev[SHA256_DIGEST_SIZE];
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100615
616 *match = 1;
617
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100618 if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE,
619 FEC_DEFAULT_ROOTS) == -1) {
620 ERROR("Failed to open '%s' (%s)\n", fstab->blk_device,
621 strerror(errno));
622 return rc;
623 }
624
625 // read verity metadata
626 if (fec_verity_get_metadata(f, &verity) == -1) {
627 ERROR("Failed to get verity metadata '%s' (%s)\n", fstab->blk_device,
628 strerror(errno));
Mohamad Ayyash030ef3592015-04-08 17:59:19 -0700629 goto out;
630 }
631
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100632 SHA256_hash(verity.signature, RSANUMBYTES, curr);
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100633
634 if (snprintf(tag, sizeof(tag), VERITY_LASTSIG_TAG "_%s",
635 basename(fstab->mount_point)) >= (int)sizeof(tag)) {
636 ERROR("Metadata tag name too long for %s\n", fstab->mount_point);
637 goto out;
638 }
639
640 if (metadata_find(fstab->verity_loc, tag, SHA256_DIGEST_SIZE,
641 &offset) < 0) {
642 goto out;
643 }
644
645 fd = TEMP_FAILURE_RETRY(open(fstab->verity_loc, O_RDWR | O_SYNC | O_CLOEXEC));
646
647 if (fd == -1) {
648 ERROR("Failed to open %s: %s\n", fstab->verity_loc, strerror(errno));
649 goto out;
650 }
651
652 if (TEMP_FAILURE_RETRY(pread64(fd, prev, sizeof(prev),
653 offset)) != sizeof(prev)) {
654 ERROR("Failed to read %zu bytes from %s offset %" PRIu64 " (%s)\n",
655 sizeof(prev), fstab->verity_loc, offset, strerror(errno));
656 goto out;
657 }
658
659 *match = !memcmp(curr, prev, SHA256_DIGEST_SIZE);
660
661 if (!*match) {
662 /* update current signature hash */
663 if (TEMP_FAILURE_RETRY(pwrite64(fd, curr, sizeof(curr),
664 offset)) != sizeof(curr)) {
665 ERROR("Failed to write %zu bytes to %s offset %" PRIu64 " (%s)\n",
666 sizeof(curr), fstab->verity_loc, offset, strerror(errno));
667 goto out;
668 }
669 }
670
671 rc = 0;
672
673out:
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100674 fec_close(f);
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100675 return rc;
676}
677
678static int get_verity_state_offset(struct fstab_rec *fstab, off64_t *offset)
679{
680 char tag[METADATA_TAG_MAX_LENGTH + 1];
681
682 if (snprintf(tag, sizeof(tag), VERITY_STATE_TAG "_%s",
683 basename(fstab->mount_point)) >= (int)sizeof(tag)) {
684 ERROR("Metadata tag name too long for %s\n", fstab->mount_point);
685 return -1;
686 }
687
688 return metadata_find(fstab->verity_loc, tag, sizeof(struct verity_state),
689 offset);
690}
691
Sami Tolvanen45474232015-03-30 11:38:38 +0100692static int load_verity_state(struct fstab_rec *fstab, int *mode)
693{
Sami Tolvanenac5c1222015-06-03 12:33:07 +0100694 char propbuf[PROPERTY_VALUE_MAX];
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100695 int match = 0;
Sami Tolvanenac5c1222015-06-03 12:33:07 +0100696 off64_t offset = 0;
697
698 /* use the kernel parameter if set */
699 property_get("ro.boot.veritymode", propbuf, "");
700
701 if (*propbuf != '\0') {
702 if (!strcmp(propbuf, "enforcing")) {
703 *mode = VERITY_MODE_DEFAULT;
704 return 0;
705 } else if (!strcmp(propbuf, "logging")) {
706 *mode = VERITY_MODE_LOGGING;
707 return 0;
708 } else {
709 INFO("Unknown value %s for veritymode; ignoring", propbuf);
710 }
711 }
Sami Tolvanen45474232015-03-30 11:38:38 +0100712
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100713 if (get_verity_state_offset(fstab, &offset) < 0) {
Sami Tolvanen45474232015-03-30 11:38:38 +0100714 /* fall back to stateless behavior */
715 *mode = VERITY_MODE_EIO;
716 return 0;
717 }
718
719 if (was_verity_restart()) {
720 /* device was restarted after dm-verity detected a corrupted
721 * block, so switch to logging mode */
722 *mode = VERITY_MODE_LOGGING;
723 return write_verity_state(fstab->verity_loc, offset, *mode);
724 }
725
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100726 if (!compare_last_signature(fstab, &match) && !match) {
727 /* partition has been reflashed, reset dm-verity state */
728 *mode = VERITY_MODE_DEFAULT;
729 return write_verity_state(fstab->verity_loc, offset, *mode);
730 }
731
Sami Tolvanen45474232015-03-30 11:38:38 +0100732 return read_verity_state(fstab->verity_loc, offset, mode);
733}
734
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000735int fs_mgr_load_verity_state(int *mode)
736{
737 char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
738 char propbuf[PROPERTY_VALUE_MAX];
739 int rc = -1;
740 int i;
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100741 int current;
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000742 struct fstab *fstab = NULL;
743
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100744 /* return the default mode, unless any of the verified partitions are in
745 * logging mode, in which case return that */
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000746 *mode = VERITY_MODE_DEFAULT;
747
748 property_get("ro.hardware", propbuf, "");
749 snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
750
751 fstab = fs_mgr_read_fstab(fstab_filename);
752
753 if (!fstab) {
754 ERROR("Failed to read %s\n", fstab_filename);
755 goto out;
756 }
757
758 for (i = 0; i < fstab->num_entries; i++) {
759 if (!fs_mgr_is_verified(&fstab->recs[i])) {
760 continue;
761 }
762
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100763 rc = load_verity_state(&fstab->recs[i], &current);
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000764 if (rc < 0) {
765 continue;
766 }
767
Sami Tolvanen25b230c2015-10-30 13:11:00 +0000768 if (current != VERITY_MODE_DEFAULT) {
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100769 *mode = current;
Sami Tolvanen25b230c2015-10-30 13:11:00 +0000770 break;
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000771 }
772 }
773
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000774 rc = 0;
775
776out:
777 if (fstab) {
778 fs_mgr_free_fstab(fstab);
779 }
780
781 return rc;
782}
783
Sami Tolvanenacbf9be2015-03-19 10:00:34 +0000784int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback)
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000785{
Elliott Hughes246c18c2015-10-09 11:52:00 -0700786 alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
Sami Tolvanen2f425542015-06-19 16:08:41 +0100787 bool use_state = true;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000788 char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
789 char *mount_point;
790 char propbuf[PROPERTY_VALUE_MAX];
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000791 char *status;
792 int fd = -1;
793 int i;
Sami Tolvanen45474232015-03-30 11:38:38 +0100794 int mode;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000795 int rc = -1;
796 off64_t offset = 0;
797 struct dm_ioctl *io = (struct dm_ioctl *) buffer;
798 struct fstab *fstab = NULL;
799
Sami Tolvanenac5c1222015-06-03 12:33:07 +0100800 /* check if we need to store the state */
801 property_get("ro.boot.veritymode", propbuf, "");
802
803 if (*propbuf != '\0') {
Sami Tolvanen2f425542015-06-19 16:08:41 +0100804 use_state = false; /* state is kept by the bootloader */
Sami Tolvanenac5c1222015-06-03 12:33:07 +0100805 }
806
Sami Tolvanen25b230c2015-10-30 13:11:00 +0000807 if (fs_mgr_load_verity_state(&mode) == -1) {
808 return -1;
809 }
810
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000811 fd = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
812
813 if (fd == -1) {
814 ERROR("Error opening device mapper (%s)\n", strerror(errno));
815 goto out;
816 }
817
818 property_get("ro.hardware", propbuf, "");
819 snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
820
821 fstab = fs_mgr_read_fstab(fstab_filename);
822
823 if (!fstab) {
824 ERROR("Failed to read %s\n", fstab_filename);
825 goto out;
826 }
827
828 for (i = 0; i < fstab->num_entries; i++) {
829 if (!fs_mgr_is_verified(&fstab->recs[i])) {
830 continue;
831 }
832
833 mount_point = basename(fstab->recs[i].mount_point);
834 verity_ioctl_init(io, mount_point, 0);
835
836 if (ioctl(fd, DM_TABLE_STATUS, io)) {
837 ERROR("Failed to query DM_TABLE_STATUS for %s (%s)\n", mount_point,
838 strerror(errno));
Sami Tolvanen45474232015-03-30 11:38:38 +0100839 continue;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000840 }
841
842 status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
843
Sami Tolvanen25b230c2015-10-30 13:11:00 +0000844 if (use_state && *status == 'C') {
Sami Tolvanen45474232015-03-30 11:38:38 +0100845 if (write_verity_state(fstab->recs[i].verity_loc, offset,
846 VERITY_MODE_LOGGING) < 0) {
847 continue;
Sami Tolvanenacbf9be2015-03-19 10:00:34 +0000848 }
849 }
850
851 if (callback) {
Sami Tolvanen45474232015-03-30 11:38:38 +0100852 callback(&fstab->recs[i], mount_point, mode, *status);
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000853 }
854 }
855
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000856 rc = 0;
857
858out:
859 if (fstab) {
860 fs_mgr_free_fstab(fstab);
861 }
862
863 if (fd) {
Elliott Hughes47b01342015-05-15 19:16:40 -0700864 close(fd);
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000865 }
866
867 return rc;
868}
869
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100870int fs_mgr_setup_verity(struct fstab_rec *fstab)
871{
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000872 int retval = FS_MGR_SETUP_VERITY_FAIL;
Paul Lawrenceec900bb2014-10-09 14:22:49 +0000873 int fd = -1;
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100874 char *invalid_table = NULL;
875 char *verity_blk_name = NULL;
876 struct fec_handle *f = NULL;
877 struct fec_verity_metadata verity;
878 struct verity_table_params params;
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800879
Elliott Hughes246c18c2015-10-09 11:52:00 -0700880 alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800881 struct dm_ioctl *io = (struct dm_ioctl *) buffer;
882 char *mount_point = basename(fstab->mount_point);
883
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100884 if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE,
885 FEC_DEFAULT_ROOTS) < 0) {
886 ERROR("Failed to open '%s' (%s)\n", fstab->blk_device,
887 strerror(errno));
Geremy Condra05699b32014-03-17 14:46:51 -0700888 return retval;
889 }
890
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100891 // read verity metadata
892 if (fec_verity_get_metadata(f, &verity) < 0) {
893 ERROR("Failed to get verity metadata '%s' (%s)\n", fstab->blk_device,
894 strerror(errno));
Paul Lawrenceec900bb2014-10-09 14:22:49 +0000895 goto out;
896 }
897
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100898#ifdef ALLOW_ADBD_DISABLE_VERITY
899 if (verity.disabled) {
900 retval = FS_MGR_SETUP_VERITY_DISABLED;
901 INFO("Attempt to cleanly disable verity - only works in USERDEBUG\n");
902 goto out;
903 }
904#endif
905
906 // read ecc metadata
907 if (fec_ecc_get_metadata(f, &params.ecc) < 0) {
908 params.ecc.valid = false;
909 }
910
911 params.ecc_dev = fstab->blk_device;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000912
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800913 // get the device mapper fd
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800914 if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100915 ERROR("Error opening device mapper (%s)\n", strerror(errno));
Paul Lawrence88a12fb2014-10-09 09:37:00 -0700916 goto out;
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800917 }
918
919 // create the device
920 if (create_verity_device(io, mount_point, fd) < 0) {
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100921 ERROR("Couldn't create verity device!\n");
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800922 goto out;
923 }
924
925 // get the name of the device file
926 if (get_verity_device_name(io, mount_point, fd, &verity_blk_name) < 0) {
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100927 ERROR("Couldn't get verity device number!\n");
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800928 goto out;
929 }
930
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100931 if (load_verity_state(fstab, &params.mode) < 0) {
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000932 /* if accessing or updating the state failed, switch to the default
933 * safe mode. This makes sure the device won't end up in an endless
934 * restart loop, and no corrupted data will be exposed to userspace
935 * without a warning. */
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100936 params.mode = VERITY_MODE_EIO;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000937 }
938
Sami Tolvanen1ada1492015-09-21 15:12:29 +0100939 // verify the signature on the table
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100940 if (verify_table(verity.signature, verity.table,
941 verity.table_length) < 0) {
942 if (params.mode == VERITY_MODE_LOGGING) {
Sami Tolvanen1ada1492015-09-21 15:12:29 +0100943 // the user has been warned, allow mounting without dm-verity
944 retval = FS_MGR_SETUP_VERITY_SUCCESS;
945 goto out;
946 }
947
948 // invalidate root hash and salt to trigger device-specific recovery
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100949 invalid_table = strdup(verity.table);
950
951 if (!invalid_table ||
952 invalidate_table(invalid_table, verity.table_length) < 0) {
Sami Tolvanen1ada1492015-09-21 15:12:29 +0100953 goto out;
954 }
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100955
956 params.table = invalid_table;
957 } else {
958 params.table = verity.table;
Sami Tolvanen1ada1492015-09-21 15:12:29 +0100959 }
960
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100961 INFO("Enabling dm-verity for %s (mode %d)\n", mount_point, params.mode);
Sami Tolvanenacbf9be2015-03-19 10:00:34 +0000962
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800963 // load the verity mapping table
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100964 if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
965 format_verity_table) < 0 &&
966 // try the legacy format for backwards compatibility
967 load_verity_table(io, mount_point, verity.data_size, fd, &params,
968 format_legacy_verity_table) < 0) {
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800969 goto out;
970 }
971
972 // activate the device
973 if (resume_verity_table(io, mount_point, fd) < 0) {
974 goto out;
975 }
976
Sami Tolvanen214f33b2014-12-18 16:15:30 +0000977 // mark the underlying block device as read-only
978 fs_mgr_set_blk_ro(fstab->blk_device);
979
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800980 // assign the new verity block device as the block device
981 free(fstab->blk_device);
982 fstab->blk_device = verity_blk_name;
Paul Lawrenceec900bb2014-10-09 14:22:49 +0000983 verity_blk_name = 0;
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800984
985 // make sure we've set everything up properly
986 if (test_access(fstab->blk_device) < 0) {
987 goto out;
988 }
989
Sami Tolvanen86cddf42015-03-05 00:02:28 +0000990 retval = FS_MGR_SETUP_VERITY_SUCCESS;
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800991
992out:
Paul Lawrenceec900bb2014-10-09 14:22:49 +0000993 if (fd != -1) {
994 close(fd);
995 }
996
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100997 fec_close(f);
998 free(invalid_table);
Paul Lawrence88a12fb2014-10-09 09:37:00 -0700999 free(verity_blk_name);
Paul Lawrenceec900bb2014-10-09 14:22:49 +00001000
Geremy Condra3ad3d1c2013-02-22 18:11:41 -08001001 return retval;
1002}