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 #ifndef NVRAM_CORE_NVRAM_MANAGER_H_
18 #define NVRAM_CORE_NVRAM_MANAGER_H_
19 
20 #include <nvram/messages/nvram_messages.h>
21 
22 #include <nvram/core/persistence.h>
23 
24 namespace nvram {
25 
26 // |NvramManager| implements the core functionality of the access-controlled
27 // NVRAM HAL backend. It keeps track of the allocated spaces and their state,
28 // including the transient state that is held per boot. It provides operations
29 // for querying, creating, deleting, reading and writing spaces. It deals with
30 // persistent storage objects in the form of |NvramHeader| and |NvramSpace|
31 // objects and uses the persistence layer to read and write them from persistent
32 // storage.
33 class NvramManager {
34  public:
35   // Looks at |request| to determine the command to execute, extracts the
36   // request parameters and invokes the correct handler function. Stores status
37   // and output parameters in |response|.
38   void Dispatch(const Request& request, Response* response);
39 
40   nvram_result_t GetInfo(const GetInfoRequest& request,
41                          GetInfoResponse* response);
42   nvram_result_t CreateSpace(const CreateSpaceRequest& request,
43                              CreateSpaceResponse* response);
44   nvram_result_t GetSpaceInfo(const GetSpaceInfoRequest& request,
45                               GetSpaceInfoResponse* response);
46   nvram_result_t DeleteSpace(const DeleteSpaceRequest& request,
47                              DeleteSpaceResponse* response);
48   nvram_result_t DisableCreate(const DisableCreateRequest& request,
49                                DisableCreateResponse* response);
50   nvram_result_t WriteSpace(const WriteSpaceRequest& request,
51                             WriteSpaceResponse* response);
52   nvram_result_t ReadSpace(const ReadSpaceRequest& request,
53                            ReadSpaceResponse* response);
54   nvram_result_t LockSpaceWrite(const LockSpaceWriteRequest& request,
55                                 LockSpaceWriteResponse* response);
56   nvram_result_t LockSpaceRead(const LockSpaceReadRequest& request,
57                                LockSpaceReadResponse* response);
58 
59   // The wipe functions are meant for use by firmware after determining the
60   // device's mode of operation. These can be used to clear access-controlled
61   // NVRAM when a user invokes a full hardware reset. Note that in regular
62   // operation, the user *MUST BE PREVENTED* from wiping access-controlled
63   // NVRAM.
64   //
65   // If a full hardware reset can conveniently clear the access-controlled NVRAM
66   // storage area out of band, it's fine to do so. In this case, the
67   // wiping-related commands should not be exposed at all. Note that this is the
68   // default behavior - the reference implementation will ignore all wipe
69   // requests unless compiled with NVRAM_WIPE_STORAGE_SUPPORT=1.
70   //
71   // For devices where firmware doesn't have direct control over the storage
72   // area used by access-controlled NVRAM, the wiping commands are provided to
73   // facilitate clearing storage:
74   //   1. Determine boot mode.
75   //   2. If not in recovery mode, call DisableWipe(). All further wipe requests
76   //      will be rejected. A reboot (or TEE restart for that matter) is
77   //      required before a new decision can be made.
78   //   3. If operating in recovery mode, forgo calling DisableWipe(). The
79   //      recovery process will then be able to invoke WipeStorage() later as
80   //      needed.
81   nvram_result_t WipeStorage(const WipeStorageRequest& request,
82                              WipeStorageResponse* response);
83   nvram_result_t DisableWipe(const DisableWipeRequest& request,
84                              DisableWipeResponse* response);
85 
86  private:
87   // Holds transient state corresponding to an allocated NVRAM space, i.e. meta
88   // data valid for a single boot. One instance of this struct is kept in memory
89   // in the |spaces_| array for each of the spaces that are currently allocated.
90   struct SpaceListEntry {
91     uint32_t index;
92     bool write_locked = false;
93     bool read_locked = false;
94   };
95 
96   // |SpaceRecord| holds all information known about a space. It includes both
97   // an index and pointer to the transient information held in the
98   // |SpaceListEntry| in the |spaces_| array and the persistent |NvramSpace|
99   // state held in permanent storage. We only load the persistent space data
100   // from storage when it is needed for an operation, such as reading and
101   // writing space contents.
102   struct SpaceRecord {
103     // Access control check for write access to the space. The
104     // |authorization_value| is only relevant if the space was configured to
105     // require authorization. Returns RESULT_SUCCESS if write access is
106     // permitted and a suitable result code to return to the client on failure.
107     nvram_result_t CheckWriteAccess(const Blob& authorization_value);
108 
109     // Access control check for read access to the space. The
110     // |authorization_value| is only relevant if the space was configured to
111     // require authorization. Returns RESULT_SUCCESS if write access is
112     // permitted and a suitable result code to return the client on failure.
113     nvram_result_t CheckReadAccess(const Blob& authorization_value);
114 
115     size_t array_index = 0;
116     SpaceListEntry* transient = nullptr;
117     NvramSpace persistent;
118   };
119 
120   // Initializes |header_| from storage if that hasn't happened already. Returns
121   // true if NvramManager object is initialized and ready to serve requests. May
122   // be called again after failure to attempt initialization again.
123   bool Initialize();
124 
125   // Finds the array index in |spaces_| that corresponds to |space_index|.
126   // Returns |kMaxSpaces| if there is no matching space.
127   size_t FindSpace(uint32_t space_index);
128 
129   // Loads space data for |index|. Fills in |space_record| and returns true if
130   // successful. Returns false and sets |result| on error.
131   bool LoadSpaceRecord(uint32_t index,
132                        SpaceRecord* space_record,
133                        nvram_result_t* result);
134 
135   // Writes the header to storage and returns a suitable status code.
136   nvram_result_t WriteHeader(Optional<uint32_t> provisional_index);
137 
138   // Write |space| data for |index|.
139   nvram_result_t WriteSpace(uint32_t index, const NvramSpace& space);
140 
141   // Maximum number of NVRAM spaces we're willing to allocate.
142   static constexpr size_t kMaxSpaces = 32;
143 
144   bool initialized_ = false;
145   bool disable_create_ = false;
146   bool disable_wipe_ = false;
147 
148   // Bookkeeping information for allocated spaces.
149   size_t num_spaces_ = 0;
150   SpaceListEntry spaces_[kMaxSpaces];
151 };
152 
153 }  // namespace nvram
154 
155 #endif  // NVRAM_CORE_NVRAM_MANAGER_H_
156