resource_manager.h revision 89a5173601e7e2f68dbbd064a228ea6e4c7f2abf
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
34namespace 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.
51class 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