Home | History | Annotate | Download | only in core
      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