blob: c73c1e0f3e24d1ecd3b52f856a7dce8120f6317c [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
Elliott Hughes4f713192015-12-04 22:00:26 -080032#include <android-base/file.h>
Jeremy Compostella32cabf22016-04-26 13:51:27 +020033#include <android-base/strings.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 {
Jeremy Compostella32cabf22016-04-26 13:51:27 +0200220 char *table;
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100221 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 {
Sami Tolvanenff980d22015-12-10 00:04:10 +0000257 res = snprintf(buf, bufsize, "%s 1 " VERITY_TABLE_OPT_IGNZERO, params->table);
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100258 }
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
Sami Tolvanen90f52df2015-12-02 14:23:09 +0000698 /* unless otherwise specified, use EIO mode */
699 *mode = VERITY_MODE_EIO;
700
Sami Tolvanenac5c1222015-06-03 12:33:07 +0100701 /* use the kernel parameter if set */
702 property_get("ro.boot.veritymode", propbuf, "");
703
704 if (*propbuf != '\0') {
705 if (!strcmp(propbuf, "enforcing")) {
706 *mode = VERITY_MODE_DEFAULT;
Sami Tolvanenac5c1222015-06-03 12:33:07 +0100707 }
Sami Tolvanen90f52df2015-12-02 14:23:09 +0000708 return 0;
Sami Tolvanenac5c1222015-06-03 12:33:07 +0100709 }
Sami Tolvanen45474232015-03-30 11:38:38 +0100710
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100711 if (get_verity_state_offset(fstab, &offset) < 0) {
Sami Tolvanen45474232015-03-30 11:38:38 +0100712 /* fall back to stateless behavior */
Sami Tolvanen45474232015-03-30 11:38:38 +0100713 return 0;
714 }
715
716 if (was_verity_restart()) {
717 /* device was restarted after dm-verity detected a corrupted
Sami Tolvanen90f52df2015-12-02 14:23:09 +0000718 * block, so use EIO mode */
Sami Tolvanen45474232015-03-30 11:38:38 +0100719 return write_verity_state(fstab->verity_loc, offset, *mode);
720 }
721
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100722 if (!compare_last_signature(fstab, &match) && !match) {
723 /* partition has been reflashed, reset dm-verity state */
724 *mode = VERITY_MODE_DEFAULT;
725 return write_verity_state(fstab->verity_loc, offset, *mode);
726 }
727
Sami Tolvanen45474232015-03-30 11:38:38 +0100728 return read_verity_state(fstab->verity_loc, offset, mode);
729}
730
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000731int fs_mgr_load_verity_state(int *mode)
732{
733 char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
734 char propbuf[PROPERTY_VALUE_MAX];
735 int rc = -1;
736 int i;
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100737 int current;
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000738 struct fstab *fstab = NULL;
739
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100740 /* return the default mode, unless any of the verified partitions are in
741 * logging mode, in which case return that */
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000742 *mode = VERITY_MODE_DEFAULT;
743
744 property_get("ro.hardware", propbuf, "");
745 snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
746
747 fstab = fs_mgr_read_fstab(fstab_filename);
748
749 if (!fstab) {
750 ERROR("Failed to read %s\n", fstab_filename);
751 goto out;
752 }
753
754 for (i = 0; i < fstab->num_entries; i++) {
755 if (!fs_mgr_is_verified(&fstab->recs[i])) {
756 continue;
757 }
758
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100759 rc = load_verity_state(&fstab->recs[i], &current);
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000760 if (rc < 0) {
761 continue;
762 }
763
Sami Tolvanen25b230c2015-10-30 13:11:00 +0000764 if (current != VERITY_MODE_DEFAULT) {
Sami Tolvanen6122edb2015-03-31 14:36:03 +0100765 *mode = current;
Sami Tolvanen25b230c2015-10-30 13:11:00 +0000766 break;
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000767 }
768 }
769
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000770 rc = 0;
771
772out:
773 if (fstab) {
774 fs_mgr_free_fstab(fstab);
775 }
776
777 return rc;
778}
779
Sami Tolvanenacbf9be2015-03-19 10:00:34 +0000780int fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback)
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000781{
Elliott Hughes246c18c2015-10-09 11:52:00 -0700782 alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000783 char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
784 char *mount_point;
785 char propbuf[PROPERTY_VALUE_MAX];
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000786 char *status;
787 int fd = -1;
788 int i;
Sami Tolvanen45474232015-03-30 11:38:38 +0100789 int mode;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000790 int rc = -1;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000791 struct dm_ioctl *io = (struct dm_ioctl *) buffer;
792 struct fstab *fstab = NULL;
793
Sami Tolvanen90f52df2015-12-02 14:23:09 +0000794 if (!callback) {
795 return -1;
Sami Tolvanenac5c1222015-06-03 12:33:07 +0100796 }
797
Sami Tolvanen25b230c2015-10-30 13:11:00 +0000798 if (fs_mgr_load_verity_state(&mode) == -1) {
799 return -1;
800 }
801
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000802 fd = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
803
804 if (fd == -1) {
805 ERROR("Error opening device mapper (%s)\n", strerror(errno));
806 goto out;
807 }
808
809 property_get("ro.hardware", propbuf, "");
810 snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf);
811
812 fstab = fs_mgr_read_fstab(fstab_filename);
813
814 if (!fstab) {
815 ERROR("Failed to read %s\n", fstab_filename);
816 goto out;
817 }
818
819 for (i = 0; i < fstab->num_entries; i++) {
820 if (!fs_mgr_is_verified(&fstab->recs[i])) {
821 continue;
822 }
823
824 mount_point = basename(fstab->recs[i].mount_point);
825 verity_ioctl_init(io, mount_point, 0);
826
827 if (ioctl(fd, DM_TABLE_STATUS, io)) {
828 ERROR("Failed to query DM_TABLE_STATUS for %s (%s)\n", mount_point,
829 strerror(errno));
Sami Tolvanen45474232015-03-30 11:38:38 +0100830 continue;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000831 }
832
833 status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
834
Sami Tolvanen90f52df2015-12-02 14:23:09 +0000835 callback(&fstab->recs[i], mount_point, mode, *status);
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000836 }
837
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000838 rc = 0;
839
840out:
841 if (fstab) {
842 fs_mgr_free_fstab(fstab);
843 }
844
845 if (fd) {
Elliott Hughes47b01342015-05-15 19:16:40 -0700846 close(fd);
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000847 }
848
849 return rc;
850}
851
Jeremy Compostella32cabf22016-04-26 13:51:27 +0200852static void update_verity_table_blk_device(char *blk_device, char **table)
853{
854 std::string result, word;
855 auto tokens = android::base::Split(*table, " ");
856
857 for (const auto token : tokens) {
858 if (android::base::StartsWith(token, "/dev/block/") &&
859 android::base::StartsWith(blk_device, token.c_str())) {
860 word = blk_device;
861 } else {
862 word = token;
863 }
864
865 if (result.empty()) {
866 result = word;
867 } else {
868 result += " " + word;
869 }
870 }
871
872 if (result.empty()) {
873 return;
874 }
875
876 free(*table);
877 *table = strdup(result.c_str());
878}
879
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100880int fs_mgr_setup_verity(struct fstab_rec *fstab)
881{
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000882 int retval = FS_MGR_SETUP_VERITY_FAIL;
Paul Lawrenceec900bb2014-10-09 14:22:49 +0000883 int fd = -1;
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100884 char *verity_blk_name = NULL;
885 struct fec_handle *f = NULL;
886 struct fec_verity_metadata verity;
Jeremy Compostella32cabf22016-04-26 13:51:27 +0200887 struct verity_table_params params = { .table = NULL };
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800888
Elliott Hughes246c18c2015-10-09 11:52:00 -0700889 alignas(dm_ioctl) char buffer[DM_BUF_SIZE];
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800890 struct dm_ioctl *io = (struct dm_ioctl *) buffer;
891 char *mount_point = basename(fstab->mount_point);
892
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100893 if (fec_open(&f, fstab->blk_device, O_RDONLY, FEC_VERITY_DISABLE,
894 FEC_DEFAULT_ROOTS) < 0) {
895 ERROR("Failed to open '%s' (%s)\n", fstab->blk_device,
896 strerror(errno));
Geremy Condra05699b32014-03-17 14:46:51 -0700897 return retval;
898 }
899
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100900 // read verity metadata
901 if (fec_verity_get_metadata(f, &verity) < 0) {
902 ERROR("Failed to get verity metadata '%s' (%s)\n", fstab->blk_device,
903 strerror(errno));
Paul Lawrenceec900bb2014-10-09 14:22:49 +0000904 goto out;
905 }
906
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100907#ifdef ALLOW_ADBD_DISABLE_VERITY
908 if (verity.disabled) {
909 retval = FS_MGR_SETUP_VERITY_DISABLED;
910 INFO("Attempt to cleanly disable verity - only works in USERDEBUG\n");
911 goto out;
912 }
913#endif
914
915 // read ecc metadata
916 if (fec_ecc_get_metadata(f, &params.ecc) < 0) {
917 params.ecc.valid = false;
918 }
919
920 params.ecc_dev = fstab->blk_device;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000921
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800922 // get the device mapper fd
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800923 if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100924 ERROR("Error opening device mapper (%s)\n", strerror(errno));
Paul Lawrence88a12fb2014-10-09 09:37:00 -0700925 goto out;
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800926 }
927
928 // create the device
929 if (create_verity_device(io, mount_point, fd) < 0) {
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100930 ERROR("Couldn't create verity device!\n");
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800931 goto out;
932 }
933
934 // get the name of the device file
935 if (get_verity_device_name(io, mount_point, fd, &verity_blk_name) < 0) {
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100936 ERROR("Couldn't get verity device number!\n");
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800937 goto out;
938 }
939
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100940 if (load_verity_state(fstab, &params.mode) < 0) {
Sami Tolvanen946a0f32015-03-22 12:40:05 +0000941 /* if accessing or updating the state failed, switch to the default
942 * safe mode. This makes sure the device won't end up in an endless
943 * restart loop, and no corrupted data will be exposed to userspace
944 * without a warning. */
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100945 params.mode = VERITY_MODE_EIO;
Sami Tolvanen51bf11a2015-02-16 10:27:21 +0000946 }
947
Jeremy Compostella32cabf22016-04-26 13:51:27 +0200948 if (!verity.table) {
949 goto out;
950 }
951
952 params.table = strdup(verity.table);
953 if (!params.table) {
954 goto out;
955 }
956
Sami Tolvanen1ada1492015-09-21 15:12:29 +0100957 // verify the signature on the table
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100958 if (verify_table(verity.signature, verity.table,
959 verity.table_length) < 0) {
960 if (params.mode == VERITY_MODE_LOGGING) {
Sami Tolvanen1ada1492015-09-21 15:12:29 +0100961 // the user has been warned, allow mounting without dm-verity
962 retval = FS_MGR_SETUP_VERITY_SUCCESS;
963 goto out;
964 }
965
966 // invalidate root hash and salt to trigger device-specific recovery
Jeremy Compostella32cabf22016-04-26 13:51:27 +0200967 if (invalidate_table(params.table, verity.table_length) < 0) {
Sami Tolvanen1ada1492015-09-21 15:12:29 +0100968 goto out;
969 }
970 }
971
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100972 INFO("Enabling dm-verity for %s (mode %d)\n", mount_point, params.mode);
Sami Tolvanenacbf9be2015-03-19 10:00:34 +0000973
Jeremy Compostella32cabf22016-04-26 13:51:27 +0200974 if (fstab->fs_mgr_flags & MF_SLOTSELECT) {
975 // Update the verity params using the actual block device path
976 update_verity_table_blk_device(fstab->blk_device, &params.table);
977 }
978
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800979 // load the verity mapping table
Sami Tolvanen99e3a922015-05-22 15:43:50 +0100980 if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
Sami Tolvanenff980d22015-12-10 00:04:10 +0000981 format_verity_table) == 0) {
982 goto loaded;
Geremy Condra3ad3d1c2013-02-22 18:11:41 -0800983 }
984
Sami Tolvanenff980d22015-12-10 00:04:10 +0000985 if (params.ecc.valid) {
986 // kernel may not support error correction, try without
987 INFO("Disabling error correction for %s\n", mount_point);
988 params.ecc.valid = false;
989
990 if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
991 format_verity_table) == 0) {
992 goto loaded;
993 }
994 }
995
996 // try the legacy format for backwards compatibility
997 if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
998 format_legacy_verity_table) == 0) {
999 goto loaded;
1000 }
1001
1002 if (params.mode != VERITY_MODE_EIO) {
1003 // as a last resort, EIO mode should always be supported
1004 INFO("Falling back to EIO mode for %s\n", mount_point);
1005 params.mode = VERITY_MODE_EIO;
1006
1007 if (load_verity_table(io, mount_point, verity.data_size, fd, &params,
1008 format_legacy_verity_table) == 0) {
1009 goto loaded;
1010 }
1011 }
1012
1013 ERROR("Failed to load verity table for %s\n", mount_point);
1014 goto out;
1015
1016loaded:
1017
Geremy Condra3ad3d1c2013-02-22 18:11:41 -08001018 // activate the device
1019 if (resume_verity_table(io, mount_point, fd) < 0) {
1020 goto out;
1021 }
1022
Sami Tolvanen214f33b2014-12-18 16:15:30 +00001023 // mark the underlying block device as read-only
1024 fs_mgr_set_blk_ro(fstab->blk_device);
1025
Geremy Condra3ad3d1c2013-02-22 18:11:41 -08001026 // assign the new verity block device as the block device
1027 free(fstab->blk_device);
1028 fstab->blk_device = verity_blk_name;
Paul Lawrenceec900bb2014-10-09 14:22:49 +00001029 verity_blk_name = 0;
Geremy Condra3ad3d1c2013-02-22 18:11:41 -08001030
1031 // make sure we've set everything up properly
1032 if (test_access(fstab->blk_device) < 0) {
1033 goto out;
1034 }
1035
Sami Tolvanen86cddf42015-03-05 00:02:28 +00001036 retval = FS_MGR_SETUP_VERITY_SUCCESS;
Geremy Condra3ad3d1c2013-02-22 18:11:41 -08001037
1038out:
Paul Lawrenceec900bb2014-10-09 14:22:49 +00001039 if (fd != -1) {
1040 close(fd);
1041 }
1042
Sami Tolvanen99e3a922015-05-22 15:43:50 +01001043 fec_close(f);
Jeremy Compostella32cabf22016-04-26 13:51:27 +02001044 free(params.table);
Paul Lawrence88a12fb2014-10-09 09:37:00 -07001045 free(verity_blk_name);
Paul Lawrenceec900bb2014-10-09 14:22:49 +00001046
Geremy Condra3ad3d1c2013-02-22 18:11:41 -08001047 return retval;
1048}