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