1 // Copyright 2018 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 <lib/fzl/owned-vmo-mapper.h>
6 #include <lib/inspect/block.h>
7 #include <lib/inspect/snapshot.h>
8 #include <unittest/unittest.h>
9 
10 namespace {
11 
12 using inspect::BlockType;
13 using inspect::Snapshot;
14 using inspect::internal::Block;
15 using inspect::internal::HeaderBlockFields;
16 
ValidRead()17 bool ValidRead() {
18     BEGIN_TEST;
19 
20     fzl::OwnedVmoMapper vmo;
21     ASSERT_EQ(ZX_OK, vmo.CreateAndMap(4096, "test"));
22     memset(vmo.start(), 'a', 4096);
23     Block* header = reinterpret_cast<Block*>(vmo.start());
24     header->header = HeaderBlockFields::Order::Make(0) |
25                      HeaderBlockFields::Type::Make(BlockType::kHeader) |
26                      HeaderBlockFields::Version::Make(0);
27     memcpy(&header->header_data[4], inspect::kMagicNumber, 4);
28     header->payload.u64 = 0;
29 
30     zx::vmo dup;
31     ASSERT_EQ(ZX_OK, vmo.vmo().duplicate(ZX_RIGHT_SAME_RIGHTS, &dup));
32     Snapshot snapshot;
33     zx_status_t status = Snapshot::Create(std::move(dup), &snapshot);
34 
35     EXPECT_EQ(ZX_OK, status);
36     EXPECT_EQ(4096, snapshot.size());
37 
38     // Make sure that the data was actually fully copied to the snapshot.
39     uint8_t buf[snapshot.size() - sizeof(Block)];
40     memset(buf, 'a', snapshot.size() - sizeof(Block));
41     EXPECT_EQ(0, memcmp(snapshot.data() + sizeof(Block), buf, snapshot.size() - sizeof(Block)));
42 
43     END_TEST;
44 }
45 
InvalidWritePending()46 bool InvalidWritePending() {
47     BEGIN_TEST;
48 
49     fzl::OwnedVmoMapper vmo;
50     ASSERT_EQ(ZX_OK, vmo.CreateAndMap(4096, "test"));
51     Block* header = reinterpret_cast<Block*>(vmo.start());
52     header->header = HeaderBlockFields::Order::Make(0) |
53                      HeaderBlockFields::Type::Make(BlockType::kHeader) |
54                      HeaderBlockFields::Version::Make(0);
55     memcpy(&header->header_data[4], inspect::kMagicNumber, 4);
56     header->payload.u64 = 1;
57 
58     zx::vmo dup;
59     ASSERT_EQ(ZX_OK, vmo.vmo().duplicate(ZX_RIGHT_SAME_RIGHTS, &dup));
60     Snapshot snapshot;
61     zx_status_t status = Snapshot::Create(std::move(dup), &snapshot);
62 
63     EXPECT_EQ(ZX_ERR_INTERNAL, status);
64     EXPECT_FALSE(snapshot);
65 
66     END_TEST;
67 }
68 
ValidPendingSkipCheck()69 bool ValidPendingSkipCheck() {
70     BEGIN_TEST;
71 
72     fzl::OwnedVmoMapper vmo;
73     ASSERT_EQ(ZX_OK, vmo.CreateAndMap(4096, "test"));
74     Block* header = reinterpret_cast<Block*>(vmo.start());
75     header->header = HeaderBlockFields::Order::Make(0) |
76                      HeaderBlockFields::Type::Make(BlockType::kHeader) |
77                      HeaderBlockFields::Version::Make(0);
78     memcpy(&header->header_data[4], inspect::kMagicNumber, 4);
79     header->payload.u64 = 1;
80 
81     zx::vmo dup;
82     ASSERT_EQ(ZX_OK, vmo.vmo().duplicate(ZX_RIGHT_SAME_RIGHTS, &dup));
83     Snapshot snapshot;
84     zx_status_t status = Snapshot::Create(
85         std::move(dup), {.read_attempts = 100, .skip_consistency_check = true}, &snapshot);
86     EXPECT_EQ(ZX_OK, status);
87     EXPECT_EQ(4096, snapshot.size());
88 
89     END_TEST;
90 }
91 
InvalidGenerationChange()92 bool InvalidGenerationChange() {
93     BEGIN_TEST;
94 
95     fzl::OwnedVmoMapper vmo;
96     ASSERT_EQ(ZX_OK, vmo.CreateAndMap(4096, "test"));
97     Block* header = reinterpret_cast<Block*>(vmo.start());
98     header->header = HeaderBlockFields::Order::Make(0) |
99                      HeaderBlockFields::Type::Make(BlockType::kHeader) |
100                      HeaderBlockFields::Version::Make(0);
101     memcpy(&header->header_data[4], inspect::kMagicNumber, 4);
102     header->payload.u64 = 0;
103 
104     zx::vmo dup;
105     ASSERT_EQ(ZX_OK, vmo.vmo().duplicate(ZX_RIGHT_SAME_RIGHTS, &dup));
106     Snapshot snapshot;
107     zx_status_t status = Snapshot::Create(
108         std::move(dup), Snapshot::kDefaultOptions,
109         [header] (uint8_t* buffer, size_t buffer_size) { header->payload.u64 += 2; }, &snapshot);
110 
111     EXPECT_EQ(ZX_ERR_INTERNAL, status);
112 
113     END_TEST;
114 }
115 
ValidGenerationChangeSkipCheck()116 bool ValidGenerationChangeSkipCheck() {
117     BEGIN_TEST;
118 
119     fzl::OwnedVmoMapper vmo;
120     ASSERT_EQ(ZX_OK, vmo.CreateAndMap(4096, "test"));
121     Block* header = reinterpret_cast<Block*>(vmo.start());
122     header->header = HeaderBlockFields::Order::Make(0) |
123                      HeaderBlockFields::Type::Make(BlockType::kHeader) |
124                      HeaderBlockFields::Version::Make(0);
125     memcpy(&header->header_data[4], inspect::kMagicNumber, 4);
126     header->payload.u64 = 0;
127 
128     zx::vmo dup;
129     ASSERT_EQ(ZX_OK, vmo.vmo().duplicate(ZX_RIGHT_SAME_RIGHTS, &dup));
130     Snapshot snapshot;
131     zx_status_t status = Snapshot::Create(
132         std::move(dup), {.read_attempts = 100, .skip_consistency_check = true},
133         [header] (uint8_t* buffer, size_t buffer_size) { header->payload.u64 += 2; }, &snapshot);
134 
135     EXPECT_EQ(ZX_OK, status);
136     EXPECT_EQ(4096, snapshot.size());
137 
138     END_TEST;
139 }
140 
InvalidBadMagicNumber()141 bool InvalidBadMagicNumber() {
142     BEGIN_TEST;
143 
144     fzl::OwnedVmoMapper vmo;
145     ASSERT_EQ(ZX_OK, vmo.CreateAndMap(4096, "test"));
146     Block* header = reinterpret_cast<Block*>(vmo.start());
147     header->header = HeaderBlockFields::Order::Make(0) |
148                      HeaderBlockFields::Type::Make(BlockType::kHeader) |
149                      HeaderBlockFields::Version::Make(0);
150     header->payload.u64 = 0;
151 
152     zx::vmo dup;
153     ASSERT_EQ(ZX_OK, vmo.vmo().duplicate(ZX_RIGHT_SAME_RIGHTS, &dup));
154     Snapshot snapshot;
155     zx_status_t status = Snapshot::Create(std::move(dup), &snapshot);
156 
157     EXPECT_EQ(ZX_ERR_INTERNAL, status);
158 
159     END_TEST;
160 }
161 
InvalidBadMagicNumberSkipCheck()162 bool InvalidBadMagicNumberSkipCheck() {
163     BEGIN_TEST;
164 
165     fzl::OwnedVmoMapper vmo;
166     ASSERT_EQ(ZX_OK, vmo.CreateAndMap(4096, "test"));
167     Block* header = reinterpret_cast<Block*>(vmo.start());
168     header->header = HeaderBlockFields::Order::Make(0) |
169                      HeaderBlockFields::Type::Make(BlockType::kHeader) |
170                      HeaderBlockFields::Version::Make(0);
171     header->payload.u64 = 0;
172 
173     zx::vmo dup;
174     ASSERT_EQ(ZX_OK, vmo.vmo().duplicate(ZX_RIGHT_SAME_RIGHTS, &dup));
175     Snapshot snapshot;
176     zx_status_t status = Snapshot::Create(
177         std::move(dup), {.read_attempts = 100, .skip_consistency_check = true}, &snapshot);
178 
179     EXPECT_EQ(ZX_ERR_INTERNAL, status);
180 
181     END_TEST;
182 }
183 
184 } // namespace
185 
186 BEGIN_TEST_CASE(SnapshotTests)
187 RUN_TEST(ValidRead)
188 RUN_TEST(InvalidWritePending)
189 RUN_TEST(ValidPendingSkipCheck)
190 RUN_TEST(InvalidGenerationChange)
191 RUN_TEST(ValidGenerationChangeSkipCheck)
192 RUN_TEST(InvalidBadMagicNumber)
193 RUN_TEST(InvalidBadMagicNumberSkipCheck)
194 END_TEST_CASE(SnapshotTests)
195