1 // 2 // Copyright (C) 2015 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 TRUNKS_RESOURCE_MANAGER_H_ 18 #define TRUNKS_RESOURCE_MANAGER_H_ 19 20 #include "trunks/command_transceiver.h" 21 22 #include <map> 23 #include <set> 24 #include <string> 25 #include <vector> 26 27 #include <base/location.h> 28 #include <base/macros.h> 29 #include <base/time/time.h> 30 31 #include "trunks/tpm_generated.h" 32 #include "trunks/trunks_factory.h" 33 34 namespace trunks { 35 36 // The ResourceManager class manages access to limited TPM resources. 37 // 38 // It is reactive to and synchronous with active TPM commands, it does not 39 // perform any background processing. It needs to inspect every TPM command and 40 // reply. It maintains all actual TPM handles and provides its own handles to 41 // callers. If a command fails because a resource is not available the resource 42 // manager will perform the necessary evictions and run the command again. If a 43 // command needs an object that has been evicted, that object will be loaded 44 // before the command is sent to the TPM. 45 // 46 // In terms of interface the ResourceManager is simply a CommandTranceiver but 47 // with the limitation that all calls are synchronous. The SendCommand method 48 // is supported but does not return until the callback has been called. Keeping 49 // ResourceManager synchronous simplifies the code and improves readability. 50 // This class works well with a BackgroundCommandTransceiver. 51 class ResourceManager : public CommandTransceiver { 52 public: 53 // The given |factory| will be used to create objects so mocks can be easily 54 // injected. This class retains a reference to the factory; the factory must 55 // remain valid for the duration of the ResourceManager lifetime. The 56 // |next_transceiver| will be used to forward commands to the TPM, this class 57 // does NOT take ownership of the pointer. 58 ResourceManager(const TrunksFactory& factory, 59 CommandTransceiver* next_transceiver); 60 ~ResourceManager() override; 61 62 void Initialize(); 63 64 // CommandTransceiver methods. 65 void SendCommand(const std::string& command, 66 const ResponseCallback& callback) override; 67 68 std::string SendCommandAndWait(const std::string& command) override; 69 70 private: 71 struct MessageInfo { 72 bool has_sessions; 73 TPM_CC code; // For a response message this is the TPM_RC response code. 74 std::vector<TPM_HANDLE> handles; 75 std::vector<TPM_HANDLE> session_handles; 76 std::vector<bool> session_continued; 77 std::string parameter_data; 78 }; 79 80 struct HandleInfo { 81 HandleInfo(); 82 // Initializes info for a loaded handle. 83 void Init(TPM_HANDLE handle); 84 85 bool is_loaded; 86 // Valid only if |is_loaded| is true. 87 TPM_HANDLE tpm_handle; 88 // Valid only if |is_loaded| is false. 89 TPMS_CONTEXT context; 90 // Time when the handle is create. 91 base::TimeTicks time_of_create; 92 // Time when the handle was last used. 93 base::TimeTicks time_of_last_use; 94 }; 95 96 // Chooses an appropriate session for eviction (or flush) which is not one of 97 // |sessions_to_retain| and assigns it to |session_to_evict|. Returns true on 98 // success. 99 bool ChooseSessionToEvict(const std::vector<TPM_HANDLE>& sessions_to_retain, 100 TPM_HANDLE* session_to_evict); 101 102 // Cleans up all references to and information about |flushed_handle|. 103 void CleanupFlushedHandle(TPM_HANDLE flushed_handle); 104 105 // Creates a new virtual object handle. If the handle space is exhausted a 106 // valid handle is flushed and re-used. 107 TPM_HANDLE CreateVirtualHandle(); 108 109 // Given a session handle, ensures the session is loaded in the TPM. 110 TPM_RC EnsureSessionIsLoaded(const MessageInfo& command_info, 111 TPM_HANDLE session_handle); 112 113 // Evicts all loaded objects except those required by |command_info|. The 114 // eviction is best effort; any errors will be ignored. 115 void EvictObjects(const MessageInfo& command_info); 116 117 // Evicts a session other than those required by |command_info|. The eviction 118 // is best effort; any errors will be ignored. 119 void EvictSession(const MessageInfo& command_info); 120 121 // Returns a list of handles parsed from a given |buffer|. No more than 122 // |number_of_handles| will be parsed. 123 std::vector<TPM_HANDLE> ExtractHandlesFromBuffer(size_t number_of_handles, 124 std::string* buffer); 125 126 // A context gap may occur when context counters for active sessions drift too 127 // far apart for the TPM to manage. Basically, the TPM needs to reassign new 128 // counters to saved sessions. See the TPM Library Specification Part 1 129 // Section 30.5 Session Context Management for details. 130 void FixContextGap(const MessageInfo& command_info); 131 132 // Performs best-effort handling of actionable warnings. The |command_info| 133 // must correspond with the current command being processed by the resource 134 // manager. Returns true only if |result| represents an actionable warning and 135 // it has been handled. 136 bool FixWarnings(const MessageInfo& command_info, TPM_RC result); 137 138 // Flushes a session other than those required by |command_info|. The flush is 139 // best effort; any errors will be ignored. 140 void FlushSession(const MessageInfo& command_info); 141 142 // When a caller saves context, the resource manager retains that context and 143 // possible trades it for new context data to fix a context gap (see 144 // FixContextGap). So when the caller wants to load the original context again 145 // it needs to be swapped with the latest actual context maintained by the 146 // resource manager. This method finds the correct TPM context for a given 147 // |external_context| previously returned to the caller. If not found, 148 // |external_context| is returned. 149 std::string GetActualContextFromExternalContext( 150 const std::string& external_context); 151 152 // Returns true iff |handle| is a transient object handle. 153 bool IsObjectHandle(TPM_HANDLE handle) const; 154 155 // Returns true iff |handle| is a session handle. 156 bool IsSessionHandle(TPM_HANDLE handle) const; 157 158 // Loads the context for a session or object handle. On success returns 159 // TPM_RC_SUCCESS and ensures |handle_info| holds a valid handle (and invalid 160 // context data). 161 TPM_RC LoadContext(const MessageInfo& command_info, HandleInfo* handle_info); 162 163 // Returns a resource manager error code given a particular |tpm_error| and 164 // logs the occurrence of the error. 165 TPM_RC MakeError(TPM_RC tpm_error, 166 const ::tracked_objects::Location& location); 167 168 // Parses a |command|, sanity checking its format and extracting 169 // |message_info| on success. Returns TPM_RC_SUCCESS on success. 170 TPM_RC ParseCommand(const std::string& command, MessageInfo* message_info); 171 172 // Parses a |response| to a command associated with |command_info|. The 173 // response is sanity checked and |response_info| is extracted. Returns 174 // TPM_RC_SUCCESS on success. 175 TPM_RC ParseResponse(const MessageInfo& command_info, 176 const std::string& response, 177 MessageInfo* response_info); 178 179 // Performs processing after a successful external ContextSave operation. 180 // A subsequent call to GetActualContextFromExternalContext will succeed for 181 // the context. 182 void ProcessExternalContextSave(const MessageInfo& command_info, 183 const MessageInfo& response_info); 184 185 // Process an external flush context |command|. 186 std::string ProcessFlushContext(const std::string& command, 187 const MessageInfo& command_info); 188 189 // Given a |virtual_handle| created by this resource manager, finds the 190 // associated TPM |actual_handle|, restoring the object if necessary. The 191 // current |command_info| must be provided. If |virtual_handle| is not an 192 // object handle, then |actual_handle| is set to |virtual_handle|. Returns 193 // TPM_RC_SUCCESS on success. 194 TPM_RC ProcessInputHandle(const MessageInfo& command_info, 195 TPM_HANDLE virtual_handle, 196 TPM_HANDLE* actual_handle); 197 198 // Given a TPM object handle, returns an associated virtual handle, generating 199 // a new one if necessary. 200 TPM_HANDLE ProcessOutputHandle(TPM_HANDLE object_handle); 201 202 // Replaces all handles in a given |message| with |new_handles| and returns 203 // the resulting modified message. The modified message is guaranteed to have 204 // the same length as the input message. 205 std::string ReplaceHandles(const std::string& message, 206 const std::vector<TPM_HANDLE>& new_handles); 207 208 // Saves the context for a session or object handle. On success returns 209 // TPM_RC_SUCCESS and ensures |handle_info| holds valid context data. 210 TPM_RC SaveContext(const MessageInfo& command_info, HandleInfo* handle_info); 211 212 const TrunksFactory& factory_; 213 CommandTransceiver* next_transceiver_ = nullptr; 214 TPM_HANDLE next_virtual_handle_ = TRANSIENT_FIRST; 215 216 // A mapping of known virtual handles to corresponding HandleInfo. 217 std::map<TPM_HANDLE, HandleInfo> virtual_object_handles_; 218 // A mapping of loaded tpm object handles to the corresponding virtual handle. 219 std::map<TPM_HANDLE, TPM_HANDLE> tpm_object_handles_; 220 // A mapping of known session handles to corresponding HandleInfo. 221 std::map<TPM_HANDLE, HandleInfo> session_handles_; 222 // A mapping of external context blobs to current context blobs. 223 std::map<std::string, std::string> external_context_to_actual_; 224 // A mapping of actual context blobs to external context blobs. 225 std::map<std::string, std::string> actual_context_to_external_; 226 227 // The set of warnings already handled in the context of a FixWarnings() call. 228 // Tracking this allows us to avoid re-entrance. 229 std::set<TPM_RC> warnings_already_seen_; 230 // Whether a FixWarnings() call is currently executing. 231 bool fixing_warnings_ = false; 232 233 DISALLOW_COPY_AND_ASSIGN(ResourceManager); 234 }; 235 236 } // namespace trunks 237 238 #endif // TRUNKS_RESOURCE_MANAGER_H_ 239