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