fec_verity.cpp revision dadd5e33ac00df9a57114487f8441a59fd08bd89
1/*
2 * Copyright (C) 2015 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
17#include <ctype.h>
18#include <stdlib.h>
19#include <base/strings.h>
20#include "fec_private.h"
21
22/* converts a hex nibble into an int */
23static inline int hextobin(char c)
24{
25    if (c >= '0' && c <= '9') {
26        return c - '0';
27    } else if (c >= 'a' && c <= 'f') {
28        return c - 'a' + 10;
29    } else {
30        errno = EINVAL;
31        return -1;
32    }
33}
34
35/* converts a hex string `src' of `size' characters to binary and copies the
36   the result into `dst' */
37static int parse_hex(uint8_t *dst, uint32_t size, const char *src)
38{
39    int l, h;
40
41    check(dst);
42    check(src);
43    check(2 * size == strlen(src));
44
45    while (size) {
46        h = hextobin(tolower(*src++));
47        l = hextobin(tolower(*src++));
48
49        check(l >= 0);
50        check(h >= 0);
51
52        *dst++ = (h << 4) | l;
53        --size;
54    }
55
56    return 0;
57}
58
59/* parses a 64-bit unsigned integer from string `src' into `dst' and if
60   `maxval' is >0, checks that `dst' <= `maxval' */
61static int parse_uint64(const char *src, uint64_t maxval, uint64_t *dst)
62{
63    char *end;
64    unsigned long long int value;
65
66    check(src);
67    check(dst);
68
69    errno = 0;
70    value = strtoull(src, &end, 0);
71
72    if (*src == '\0' || *end != '\0' ||
73            (errno == ERANGE && value == ULLONG_MAX)) {
74        errno = EINVAL;
75        return -1;
76    }
77
78    if (maxval && value > maxval) {
79        errno = EINVAL;
80        return -1;
81    }
82
83   *dst = (uint64_t)value;
84    return 0;
85}
86
87/* computes the size of verity hash tree for `file_size' bytes and returns the
88   number of hash tree levels in `verity_levels,' and the number of hashes per
89   level in `level_hashes', if the parameters are non-NULL */
90uint64_t verity_get_size(uint64_t file_size, uint32_t *verity_levels,
91        uint32_t *level_hashes)
92{
93    /* we assume a known metadata size, 4 KiB block size, and SHA-256 to avoid
94       relying on disk content */
95
96    uint32_t level = 0;
97    uint64_t total = 0;
98    uint64_t hashes = file_size / FEC_BLOCKSIZE;
99
100    do {
101        if (level_hashes) {
102            level_hashes[level] = hashes;
103        }
104
105        hashes = fec_div_round_up(hashes * SHA256_DIGEST_LENGTH, FEC_BLOCKSIZE);
106        total += hashes;
107
108        ++level;
109    } while (hashes > 1);
110
111    if (verity_levels) {
112        *verity_levels = level;
113    }
114
115    return total * FEC_BLOCKSIZE;
116}
117
118/* computes a SHA-256 salted with `f->verity.salt' from a FEC_BLOCKSIZE byte
119   buffer `block', and copies the hash to `hash' */
120static inline int verity_hash(fec_handle *f, const uint8_t *block,
121        uint8_t *hash)
122{
123    SHA256_CTX ctx;
124    SHA256_Init(&ctx);
125
126    check(f);
127    check(f->verity.salt);
128    SHA256_Update(&ctx, f->verity.salt, f->verity.salt_size);
129
130    check(block);
131    SHA256_Update(&ctx, block, FEC_BLOCKSIZE);
132
133    check(hash);
134    SHA256_Final(hash, &ctx);
135    return 0;
136}
137
138/* computes a verity hash for FEC_BLOCKSIZE bytes from buffer `block' and
139   compares it to the expected value in `expected' */
140bool verity_check_block(fec_handle *f, const uint8_t *expected,
141        const uint8_t *block)
142{
143    check(f);
144    check(block);
145
146    uint8_t hash[SHA256_DIGEST_LENGTH];
147
148    if (unlikely(verity_hash(f, block, hash) == -1)) {
149        error("failed to hash");
150        return false;
151    }
152
153    check(expected);
154    return !memcmp(expected, hash, SHA256_DIGEST_LENGTH);
155}
156
157/* reads a verity hash and the corresponding data block using error correction,
158   if available */
159static bool ecc_read_hashes(fec_handle *f, uint64_t hash_offset,
160        uint8_t *hash, uint64_t data_offset, uint8_t *data)
161{
162    check(f);
163
164    if (hash && fec_pread(f, hash, SHA256_DIGEST_LENGTH, hash_offset) !=
165                    SHA256_DIGEST_LENGTH) {
166        error("failed to read hash tree: offset %" PRIu64 ": %s", hash_offset,
167            strerror(errno));
168        return false;
169    }
170
171    check(data);
172
173    if (fec_pread(f, data, FEC_BLOCKSIZE, data_offset) != FEC_BLOCKSIZE) {
174        error("failed to read hash tree: data_offset %" PRIu64 ": %s",
175            data_offset, strerror(errno));
176        return false;
177    }
178
179    return true;
180}
181
182/* reads the verity hash tree, validates it against the root hash in `root',
183   corrects errors if necessary, and copies valid data blocks for later use
184   to `f->verity.hash' */
185static int verify_tree(fec_handle *f, const uint8_t *root)
186{
187    uint8_t data[FEC_BLOCKSIZE];
188    uint8_t hash[SHA256_DIGEST_LENGTH];
189
190    check(f);
191    check(root);
192
193    verity_info *v = &f->verity;
194    uint32_t levels = 0;
195
196    /* calculate the size and the number of levels in the hash tree */
197    v->hash_size =
198        verity_get_size(v->data_blocks * FEC_BLOCKSIZE, &levels, NULL);
199
200    check(v->hash_start < UINT64_MAX - v->hash_size);
201    check(v->hash_start + v->hash_size <= f->data_size);
202
203    uint64_t hash_offset = v->hash_start;
204    uint64_t data_offset = hash_offset + FEC_BLOCKSIZE;
205
206    v->hash_data_offset = data_offset;
207
208    /* validate the root hash */
209    if (!raw_pread(f, data, FEC_BLOCKSIZE, hash_offset) ||
210            !verity_check_block(f, root, data)) {
211        /* try to correct */
212        if (!ecc_read_hashes(f, 0, NULL, hash_offset, data) ||
213                !verity_check_block(f, root, data)) {
214            error("root hash invalid");
215            return -1;
216        } else if (f->mode & O_RDWR &&
217                    !raw_pwrite(f, data, FEC_BLOCKSIZE, hash_offset)) {
218            error("failed to rewrite the root block: %s", strerror(errno));
219            return -1;
220        }
221    }
222
223    debug("root hash valid");
224
225    /* calculate the number of hashes on each level */
226    uint32_t hashes[levels];
227
228    verity_get_size(v->data_blocks * FEC_BLOCKSIZE, NULL, hashes);
229
230    /* calculate the size and offset for the data hashes */
231    for (uint32_t i = 1; i < levels; ++i) {
232        uint32_t blocks = hashes[levels - i];
233        debug("%u hash blocks on level %u", blocks, levels - i);
234
235        v->hash_data_offset = data_offset;
236        v->hash_data_blocks = blocks;
237
238        data_offset += blocks * FEC_BLOCKSIZE;
239    }
240
241    check(v->hash_data_blocks);
242    check(v->hash_data_blocks <= v->hash_size / FEC_BLOCKSIZE);
243
244    check(v->hash_data_offset);
245    check(v->hash_data_offset <=
246        UINT64_MAX - (v->hash_data_blocks * FEC_BLOCKSIZE));
247    check(v->hash_data_offset < f->data_size);
248    check(v->hash_data_offset + v->hash_data_blocks * FEC_BLOCKSIZE <=
249        f->data_size);
250
251    /* copy data hashes to memory in case they are corrupted, so we don't
252       have to correct them every time they are needed */
253    std::unique_ptr<uint8_t[]> data_hashes(
254       new (std::nothrow) uint8_t[f->verity.hash_data_blocks * FEC_BLOCKSIZE]);
255
256    if (!data_hashes) {
257        errno = ENOMEM;
258        return -1;
259    }
260
261    /* validate the rest of the hash tree */
262    data_offset = hash_offset + FEC_BLOCKSIZE;
263
264    for (uint32_t i = 1; i < levels; ++i) {
265        uint32_t blocks = hashes[levels - i];
266
267        for (uint32_t j = 0; j < blocks; ++j) {
268            /* ecc reads are very I/O intensive, so read raw hash tree and do
269               error correcting only if it doesn't validate */
270            if (!raw_pread(f, hash, SHA256_DIGEST_LENGTH,
271                    hash_offset + j * SHA256_DIGEST_LENGTH) ||
272                !raw_pread(f, data, FEC_BLOCKSIZE,
273                    data_offset + j * FEC_BLOCKSIZE)) {
274                error("failed to read hashes: %s", strerror(errno));
275                return -1;
276            }
277
278            if (!verity_check_block(f, hash, data)) {
279                /* try to correct */
280                if (!ecc_read_hashes(f,
281                        hash_offset + j * SHA256_DIGEST_LENGTH, hash,
282                        data_offset + j * FEC_BLOCKSIZE, data) ||
283                    !verity_check_block(f, hash, data)) {
284                    error("invalid hash tree: hash_offset %" PRIu64 ", "
285                        "data_offset %" PRIu64 ", block %u",
286                        hash_offset, data_offset, j);
287                    return -1;
288                }
289
290                /* update the corrected blocks to the file if we are in r/w
291                   mode */
292                if (f->mode & O_RDWR) {
293                    if (!raw_pwrite(f, hash, SHA256_DIGEST_LENGTH,
294                            hash_offset + j * SHA256_DIGEST_LENGTH) ||
295                        !raw_pwrite(f, data, FEC_BLOCKSIZE,
296                            data_offset + j * FEC_BLOCKSIZE)) {
297                        error("failed to write hashes: %s", strerror(errno));
298                        return -1;
299                    }
300                }
301            }
302
303            if (blocks == v->hash_data_blocks) {
304                memcpy(data_hashes.get() + j * FEC_BLOCKSIZE, data,
305                    FEC_BLOCKSIZE);
306            }
307        }
308
309        hash_offset = data_offset;
310        data_offset += blocks * FEC_BLOCKSIZE;
311    }
312
313    debug("valid");
314
315    v->hash = data_hashes.release();
316    return 0;
317}
318
319/* reads, corrects and parses the verity table, validates parameters, and if
320   `f->flags' does not have `FEC_VERITY_DISABLE' set, calls `verify_tree' to
321   load and validate the hash tree */
322static int parse_table(fec_handle *f, uint64_t offset, uint32_t size)
323{
324    check(f);
325    check(size >= VERITY_MIN_TABLE_SIZE);
326    check(size <= VERITY_MAX_TABLE_SIZE);
327
328    debug("offset = %" PRIu64 ", size = %u", offset, size);
329
330    verity_info *v = &f->verity;
331    std::unique_ptr<char[]> table(new (std::nothrow) char[size + 1]);
332
333    if (!table) {
334        errno = ENOMEM;
335        return -1;
336    }
337
338    if (fec_pread(f, table.get(), size, offset) != (ssize_t)size) {
339        error("failed to read verity table: %s", strerror(errno));
340        return -1;
341    }
342
343    table[size] = '\0';
344    debug("verity table: '%s'", table.get());
345
346    int i = 0;
347    std::unique_ptr<uint8_t[]> salt;
348    uint8_t root[SHA256_DIGEST_LENGTH];
349
350    auto tokens = android::base::Split(table.get(), " ");
351
352    for (const auto token : tokens) {
353        switch (i++) {
354        case 0: /* version */
355            if (token != stringify(VERITY_TABLE_VERSION)) {
356                error("unsupported verity table version: %s", token.c_str());
357                return -1;
358            }
359            break;
360        case 3: /* data_block_size */
361        case 4: /* hash_block_size */
362            /* assume 4 KiB block sizes for everything */
363            if (token != stringify(FEC_BLOCKSIZE)) {
364                error("unsupported verity block size: %s", token.c_str());
365                return -1;
366            }
367            break;
368        case 5: /* num_data_blocks */
369            if (parse_uint64(token.c_str(), f->data_size / FEC_BLOCKSIZE,
370                    &v->data_blocks) == -1) {
371                error("invalid number of verity data blocks: %s",
372                    token.c_str());
373                return -1;
374            }
375            break;
376        case 6: /* hash_start_block */
377            if (parse_uint64(token.c_str(), f->data_size / FEC_BLOCKSIZE,
378                    &v->hash_start) == -1) {
379                error("invalid verity hash start block: %s", token.c_str());
380                return -1;
381            }
382
383            v->hash_start *= FEC_BLOCKSIZE;
384            break;
385        case 7: /* algorithm */
386            if (token != "sha256") {
387                error("unsupported verity hash algorithm: %s", token.c_str());
388                return -1;
389            }
390            break;
391        case 8: /* digest */
392            if (parse_hex(root, sizeof(root), token.c_str()) == -1) {
393                error("invalid verity root hash: %s", token.c_str());
394                return -1;
395            }
396            break;
397        case 9: /* salt */
398            v->salt_size = token.size();
399            check(v->salt_size % 2 == 0);
400            v->salt_size /= 2;
401
402            salt.reset(new (std::nothrow) uint8_t[v->salt_size]);
403
404            if (!salt) {
405                errno = ENOMEM;
406                return -1;
407            }
408
409            if (parse_hex(salt.get(), v->salt_size, token.c_str()) == -1) {
410                error("invalid verity salt: %s", token.c_str());
411                return -1;
412            }
413            break;
414        default:
415            break;
416        }
417    }
418
419    if (i < VERITY_TABLE_ARGS) {
420        error("not enough arguments in verity table: %d; expected at least "
421            stringify(VERITY_TABLE_ARGS), i);
422        return -1;
423    }
424
425    check(v->hash_start < f->data_size);
426
427    if (v->metadata_start < v->hash_start) {
428        check(v->data_blocks == v->metadata_start / FEC_BLOCKSIZE);
429    } else {
430        check(v->data_blocks == v->hash_start / FEC_BLOCKSIZE);
431    }
432
433    v->salt = salt.release();
434    v->table = table.release();
435
436    if (!(f->flags & FEC_VERITY_DISABLE)) {
437        if (verify_tree(f, root) == -1) {
438            return -1;
439        }
440
441        check(v->hash);
442
443        uint8_t zero_block[FEC_BLOCKSIZE];
444        memset(zero_block, 0, FEC_BLOCKSIZE);
445
446        if (verity_hash(f, zero_block, v->zero_hash) == -1) {
447            error("failed to hash");
448            return -1;
449        }
450    }
451
452    return 0;
453}
454
455/* rewrites verity metadata block using error corrected data in `f->verity' */
456static int rewrite_metadata(fec_handle *f, uint64_t offset)
457{
458    check(f);
459    check(f->data_size > VERITY_METADATA_SIZE);
460    check(offset <= f->data_size - VERITY_METADATA_SIZE);
461
462    std::unique_ptr<uint8_t[]> metadata(
463        new (std::nothrow) uint8_t[VERITY_METADATA_SIZE]);
464
465    if (!metadata) {
466        errno = ENOMEM;
467        return -1;
468    }
469
470    memset(metadata.get(), 0, VERITY_METADATA_SIZE);
471
472    verity_info *v = &f->verity;
473    memcpy(metadata.get(), &v->header, sizeof(v->header));
474
475    check(v->table);
476    size_t len = strlen(v->table);
477
478    check(sizeof(v->header) + len <= VERITY_METADATA_SIZE);
479    memcpy(metadata.get() + sizeof(v->header), v->table, len);
480
481    return raw_pwrite(f, metadata.get(), VERITY_METADATA_SIZE, offset);
482}
483
484/* attempts to read verity metadata from `f->fd' position `offset'; if in r/w
485   mode, rewrites the metadata if it had errors */
486int verity_parse_header(fec_handle *f, uint64_t offset)
487{
488    check(f);
489    check(f->data_size > VERITY_METADATA_SIZE);
490
491    if (offset > f->data_size - VERITY_METADATA_SIZE) {
492        debug("failed to read verity header: offset %" PRIu64 " is too far",
493            offset);
494        return -1;
495    }
496
497    verity_info *v = &f->verity;
498    uint64_t errors = f->errors;
499
500    if (fec_pread(f, &v->header, sizeof(v->header), offset) !=
501            sizeof(v->header)) {
502        error("failed to read verity header: %s", strerror(errno));
503        return -1;
504    }
505
506    verity_header raw_header;
507
508    if (!raw_pread(f, &raw_header, sizeof(raw_header), offset)) {
509        error("failed to read verity header: %s", strerror(errno));
510        return -1;
511    }
512    /* use raw data to check for the alternative magic, because it will
513       be error corrected to VERITY_MAGIC otherwise */
514    if (raw_header.magic == VERITY_MAGIC_DISABLE) {
515        /* this value is not used by us, but can be used by a caller to
516           decide whether dm-verity should be enabled */
517        v->disabled = true;
518    } else if (v->header.magic != VERITY_MAGIC) {
519        return -1;
520    }
521
522    if (v->header.version != VERITY_VERSION) {
523        error("unsupported verity version %u", v->header.version);
524        return -1;
525    }
526
527    if (v->header.length < VERITY_MIN_TABLE_SIZE ||
528        v->header.length > VERITY_MAX_TABLE_SIZE) {
529        error("invalid verity table size: %u; expected ["
530            stringify(VERITY_MIN_TABLE_SIZE) ", "
531            stringify(VERITY_MAX_TABLE_SIZE) ")", v->header.length);
532        return -1;
533    }
534
535    v->metadata_start = offset;
536
537    /* signature is skipped, because for our purposes it won't matter from
538       where the data originates; the caller of the library is responsible
539       for signature verification */
540
541    if (offset > UINT64_MAX - v->header.length) {
542        error("invalid verity table length: %u", v->header.length);
543        return -1;
544    } else if (offset + v->header.length >= f->data_size) {
545        error("invalid verity table length: %u", v->header.length);
546        return -1;
547    }
548
549    if (parse_table(f, offset + sizeof(v->header), v->header.length) == -1) {
550        return -1;
551    }
552
553    /* if we corrected something while parsing metadata and we are in r/w
554       mode, rewrite the corrected metadata */
555    if (f->mode & O_RDWR && f->errors > errors &&
556            rewrite_metadata(f, offset) < 0) {
557        warn("failed to rewrite verity metadata: %s", strerror(errno));
558    }
559
560    if (v->metadata_start < v->hash_start) {
561        f->data_size = v->metadata_start;
562    } else {
563        f->data_size = v->hash_start;
564    }
565
566    return 0;
567}
568
569int fec_verity_set_status(struct fec_handle *f, bool enabled)
570{
571    check(f);
572
573    if (!(f->mode & O_RDWR)) {
574        error("cannot update verity magic: read-only handle");
575        errno = EBADF;
576        return -1;
577    }
578
579    verity_info *v = &f->verity;
580
581    if (!v->metadata_start) {
582        error("cannot update verity magic: no metadata found");
583        errno = EINVAL;
584        return -1;
585    }
586
587    if (v->disabled == !enabled) {
588        return 0; /* nothing to do */
589    }
590
591    uint32_t magic = enabled ? VERITY_MAGIC : VERITY_MAGIC_DISABLE;
592
593    if (!raw_pwrite(f, &magic, sizeof(magic), v->metadata_start)) {
594        error("failed to update verity magic to %08x: %s", magic,
595            strerror(errno));
596        return -1;
597    }
598
599    warn("updated verity magic to %08x (%s)", magic,
600        enabled ? "enabled" : "disabled");
601    v->disabled = !enabled;
602
603    return 0;
604}
605