1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <fcntl.h>
6 #include <stdbool.h>
7 #include <stddef.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/stat.h>
12 #include <unistd.h>
13 
14 #ifdef __Fuchsia__
15 #include <zircon/syscalls.h>
16 #include <lib/zx/vmo.h>
17 #endif
18 
19 #include <fbl/unique_fd.h>
20 #include <fbl/unique_ptr.h>
21 #include <zircon/types.h>
22 
23 #include "fvm/fvm.h"
24 
25 #define ZXDEBUG 0
26 
27 namespace {
28 
29 // Return true if g1 is greater than or equal to g2.
30 // Safe against integer overflow.
generation_ge(uint64_t g1,uint64_t g2)31 bool generation_ge(uint64_t g1, uint64_t g2) {
32     if (g1 == UINT64_MAX && g2 == 0) {
33         return false;
34     } else if (g1 == 0 && g2 == UINT64_MAX) {
35         return true;
36     }
37     return g1 >= g2;
38 }
39 
40 // Validate the metadata's hash value.
41 // Returns 'true' if it matches, 'false' otherwise.
fvm_check_hash(const void * metadata,size_t metadata_size)42 bool fvm_check_hash(const void* metadata, size_t metadata_size) {
43     ZX_DEBUG_ASSERT(metadata_size >= sizeof(fvm::fvm_t));
44     const fvm::fvm_t* header = static_cast<const fvm::fvm_t*>(metadata);
45     const void* metadata_after_hash =
46         reinterpret_cast<const void*>(header->hash + sizeof(header->hash));
47     uint8_t empty_hash[sizeof(header->hash)];
48     memset(empty_hash, 0, sizeof(empty_hash));
49 
50     digest::Digest digest;
51     digest.Init();
52     digest.Update(metadata, offsetof(fvm::fvm_t, hash));
53     digest.Update(empty_hash, sizeof(empty_hash));
54     digest.Update(metadata_after_hash,
55                   metadata_size - (offsetof(fvm::fvm_t, hash) + sizeof(header->hash)));
56     digest.Final();
57     return digest == header->hash;
58 }
59 
60 } // namespace anonymous
61 
62 #ifdef __cplusplus
63 
Vpart() const64 uint64_t fvm::slice_entry::Vpart() const {
65     uint64_t result = data & VPART_MASK;
66     ZX_DEBUG_ASSERT(result < VPART_MAX);
67     return result;
68 }
69 
SetVpart(uint64_t vpart)70 void fvm::slice_entry::SetVpart(uint64_t vpart) {
71     ZX_DEBUG_ASSERT(vpart < VPART_MAX);
72     data = (data & ~VPART_MASK) | (vpart & VPART_MASK);
73 }
74 
Vslice() const75 uint64_t fvm::slice_entry::Vslice() const {
76     uint64_t result = (data & VSLICE_MASK) >> VPART_BITS;
77     ZX_DEBUG_ASSERT(result < VSLICE_MAX);
78     return result;
79 }
80 
SetVslice(uint64_t vslice)81 void fvm::slice_entry::SetVslice(uint64_t vslice) {
82     ZX_DEBUG_ASSERT(vslice < VSLICE_MAX);
83     data = (data & ~VSLICE_MASK) | ((vslice & VSLICE_MAX) << VPART_BITS);
84 }
85 
86 #endif // __cplusplus
87 
fvm_update_hash(void * metadata,size_t metadata_size)88 void fvm_update_hash(void* metadata, size_t metadata_size) {
89     fvm::fvm_t* header = static_cast<fvm::fvm_t*>(metadata);
90     memset(header->hash, 0, sizeof(header->hash));
91     digest::Digest digest;
92     const uint8_t* hash = digest.Hash(metadata, metadata_size);
93     memcpy(header->hash, hash, sizeof(header->hash));
94 }
95 
fvm_validate_header(const void * metadata,const void * backup,size_t metadata_size,const void ** out)96 zx_status_t fvm_validate_header(const void* metadata, const void* backup,
97                                 size_t metadata_size, const void** out) {
98     const fvm::fvm_t* primary_header = static_cast<const fvm::fvm_t*>(metadata);
99     const fvm::fvm_t* backup_header = static_cast<const fvm::fvm_t*>(backup);
100 
101     bool primary_valid = fvm_check_hash(metadata, metadata_size);
102     bool backup_valid = fvm_check_hash(backup, metadata_size);
103 
104     // Decide if we should use the primary or the backup copy of metadata
105     // for reading.
106     bool use_primary;
107     if (!primary_valid && !backup_valid) {
108         return ZX_ERR_BAD_STATE;
109     } else if (primary_valid && !backup_valid) {
110         use_primary = true;
111     } else if (!primary_valid && backup_valid) {
112         use_primary = false;
113     } else {
114         use_primary = generation_ge(primary_header->generation, backup_header->generation);
115     }
116 
117     const fvm::fvm_t* header = use_primary ? primary_header : backup_header;
118     if (header->magic != FVM_MAGIC) {
119         fprintf(stderr, "fvm: Bad magic\n");
120         return ZX_ERR_BAD_STATE;
121     }
122     if (header->version > FVM_VERSION) {
123         fprintf(stderr, "fvm: Header Version does not match fvm driver\n");
124         return ZX_ERR_BAD_STATE;
125     }
126 
127     // TODO(smklein): Additional validation....
128 
129     if (out) {
130         *out = use_primary ? metadata : backup;
131     }
132     return ZX_OK;
133 }
134