1 /*
2 * Copyright (C) 2016 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 "nvram/core/nvram_manager.h"
18
19 extern "C" {
20 #include <inttypes.h>
21 #include <string.h>
22 } // extern "C"
23
24 #include <nvram/core/logger.h>
25
26 #include "crypto.h"
27
28 using namespace nvram::storage;
29
30 namespace nvram {
31
32 namespace {
33
34 // Maximum size of a single space's contents.
35 constexpr size_t kMaxSpaceSize = 1024;
36
37 // Maximum authorization blob size;
38 constexpr size_t kMaxAuthSize = 32;
39
40 // The bitmask of all supported control flags.
41 constexpr uint32_t kSupportedControlsMask =
42 (1 << NV_CONTROL_PERSISTENT_WRITE_LOCK) |
43 (1 << NV_CONTROL_BOOT_WRITE_LOCK) |
44 (1 << NV_CONTROL_BOOT_READ_LOCK) |
45 (1 << NV_CONTROL_WRITE_AUTHORIZATION) |
46 (1 << NV_CONTROL_READ_AUTHORIZATION) |
47 (1 << NV_CONTROL_WRITE_EXTEND);
48
49 // Convert the |space.controls| bitmask to vector representation.
GetControlsVector(const NvramSpace & space,Vector<nvram_control_t> * controls)50 nvram_result_t GetControlsVector(const NvramSpace& space,
51 Vector<nvram_control_t>* controls) {
52 for (size_t control = 0; control < sizeof(uint32_t) * 8; ++control) {
53 if (space.HasControl(control)) {
54 if (!controls->Resize(controls->size() + 1)) {
55 NVRAM_LOG_ERR("Allocation failure.");
56 return NV_RESULT_INTERNAL_ERROR;
57 }
58 (*controls)[controls->size() - 1] = static_cast<nvram_control_t>(control);
59 }
60 }
61 return NV_RESULT_SUCCESS;
62 }
63
64 // Constant time memory block comparison.
ConstantTimeEquals(const Blob & a,const Blob & b)65 bool ConstantTimeEquals(const Blob& a, const Blob& b) {
66 if (a.size() != b.size())
67 return false;
68
69 // The volatile qualifiers prevent the compiler from making assumptions that
70 // allow shortcuts:
71 // * The entire array data must be read from memory.
72 // * Marking |result| volatile ensures the subsequent loop iterations must
73 // still store to |result|, thus avoiding the loop to exit early.
74 // This achieves the desired constant-time behavior.
75 volatile const uint8_t* data_a = a.data();
76 volatile const uint8_t* data_b = b.data();
77 volatile uint8_t result = 0;
78 for (size_t i = 0; i < a.size(); ++i) {
79 result |= data_a[i] ^ data_b[i];
80 }
81
82 return result == 0;
83 }
84
85 // A standard minimum function.
86 template <typename Type>
min(const Type & a,const Type & b)87 const Type& min(const Type& a, const Type& b) {
88 return (a < b) ? a : b;
89 }
90
91 // Filter status codes from the storage layer to only include known values.
92 // Anything outside the range will be mapped to the generic |kStorageError|.
SanitizeStorageStatus(storage::Status status)93 storage::Status SanitizeStorageStatus(storage::Status status) {
94 switch (status) {
95 case storage::Status::kSuccess:
96 return storage::Status::kSuccess;
97 case storage::Status::kNotFound:
98 return storage::Status::kNotFound;
99 case storage::Status::kStorageError:
100 return storage::Status::kStorageError;
101 }
102 NVRAM_LOG_ERR("Unknown status code %u!", status);
103 return storage::Status::kStorageError;
104 }
105
106 } // namespace
107
108 // Looks at |request| to determine the command to execute, then invokes
109 // the appropriate handler.
Dispatch(const nvram::Request & request,nvram::Response * response)110 void NvramManager::Dispatch(const nvram::Request& request,
111 nvram::Response* response) {
112 nvram_result_t result = NV_RESULT_INVALID_PARAMETER;
113 const nvram::RequestUnion& input = request.payload;
114 nvram::ResponseUnion* output = &response->payload;
115
116 switch (input.which()) {
117 case nvram::COMMAND_GET_INFO:
118 result = GetInfo(*input.get<COMMAND_GET_INFO>(),
119 &output->Activate<COMMAND_GET_INFO>());
120 break;
121 case nvram::COMMAND_CREATE_SPACE:
122 result = CreateSpace(*input.get<COMMAND_CREATE_SPACE>(),
123 &output->Activate<COMMAND_CREATE_SPACE>());
124 break;
125 case nvram::COMMAND_GET_SPACE_INFO:
126 result = GetSpaceInfo(*input.get<COMMAND_GET_SPACE_INFO>(),
127 &output->Activate<COMMAND_GET_SPACE_INFO>());
128 break;
129 case nvram::COMMAND_DELETE_SPACE:
130 result = DeleteSpace(*input.get<COMMAND_DELETE_SPACE>(),
131 &output->Activate<COMMAND_DELETE_SPACE>());
132 break;
133 case nvram::COMMAND_DISABLE_CREATE:
134 result = DisableCreate(*input.get<COMMAND_DISABLE_CREATE>(),
135 &output->Activate<COMMAND_DISABLE_CREATE>());
136 break;
137 case nvram::COMMAND_WRITE_SPACE:
138 result = WriteSpace(*input.get<COMMAND_WRITE_SPACE>(),
139 &output->Activate<COMMAND_WRITE_SPACE>());
140 break;
141 case nvram::COMMAND_READ_SPACE:
142 result = ReadSpace(*input.get<COMMAND_READ_SPACE>(),
143 &output->Activate<COMMAND_READ_SPACE>());
144 break;
145 case nvram::COMMAND_LOCK_SPACE_WRITE:
146 result = LockSpaceWrite(*input.get<COMMAND_LOCK_SPACE_WRITE>(),
147 &output->Activate<COMMAND_LOCK_SPACE_WRITE>());
148 break;
149 case nvram::COMMAND_LOCK_SPACE_READ:
150 result = LockSpaceRead(*input.get<COMMAND_LOCK_SPACE_READ>(),
151 &output->Activate<COMMAND_LOCK_SPACE_READ>());
152 break;
153 case nvram::COMMAND_WIPE_STORAGE:
154 result = WipeStorage(*input.get<COMMAND_WIPE_STORAGE>(),
155 &output->Activate<COMMAND_WIPE_STORAGE>());
156 break;
157 case nvram::COMMAND_DISABLE_WIPE:
158 result = DisableWipe(*input.get<COMMAND_DISABLE_WIPE>(),
159 &output->Activate<COMMAND_DISABLE_WIPE>());
160 break;
161 }
162
163 response->result = result;
164 }
165
GetInfo(const GetInfoRequest &,GetInfoResponse * response)166 nvram_result_t NvramManager::GetInfo(const GetInfoRequest& /* request */,
167 GetInfoResponse* response) {
168 NVRAM_LOG_INFO("GetInfo");
169
170 if (!Initialize())
171 return NV_RESULT_INTERNAL_ERROR;
172
173 // TODO: Get better values for total and available size from the storage
174 // layer.
175 response->total_size = kMaxSpaceSize * kMaxSpaces;
176 response->available_size = kMaxSpaceSize * (kMaxSpaces - num_spaces_);
177 response->max_space_size = kMaxSpaceSize;
178 response->max_spaces = kMaxSpaces;
179 Vector<uint32_t>& space_list = response->space_list;
180 if (!space_list.Resize(num_spaces_)) {
181 NVRAM_LOG_ERR("Allocation failure.");
182 return NV_RESULT_INTERNAL_ERROR;
183 }
184 for (size_t i = 0; i < num_spaces_; ++i) {
185 space_list[i] = spaces_[i].index;
186 }
187 response->wipe_disabled = disable_wipe_;
188
189 return NV_RESULT_SUCCESS;
190 }
191
CreateSpace(const CreateSpaceRequest & request,CreateSpaceResponse *)192 nvram_result_t NvramManager::CreateSpace(const CreateSpaceRequest& request,
193 CreateSpaceResponse* /* response */) {
194 const uint32_t index = request.index;
195 NVRAM_LOG_INFO("CreateSpace Ox%" PRIx32, index);
196
197 if (!Initialize())
198 return NV_RESULT_INTERNAL_ERROR;
199
200 if (disable_create_) {
201 NVRAM_LOG_INFO("Creation of further spaces is disabled.");
202 return NV_RESULT_OPERATION_DISABLED;
203 }
204
205 if (FindSpace(index) != kMaxSpaces) {
206 NVRAM_LOG_INFO("Space 0x%" PRIx32 " already exists.", index);
207 return NV_RESULT_SPACE_ALREADY_EXISTS;
208 }
209
210 if (num_spaces_ + 1 > kMaxSpaces) {
211 NVRAM_LOG_INFO("Too many spaces.");
212 return NV_RESULT_INVALID_PARAMETER;
213 }
214
215 if (request.size > kMaxSpaceSize) {
216 NVRAM_LOG_INFO("Create request exceeds max space size.");
217 return NV_RESULT_INVALID_PARAMETER;
218 }
219
220 if (request.authorization_value.size() > kMaxAuthSize) {
221 NVRAM_LOG_INFO("Authorization blob too large.");
222 return NV_RESULT_INVALID_PARAMETER;
223 }
224
225 uint32_t controls = 0;
226 for (uint32_t control : request.controls) {
227 controls |= (1 << control);
228 }
229 if ((controls & ~kSupportedControlsMask) != 0) {
230 NVRAM_LOG_INFO("Bad controls.");
231 return NV_RESULT_INVALID_PARAMETER;
232 }
233 if ((controls & (1 << NV_CONTROL_PERSISTENT_WRITE_LOCK)) != 0 &&
234 (controls & (1 << NV_CONTROL_BOOT_WRITE_LOCK)) != 0) {
235 NVRAM_LOG_INFO("Write lock controls are exclusive.");
236 return NV_RESULT_INVALID_PARAMETER;
237 }
238 if ((controls & (1 << NV_CONTROL_WRITE_EXTEND)) != 0 &&
239 request.size != crypto::kSHA256DigestSize) {
240 NVRAM_LOG_INFO("Write-extended space size must be %zu.",
241 crypto::kSHA256DigestSize);
242 return NV_RESULT_INVALID_PARAMETER;
243 }
244
245 // Mark the index as allocated.
246 spaces_[num_spaces_].index = index;
247 spaces_[num_spaces_].write_locked = false;
248 spaces_[num_spaces_].read_locked = false;
249 ++num_spaces_;
250
251 // Create a space record.
252 NvramSpace space;
253 space.flags = 0;
254 space.controls = controls;
255
256 // Copy the auth blob.
257 if (space.HasControl(NV_CONTROL_WRITE_AUTHORIZATION) ||
258 space.HasControl(NV_CONTROL_READ_AUTHORIZATION)) {
259 if (!space.authorization_value.Assign(request.authorization_value.data(),
260 request.authorization_value.size())) {
261 NVRAM_LOG_ERR("Allocation failure.");
262 return NV_RESULT_INTERNAL_ERROR;
263 }
264 }
265
266 // Initialize the space content.
267 if (!space.contents.Resize(request.size)) {
268 NVRAM_LOG_ERR("Allocation failure.");
269 return NV_RESULT_INTERNAL_ERROR;
270 }
271 memset(space.contents.data(), 0, request.size);
272
273 // Write the header before the space data. This ensures that all space
274 // definitions present in storage are also recorded in the header. Thus, the
275 // set of spaces present in the header is always a superset of the set of
276 // spaces that have state in storage. If there's a crash after writing the
277 // header but before writing the space information, the space data will be
278 // missing in storage. The initialization code handles this by checking the
279 // for the space data corresponding to the index marked as provisional in the
280 // header.
281 nvram_result_t result;
282 if ((result = WriteHeader(Optional<uint32_t>(index))) != NV_RESULT_SUCCESS ||
283 (result = WriteSpace(index, space)) != NV_RESULT_SUCCESS) {
284 --num_spaces_;
285 }
286 return result;
287 }
288
GetSpaceInfo(const GetSpaceInfoRequest & request,GetSpaceInfoResponse * response)289 nvram_result_t NvramManager::GetSpaceInfo(const GetSpaceInfoRequest& request,
290 GetSpaceInfoResponse* response) {
291 const uint32_t index = request.index;
292 NVRAM_LOG_INFO("GetSpaceInfo Ox%" PRIx32, index);
293
294 if (!Initialize())
295 return NV_RESULT_INTERNAL_ERROR;
296
297 SpaceRecord space_record;
298 nvram_result_t result;
299 if (!LoadSpaceRecord(index, &space_record, &result)) {
300 return result;
301 }
302
303 response->size = space_record.persistent.contents.size();
304
305 result = GetControlsVector(space_record.persistent, &response->controls);
306 if (result != NV_RESULT_SUCCESS) {
307 return NV_RESULT_INTERNAL_ERROR;
308 }
309
310 if (space_record.persistent.HasControl(NV_CONTROL_BOOT_READ_LOCK)) {
311 response->read_locked = space_record.transient->read_locked;
312 }
313
314 if (space_record.persistent.HasControl(NV_CONTROL_PERSISTENT_WRITE_LOCK)) {
315 response->write_locked =
316 space_record.persistent.HasFlag(NvramSpace::kFlagWriteLocked);
317 } else if (space_record.persistent.HasControl(NV_CONTROL_BOOT_WRITE_LOCK)) {
318 response->write_locked = space_record.transient->write_locked;
319 }
320
321 return NV_RESULT_SUCCESS;
322 }
323
DeleteSpace(const DeleteSpaceRequest & request,DeleteSpaceResponse *)324 nvram_result_t NvramManager::DeleteSpace(const DeleteSpaceRequest& request,
325 DeleteSpaceResponse* /* response */) {
326 const uint32_t index = request.index;
327 NVRAM_LOG_INFO("DeleteSpace Ox%" PRIx32, index);
328
329 if (!Initialize())
330 return NV_RESULT_INTERNAL_ERROR;
331
332 SpaceRecord space_record;
333 nvram_result_t result;
334 if (!LoadSpaceRecord(index, &space_record, &result)) {
335 return result;
336 }
337
338 result = space_record.CheckWriteAccess(request.authorization_value);
339 if (result != NV_RESULT_SUCCESS) {
340 return result;
341 }
342
343 // Delete the space. First mark the space as provisionally removed in the
344 // header. Then, delete the space data from storage. This allows orphaned
345 // space data be cleaned up after a crash.
346 SpaceListEntry tmp = spaces_[space_record.array_index];
347 spaces_[space_record.array_index] = spaces_[num_spaces_ - 1];
348 --num_spaces_;
349 result = WriteHeader(Optional<uint32_t>(index));
350 if (result == NV_RESULT_SUCCESS) {
351 switch (SanitizeStorageStatus(persistence::DeleteSpace(index))) {
352 case storage::Status::kStorageError:
353 NVRAM_LOG_ERR("Failed to delete space 0x%" PRIx32 " data.", index);
354 result = NV_RESULT_INTERNAL_ERROR;
355 break;
356 case storage::Status::kNotFound:
357 // The space was missing even if it shouldn't have been. Log an error,
358 // but return success as we're in the desired state.
359 NVRAM_LOG_ERR("Space 0x%" PRIx32 " data missing on deletion.", index);
360 return NV_RESULT_SUCCESS;
361 case storage::Status::kSuccess:
362 return NV_RESULT_SUCCESS;
363 }
364 }
365
366 // Failed to delete, re-add the transient state to |spaces_|.
367 spaces_[num_spaces_] = tmp;
368 ++num_spaces_;
369 return result;
370 }
371
DisableCreate(const DisableCreateRequest &,DisableCreateResponse *)372 nvram_result_t NvramManager::DisableCreate(
373 const DisableCreateRequest& /* request */,
374 DisableCreateResponse* /* response */) {
375 NVRAM_LOG_INFO("DisableCreate");
376
377 if (!Initialize())
378 return NV_RESULT_INTERNAL_ERROR;
379
380 // Set the |disable_create_| flag and call |WriteHeader| to persist the flag
381 // such that it remains effective after a reboot. Make sure to restore the
382 // current value of |disable_create_| if the write call fails, as we return an
383 // error in that case and client code would not expect state changes.
384 bool disable_create_previous = disable_create_;
385 disable_create_ = true;
386 nvram_result_t result = WriteHeader(Optional<uint32_t>());
387 if (result != NV_RESULT_SUCCESS) {
388 disable_create_ = disable_create_previous;
389 }
390 return result;
391 }
392
WriteSpace(const WriteSpaceRequest & request,WriteSpaceResponse *)393 nvram_result_t NvramManager::WriteSpace(const WriteSpaceRequest& request,
394 WriteSpaceResponse* /* response */) {
395 const uint32_t index = request.index;
396 NVRAM_LOG_INFO("WriteSpace Ox%" PRIx32, index);
397
398 if (!Initialize())
399 return NV_RESULT_INTERNAL_ERROR;
400
401 SpaceRecord space_record;
402 nvram_result_t result;
403 if (!LoadSpaceRecord(index, &space_record, &result)) {
404 return result;
405 }
406
407 result = space_record.CheckWriteAccess(request.authorization_value);
408 if (result != NV_RESULT_SUCCESS) {
409 return result;
410 }
411
412 Blob& contents = space_record.persistent.contents;
413 if (space_record.persistent.HasControl(NV_CONTROL_WRITE_EXTEND)) {
414 // Concatenate the current space |contents| with the input data.
415 Blob sha256_input;
416 if (!sha256_input.Resize(contents.size() + request.buffer.size())) {
417 return NV_RESULT_INTERNAL_ERROR;
418 }
419 memcpy(sha256_input.data(), contents.data(), contents.size());
420 memcpy(sha256_input.data() + contents.size(), request.buffer.data(),
421 request.buffer.size());
422
423 // Compute the SHA-256 digest and write it back to |contents|.
424 crypto::SHA256(sha256_input.data(), sha256_input.size(), contents.data(),
425 contents.size());
426 } else {
427 if (contents.size() < request.buffer.size()) {
428 return NV_RESULT_INVALID_PARAMETER;
429 }
430
431 memcpy(contents.data(), request.buffer.data(), request.buffer.size());
432 memset(contents.data() + request.buffer.size(), 0x0,
433 contents.size() - request.buffer.size());
434 }
435
436 return WriteSpace(index, space_record.persistent);
437 }
438
ReadSpace(const ReadSpaceRequest & request,ReadSpaceResponse * response)439 nvram_result_t NvramManager::ReadSpace(const ReadSpaceRequest& request,
440 ReadSpaceResponse* response) {
441 const uint32_t index = request.index;
442 NVRAM_LOG_INFO("ReadSpace Ox%" PRIx32, index);
443
444 if (!Initialize())
445 return NV_RESULT_INTERNAL_ERROR;
446
447 SpaceRecord space_record;
448 nvram_result_t result;
449 if (!LoadSpaceRecord(index, &space_record, &result)) {
450 return result;
451 }
452
453 result = space_record.CheckReadAccess(request.authorization_value);
454 if (result != NV_RESULT_SUCCESS) {
455 return result;
456 }
457
458 if (!response->buffer.Assign(space_record.persistent.contents.data(),
459 space_record.persistent.contents.size())) {
460 NVRAM_LOG_ERR("Allocation failure.");
461 return NV_RESULT_INTERNAL_ERROR;
462 }
463
464 return NV_RESULT_SUCCESS;
465 }
466
LockSpaceWrite(const LockSpaceWriteRequest & request,LockSpaceWriteResponse *)467 nvram_result_t NvramManager::LockSpaceWrite(
468 const LockSpaceWriteRequest& request,
469 LockSpaceWriteResponse* /* response */) {
470 const uint32_t index = request.index;
471 NVRAM_LOG_INFO("LockSpaceWrite Ox%" PRIx32, index);
472
473 if (!Initialize())
474 return NV_RESULT_INTERNAL_ERROR;
475
476 SpaceRecord space_record;
477 nvram_result_t result;
478 if (!LoadSpaceRecord(index, &space_record, &result)) {
479 return result;
480 }
481
482 result = space_record.CheckWriteAccess(request.authorization_value);
483 if (result != NV_RESULT_SUCCESS) {
484 return result;
485 }
486
487 if (space_record.persistent.HasControl(NV_CONTROL_PERSISTENT_WRITE_LOCK)) {
488 space_record.persistent.SetFlag(NvramSpace::kFlagWriteLocked);
489 return WriteSpace(index, space_record.persistent);
490 } else if (space_record.persistent.HasControl(NV_CONTROL_BOOT_WRITE_LOCK)) {
491 space_record.transient->write_locked = true;
492 return NV_RESULT_SUCCESS;
493 }
494
495 NVRAM_LOG_ERR("Space not configured for write locking.");
496 return NV_RESULT_INVALID_PARAMETER;
497 }
498
LockSpaceRead(const LockSpaceReadRequest & request,LockSpaceReadResponse *)499 nvram_result_t NvramManager::LockSpaceRead(
500 const LockSpaceReadRequest& request,
501 LockSpaceReadResponse* /* response */) {
502 const uint32_t index = request.index;
503 NVRAM_LOG_INFO("LockSpaceRead Ox%" PRIx32, index);
504
505 if (!Initialize())
506 return NV_RESULT_INTERNAL_ERROR;
507
508 SpaceRecord space_record;
509 nvram_result_t result;
510 if (!LoadSpaceRecord(index, &space_record, &result)) {
511 return result;
512 }
513
514 result = space_record.CheckReadAccess(request.authorization_value);
515 if (result != NV_RESULT_SUCCESS) {
516 return result;
517 }
518
519 if (space_record.persistent.HasControl(NV_CONTROL_BOOT_READ_LOCK)) {
520 space_record.transient->read_locked = true;
521 return NV_RESULT_SUCCESS;
522 }
523
524 NVRAM_LOG_ERR("Space not configured for read locking.");
525 return NV_RESULT_INVALID_PARAMETER;
526 }
527
WipeStorage(const WipeStorageRequest &,WipeStorageResponse *)528 nvram_result_t NvramManager::WipeStorage(
529 const WipeStorageRequest& /* request */,
530 WipeStorageResponse* /* response */) {
531 if (!Initialize())
532 return NV_RESULT_INTERNAL_ERROR;
533
534 #ifdef NVRAM_WIPE_STORAGE_SUPPORT
535 if (disable_wipe_) {
536 return NV_RESULT_OPERATION_DISABLED;
537 }
538
539 // Go through all spaces and wipe the corresponding data. Note that the header
540 // is only updated once all space data is gone. This will "break" all spaces
541 // that are left declared but don't have data. This situation can be observed
542 // if we crash somewhere during the wiping process before clearing the header.
543 //
544 // Note that we deliberately choose this wiping sequence so we can never end
545 // up in a state where the header appears clean but existing space data
546 // remains.
547 //
548 // As a final note, the ideal solution would be to atomically clear the header
549 // and delete all space data. While more desirable from an operational point
550 // of view, this would drastically complicate storage layer requirements to
551 // support cross-object atomicity instead of per-object atomicity.
552 for (size_t i = 0; i < num_spaces_; ++i) {
553 const uint32_t index = spaces_[i].index;
554 switch (SanitizeStorageStatus(persistence::DeleteSpace(index))) {
555 case storage::Status::kStorageError:
556 NVRAM_LOG_ERR("Failed to wipe space 0x%" PRIx32 " data.", index);
557 return NV_RESULT_INTERNAL_ERROR;
558 case storage::Status::kNotFound:
559 // The space was missing even if it shouldn't have been. This may occur
560 // if a previous wiping attempt was aborted half-way. Log an error, but
561 // return success as we're in the desired state.
562 NVRAM_LOG_WARN("Space 0x%" PRIx32 " data missing on wipe.", index);
563 break;
564 case storage::Status::kSuccess:
565 break;
566 }
567 }
568
569 // All spaces are gone, clear the header.
570 num_spaces_ = 0;
571 return WriteHeader(Optional<uint32_t>());
572 #else // NVRAM_WIPE_STORAGE_SUPPORT
573 // We're not accessing the flag member, so prevent a compiler warning. The
574 // alternative of conditionally including the member in the class declaration
575 // looks cleaner at first sight, but comes with the risk of
576 // NVRAM_WIPE_STORAGE_SUPPORT polarity mismatches between compilation units,
577 // which is more subtly dangerous, so we rather keep the member even for the
578 // case in which it is not used.
579 (void)disable_wipe_;
580 return NV_RESULT_OPERATION_DISABLED;
581 #endif // NVRAM_WIPE_STORAGE_SUPPORT
582 }
583
DisableWipe(const DisableWipeRequest &,DisableWipeResponse *)584 nvram_result_t NvramManager::DisableWipe(
585 const DisableWipeRequest& /* request */,
586 DisableWipeResponse* /* response */) {
587 if (!Initialize())
588 return NV_RESULT_INTERNAL_ERROR;
589
590 #ifdef NVRAM_WIPE_STORAGE_SUPPORT
591 disable_wipe_ = true;
592 return NV_RESULT_SUCCESS;
593 #else // NVRAM_WIPE_STORAGE_SUPPORT
594 return NV_RESULT_OPERATION_DISABLED;
595 #endif // NVRAM_WIPE_STORAGE_SUPPORT
596 }
597
CheckWriteAccess(const Blob & authorization_value)598 nvram_result_t NvramManager::SpaceRecord::CheckWriteAccess(
599 const Blob& authorization_value) {
600 if (persistent.HasControl(NV_CONTROL_PERSISTENT_WRITE_LOCK)) {
601 if (persistent.HasFlag(NvramSpace::kFlagWriteLocked)) {
602 NVRAM_LOG_INFO("Attempt to write persistently locked space 0x%" PRIx32
603 ".",
604 transient->index);
605 return NV_RESULT_OPERATION_DISABLED;
606 }
607 } else if (persistent.HasControl(NV_CONTROL_BOOT_WRITE_LOCK)) {
608 if (transient->write_locked) {
609 NVRAM_LOG_INFO("Attempt to write per-boot locked space 0x%" PRIx32 ".",
610 transient->index);
611 return NV_RESULT_OPERATION_DISABLED;
612 }
613 }
614
615 if (persistent.HasControl(NV_CONTROL_WRITE_AUTHORIZATION) &&
616 !ConstantTimeEquals(persistent.authorization_value,
617 authorization_value)) {
618 NVRAM_LOG_INFO(
619 "Authorization value mismatch for write access to space 0x%" PRIx32 ".",
620 transient->index);
621 return NV_RESULT_ACCESS_DENIED;
622 }
623
624 // All checks passed, allow the write.
625 return NV_RESULT_SUCCESS;
626 }
627
CheckReadAccess(const Blob & authorization_value)628 nvram_result_t NvramManager::SpaceRecord::CheckReadAccess(
629 const Blob& authorization_value) {
630 if (persistent.HasControl(NV_CONTROL_BOOT_READ_LOCK)) {
631 if (transient->read_locked) {
632 NVRAM_LOG_INFO("Attempt to read per-boot locked space 0x%" PRIx32 ".",
633 transient->index);
634 return NV_RESULT_OPERATION_DISABLED;
635 }
636 }
637
638 if (persistent.HasControl(NV_CONTROL_READ_AUTHORIZATION) &&
639 !ConstantTimeEquals(persistent.authorization_value,
640 authorization_value)) {
641 NVRAM_LOG_INFO(
642 "Authorization value mismatch for read access to space 0x%" PRIx32 ".",
643 transient->index);
644 return NV_RESULT_ACCESS_DENIED;
645 }
646
647 // All checks passed, allow the read.
648 return NV_RESULT_SUCCESS;
649 }
650
Initialize()651 bool NvramManager::Initialize() {
652 if (initialized_)
653 return true;
654
655 NvramHeader header;
656 switch (SanitizeStorageStatus(persistence::LoadHeader(&header))) {
657 case storage::Status::kStorageError:
658 NVRAM_LOG_ERR("Init failed to load header.");
659 return false;
660 case storage::Status::kNotFound:
661 // No header in storage. This happens the very first time we initialize
662 // on a fresh device where the header isn't present yet. The first write
663 // will flush the fresh header to storage.
664 initialized_ = true;
665 return true;
666 case storage::Status::kSuccess:
667 if (header.version > NvramHeader::kVersion) {
668 NVRAM_LOG_ERR("Storage format %" PRIu32 " is more recent than %" PRIu32
669 ", aborting.",
670 header.version, NvramHeader::kVersion);
671 return false;
672 }
673 break;
674 }
675
676 // Check the state of the provisional space if applicable.
677 const Optional<uint32_t>& provisional_index = header.provisional_index;
678 bool provisional_space_in_storage = false;
679 if (provisional_index.valid()) {
680 NvramSpace space;
681 switch (SanitizeStorageStatus(
682 persistence::LoadSpace(provisional_index.value(), &space))) {
683 case storage::Status::kStorageError:
684 // Log an error but leave the space marked as allocated. This will allow
685 // initialization to complete, so other spaces can be accessed.
686 // Operations on the bad space will fail however. The choice of keeping
687 // the bad space around (as opposed to dropping it) is intentional:
688 // * Failing noisily reduces the chances of bugs going undetected.
689 // * Keeping the index allocated prevents it from being accidentally
690 // clobbered due to appearing absent after transient storage errors.
691 NVRAM_LOG_ERR("Failed to load provisional space 0x%" PRIx32 ".",
692 provisional_index.value());
693 provisional_space_in_storage = true;
694 break;
695 case storage::Status::kNotFound:
696 break;
697 case storage::Status::kSuccess:
698 provisional_space_in_storage = true;
699 break;
700 }
701 }
702
703 // If there are more spaces allocated than this build supports, fail
704 // initialization. This may seem a bit drastic, but the alternatives aren't
705 // acceptable:
706 // * If we continued with just a subset of the spaces, that may lead to wrong
707 // conclusions about the system state in consumers. Furthermore, consumers
708 // might delete a space to make room and then create a space that appears
709 // free but is present in storage. This would clobber the existing space
710 // data and potentially violate its access control rules.
711 // * We could just try to allocate more memory to hold the larger number of
712 // spaces. That'd render the memory footprint of the NVRAM implementation
713 // unpredictable. One variation that may work is to allow a maximum number
714 // of existing spaces larger than kMaxSpaces, but still within sane limits.
715 if (header.allocated_indices.size() > kMaxSpaces) {
716 NVRAM_LOG_ERR("Excess spaces %zu in header.",
717 header.allocated_indices.size());
718 return false;
719 }
720
721 // Initialize the transient space bookkeeping data.
722 bool delete_provisional_space = provisional_index.valid();
723 for (uint32_t index : header.allocated_indices) {
724 if (provisional_index.valid() && provisional_index.value() == index) {
725 // The provisional space index refers to a created space. If it isn't
726 // valid, pretend it was never created.
727 if (!provisional_space_in_storage) {
728 continue;
729 }
730
731 // The provisional space index corresponds to a created space that is
732 // present in storage. Retain the space.
733 delete_provisional_space = false;
734 }
735
736 spaces_[num_spaces_].index = index;
737 spaces_[num_spaces_].write_locked = false;
738 spaces_[num_spaces_].read_locked = false;
739 ++num_spaces_;
740 }
741
742 // If the provisional space data is present in storage, but the index wasn't
743 // in |header.allocated_indices|, it refers to half-deleted space. Destroy the
744 // space in that case.
745 if (delete_provisional_space) {
746 switch (SanitizeStorageStatus(
747 persistence::DeleteSpace(provisional_index.value()))) {
748 case storage::Status::kStorageError:
749 NVRAM_LOG_ERR("Failed to delete provisional space 0x%" PRIx32 " data.",
750 provisional_index.value());
751 return false;
752 case storage::Status::kNotFound:
753 // The space isn't present in storage. This may happen if the space
754 // deletion succeeded, but the header wasn't written subsequently.
755 break;
756 case storage::Status::kSuccess:
757 break;
758 }
759 }
760
761 disable_create_ = header.HasFlag(NvramHeader::kFlagDisableCreate);
762 initialized_ = true;
763
764 // Write the header to clear the provisional index if necessary. It's actually
765 // not a problem if this fails, because the state is consistent regardless. We
766 // still do this opportunistically in order to avoid loading the provisional
767 // space data for each reboot after a crash.
768 if (provisional_index.valid()) {
769 WriteHeader(Optional<uint32_t>());
770 }
771
772 return true;
773 }
774
FindSpace(uint32_t space_index)775 size_t NvramManager::FindSpace(uint32_t space_index) {
776 for (size_t i = 0; i < num_spaces_; ++i) {
777 if (spaces_[i].index == space_index) {
778 return i;
779 }
780 }
781
782 return kMaxSpaces;
783 }
784
LoadSpaceRecord(uint32_t index,SpaceRecord * space_record,nvram_result_t * result)785 bool NvramManager::LoadSpaceRecord(uint32_t index,
786 SpaceRecord* space_record,
787 nvram_result_t* result) {
788 space_record->array_index = FindSpace(index);
789 if (space_record->array_index == kMaxSpaces) {
790 *result = NV_RESULT_SPACE_DOES_NOT_EXIST;
791 return false;
792 }
793
794 space_record->transient = &spaces_[space_record->array_index];
795
796 switch (SanitizeStorageStatus(
797 persistence::LoadSpace(index, &space_record->persistent))) {
798 case storage::Status::kStorageError:
799 NVRAM_LOG_ERR("Failed to load space 0x%" PRIx32 " data.", index);
800 *result = NV_RESULT_INTERNAL_ERROR;
801 return false;
802 case storage::Status::kNotFound:
803 // This should never happen if the header contains the index.
804 NVRAM_LOG_ERR("Space index 0x%" PRIx32
805 " present in header, but data missing.",
806 index);
807 *result = NV_RESULT_INTERNAL_ERROR;
808 return false;
809 case storage::Status::kSuccess:
810 *result = NV_RESULT_SUCCESS;
811 return true;
812 }
813
814 *result = NV_RESULT_INTERNAL_ERROR;
815 return false;
816 }
817
WriteHeader(Optional<uint32_t> provisional_index)818 nvram_result_t NvramManager::WriteHeader(Optional<uint32_t> provisional_index) {
819 NvramHeader header;
820 header.version = NvramHeader::kVersion;
821 if (disable_create_) {
822 header.SetFlag(NvramHeader::kFlagDisableCreate);
823 }
824
825 if (!header.allocated_indices.Resize(num_spaces_)) {
826 NVRAM_LOG_ERR("Allocation failure.");
827 return NV_RESULT_INTERNAL_ERROR;
828 }
829 for (size_t i = 0; i < num_spaces_; ++i) {
830 header.allocated_indices[i] = spaces_[i].index;
831 }
832
833 header.provisional_index = provisional_index;
834
835 if (SanitizeStorageStatus(persistence::StoreHeader(header)) !=
836 storage::Status::kSuccess) {
837 NVRAM_LOG_ERR("Failed to store header.");
838 return NV_RESULT_INTERNAL_ERROR;
839 }
840
841 return NV_RESULT_SUCCESS;
842 }
843
WriteSpace(uint32_t index,const NvramSpace & space)844 nvram_result_t NvramManager::WriteSpace(uint32_t index,
845 const NvramSpace& space) {
846 if (SanitizeStorageStatus(persistence::StoreSpace(index, space)) !=
847 storage::Status::kSuccess) {
848 NVRAM_LOG_ERR("Failed to store space 0x%" PRIx32 ".", index);
849 return NV_RESULT_INTERNAL_ERROR;
850 }
851
852 return NV_RESULT_SUCCESS;
853 }
854
855 } // namespace nvram
856