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. 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. 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> 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|. 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. 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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