238 lines
10 KiB
C++
238 lines
10 KiB
C++
//
|
|
// 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_
|