| // |
| // Copyright (C) 2015 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| |
| #ifndef TRUNKS_RESOURCE_MANAGER_H_ |
| #define TRUNKS_RESOURCE_MANAGER_H_ |
| |
| #include "trunks/command_transceiver.h" |
| |
| #include <map> |
| #include <set> |
| #include <string> |
| #include <vector> |
| |
| #include <base/location.h> |
| #include <base/macros.h> |
| #include <base/time/time.h> |
| |
| #include "trunks/tpm_generated.h" |
| #include "trunks/trunks_factory.h" |
| |
| namespace trunks { |
| |
| // The ResourceManager class manages access to limited TPM resources. |
| // |
| // It is reactive to and synchronous with active TPM commands, it does not |
| // perform any background processing. It needs to inspect every TPM command and |
| // reply. It maintains all actual TPM handles and provides its own handles to |
| // callers. If a command fails because a resource is not available the resource |
| // manager will perform the necessary evictions and run the command again. If a |
| // command needs an object that has been evicted, that object will be loaded |
| // before the command is sent to the TPM. |
| // |
| // In terms of interface the ResourceManager is simply a CommandTranceiver but |
| // with the limitation that all calls are synchronous. The SendCommand method |
| // is supported but does not return until the callback has been called. Keeping |
| // ResourceManager synchronous simplifies the code and improves readability. |
| // This class works well with a BackgroundCommandTransceiver. |
| class ResourceManager : public CommandTransceiver { |
| public: |
| // The given |factory| will be used to create objects so mocks can be easily |
| // injected. This class retains a reference to the factory; the factory must |
| // remain valid for the duration of the ResourceManager lifetime. The |
| // |next_transceiver| will be used to forward commands to the TPM, this class |
| // does NOT take ownership of the pointer. |
| ResourceManager(const TrunksFactory& factory, |
| CommandTransceiver* next_transceiver); |
| ~ResourceManager() override; |
| |
| void Initialize(); |
| |
| // CommandTransceiver methods. |
| void SendCommand(const std::string& command, |
| const ResponseCallback& callback) override; |
| |
| std::string SendCommandAndWait(const std::string& command) override; |
| |
| private: |
| struct MessageInfo { |
| bool has_sessions; |
| TPM_CC code; // For a response message this is the TPM_RC response code. |
| std::vector<TPM_HANDLE> handles; |
| std::vector<TPM_HANDLE> session_handles; |
| std::vector<bool> session_continued; |
| std::string parameter_data; |
| }; |
| |
| struct HandleInfo { |
| HandleInfo(); |
| // Initializes info for a loaded handle. |
| void Init(TPM_HANDLE handle); |
| |
| bool is_loaded; |
| // Valid only if |is_loaded| is true. |
| TPM_HANDLE tpm_handle; |
| // Valid only if |is_loaded| is false. |
| TPMS_CONTEXT context; |
| // Time when the handle is create. |
| base::TimeTicks time_of_create; |
| // Time when the handle was last used. |
| base::TimeTicks time_of_last_use; |
| }; |
| |
| // Chooses an appropriate session for eviction (or flush) which is not one of |
| // |sessions_to_retain| and assigns it to |session_to_evict|. Returns true on |
| // success. |
| bool ChooseSessionToEvict(const std::vector<TPM_HANDLE>& sessions_to_retain, |
| TPM_HANDLE* session_to_evict); |
| |
| // Cleans up all references to and information about |flushed_handle|. |
| void CleanupFlushedHandle(TPM_HANDLE flushed_handle); |
| |
| // Creates a new virtual object handle. If the handle space is exhausted a |
| // valid handle is flushed and re-used. |
| TPM_HANDLE CreateVirtualHandle(); |
| |
| // Given a session handle, ensures the session is loaded in the TPM. |
| TPM_RC EnsureSessionIsLoaded(const MessageInfo& command_info, |
| TPM_HANDLE session_handle); |
| |
| // Evicts all loaded objects except those required by |command_info|. The |
| // eviction is best effort; any errors will be ignored. |
| void EvictObjects(const MessageInfo& command_info); |
| |
| // Evicts a session other than those required by |command_info|. The eviction |
| // is best effort; any errors will be ignored. |
| void EvictSession(const MessageInfo& command_info); |
| |
| // Returns a list of handles parsed from a given |buffer|. No more than |
| // |number_of_handles| will be parsed. |
| std::vector<TPM_HANDLE> ExtractHandlesFromBuffer(size_t number_of_handles, |
| std::string* buffer); |
| |
| // A context gap may occur when context counters for active sessions drift too |
| // far apart for the TPM to manage. Basically, the TPM needs to reassign new |
| // counters to saved sessions. See the TPM Library Specification Part 1 |
| // Section 30.5 Session Context Management for details. |
| void FixContextGap(const MessageInfo& command_info); |
| |
| // Performs best-effort handling of actionable warnings. The |command_info| |
| // must correspond with the current command being processed by the resource |
| // manager. Returns true only if |result| represents an actionable warning and |
| // it has been handled. |
| bool FixWarnings(const MessageInfo& command_info, TPM_RC result); |
| |
| // Flushes a session other than those required by |command_info|. The flush is |
| // best effort; any errors will be ignored. |
| void FlushSession(const MessageInfo& command_info); |
| |
| // When a caller saves context, the resource manager retains that context and |
| // possible trades it for new context data to fix a context gap (see |
| // FixContextGap). So when the caller wants to load the original context again |
| // it needs to be swapped with the latest actual context maintained by the |
| // resource manager. This method finds the correct TPM context for a given |
| // |external_context| previously returned to the caller. If not found, |
| // |external_context| is returned. |
| std::string GetActualContextFromExternalContext( |
| const std::string& external_context); |
| |
| // Returns true iff |handle| is a transient object handle. |
| bool IsObjectHandle(TPM_HANDLE handle) const; |
| |
| // Returns true iff |handle| is a session handle. |
| bool IsSessionHandle(TPM_HANDLE handle) const; |
| |
| // Loads the context for a session or object handle. On success returns |
| // TPM_RC_SUCCESS and ensures |handle_info| holds a valid handle (and invalid |
| // context data). |
| TPM_RC LoadContext(const MessageInfo& command_info, HandleInfo* handle_info); |
| |
| // Returns a resource manager error code given a particular |tpm_error| and |
| // logs the occurrence of the error. |
| TPM_RC MakeError(TPM_RC tpm_error, |
| const ::tracked_objects::Location& location); |
| |
| // Parses a |command|, sanity checking its format and extracting |
| // |message_info| on success. Returns TPM_RC_SUCCESS on success. |
| TPM_RC ParseCommand(const std::string& command, MessageInfo* message_info); |
| |
| // Parses a |response| to a command associated with |command_info|. The |
| // response is sanity checked and |response_info| is extracted. Returns |
| // TPM_RC_SUCCESS on success. |
| TPM_RC ParseResponse(const MessageInfo& command_info, |
| const std::string& response, |
| MessageInfo* response_info); |
| |
| // Performs processing after a successful external ContextSave operation. |
| // A subsequent call to GetActualContextFromExternalContext will succeed for |
| // the context. |
| void ProcessExternalContextSave(const MessageInfo& command_info, |
| const MessageInfo& response_info); |
| |
| // Process an external flush context |command|. |
| std::string ProcessFlushContext(const std::string& command, |
| const MessageInfo& command_info); |
| |
| // Given a |virtual_handle| created by this resource manager, finds the |
| // associated TPM |actual_handle|, restoring the object if necessary. The |
| // current |command_info| must be provided. If |virtual_handle| is not an |
| // object handle, then |actual_handle| is set to |virtual_handle|. Returns |
| // TPM_RC_SUCCESS on success. |
| TPM_RC ProcessInputHandle(const MessageInfo& command_info, |
| TPM_HANDLE virtual_handle, |
| TPM_HANDLE* actual_handle); |
| |
| // Given a TPM object handle, returns an associated virtual handle, generating |
| // a new one if necessary. |
| TPM_HANDLE ProcessOutputHandle(TPM_HANDLE object_handle); |
| |
| // Replaces all handles in a given |message| with |new_handles| and returns |
| // the resulting modified message. The modified message is guaranteed to have |
| // the same length as the input message. |
| std::string ReplaceHandles(const std::string& message, |
| const std::vector<TPM_HANDLE>& new_handles); |
| |
| // Saves the context for a session or object handle. On success returns |
| // TPM_RC_SUCCESS and ensures |handle_info| holds valid context data. |
| TPM_RC SaveContext(const MessageInfo& command_info, HandleInfo* handle_info); |
| |
| const TrunksFactory& factory_; |
| CommandTransceiver* next_transceiver_ = nullptr; |
| TPM_HANDLE next_virtual_handle_ = TRANSIENT_FIRST; |
| |
| // A mapping of known virtual handles to corresponding HandleInfo. |
| std::map<TPM_HANDLE, HandleInfo> virtual_object_handles_; |
| // A mapping of loaded tpm object handles to the corresponding virtual handle. |
| std::map<TPM_HANDLE, TPM_HANDLE> tpm_object_handles_; |
| // A mapping of known session handles to corresponding HandleInfo. |
| std::map<TPM_HANDLE, HandleInfo> session_handles_; |
| // A mapping of external context blobs to current context blobs. |
| std::map<std::string, std::string> external_context_to_actual_; |
| // A mapping of actual context blobs to external context blobs. |
| std::map<std::string, std::string> actual_context_to_external_; |
| |
| // The set of warnings already handled in the context of a FixWarnings() call. |
| // Tracking this allows us to avoid re-entrance. |
| std::set<TPM_RC> warnings_already_seen_; |
| // Whether a FixWarnings() call is currently executing. |
| bool fixing_warnings_ = false; |
| |
| DISALLOW_COPY_AND_ASSIGN(ResourceManager); |
| }; |
| |
| } // namespace trunks |
| |
| #endif // TRUNKS_RESOURCE_MANAGER_H_ |