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