Asylo
enclave_manager.h
Go to the documentation of this file.
1 /*
2  *
3  * Copyright 2018 Asylo authors
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 #ifndef ASYLO_PLATFORM_CORE_ENCLAVE_MANAGER_H_
20 #define ASYLO_PLATFORM_CORE_ENCLAVE_MANAGER_H_
21 
22 // Declares the enclave client API, providing types and methods for loading,
23 // accessing, and finalizing enclaves.
24 
25 #include <string>
26 #include <utility>
27 
28 #include "absl/container/flat_hash_map.h"
29 #include "absl/memory/memory.h"
30 #include "absl/strings/string_view.h"
31 #include "absl/synchronization/mutex.h"
32 #include "absl/time/time.h"
33 #include "absl/types/variant.h"
34 #include "asylo/enclave.pb.h" // IWYU pragma: export
35 #include "asylo/platform/core/enclave_client.h"
36 #include "asylo/platform/core/enclave_config_util.h"
37 #include "asylo/platform/core/shared_resource_manager.h"
38 #include "asylo/util/status.h" // IWYU pragma: export
39 #include "asylo/util/statusor.h"
40 
41 namespace asylo {
42 class EnclaveLoader;
43 
44 /// Enclave Manager configuration.
46  public:
47  /// Configuration server connection attributes.
48  ///
49  /// A part of an enclave's configuration is expected to be the same across all
50  /// enclaves running under a single instance of an OS. An Enclave manager can
51  /// obtain such configuration from the Asylo daemon running on the system.
52  /// Alternately, the creator of the enclave manager can directly provide such
53  /// configuration to the enclave manager. To this end, an
54  /// EnclaveManagerOptions instance either holds the information necessary for
55  /// connecting to the config server, or holds a HostConfig proto. If the
56  /// enclave manager is configured with an options object containing the
57  /// server-connection information, the enclave manager obtains the necessary
58  /// information by contacting the Asylo daemon. Else, the enclave manager
59  /// directly uses the HostConfig info stored within the options structure.
60  ///
61  /// The ConfigServerConnectionAttributes struct holds information necessary
62  /// for contacting the config server running inside the Asylo daemon.
64  ConfigServerConnectionAttributes(std::string address, absl::Duration timeout)
67 
68  std::string server_address;
70  };
71 
72  /// Constructs a default EnclaveManagerOptions object.
74 
75  /// Configures a connection to the config server.
76  ///
77  /// Sets the information necessary for contacting the config server within the
78  /// Asylo daemon.
79  ///
80  /// \return A reference to this EnclaveManagerOptions object.
82  std::string address, absl::Duration timeout);
83 
84  /// Sets the HostConfig proto within this object.
85  ///
86  /// \return A reference to this EnclaveManagerOptions object.
87  EnclaveManagerOptions &set_host_config(HostConfig config);
88 
89  /// Returns the address of the configuration server.
90  ///
91  /// \return The address of the server from which the HostConfig information
92  /// can be obtained. Returns an error if
93  /// ConfigServerConnectionAttributes are not set.
95 
96  /// Returns the configuration server connection timeout.
97  ///
98  /// \return The connection timeout for the server from which the HostConfig
99  /// information can be obtained, or an error if
100  /// ConfigServerConnectionAttributes are not set.
102 
103  /// Returns the embedded HostConfig object.
104  ///
105  /// \return The HostConfig information embedded within this object, or an
106  /// error if such information is not embedded within the object.
108 
109  /// Returns true if a HostConfig instance is embedded in this object.
110  bool holds_host_config() const;
111 
112  private:
113  // A variant that either holds information necessary for connecting to the
114  // config server or a HostConfig proto.
115  absl::variant<ConfigServerConnectionAttributes, HostConfig> host_config_info_;
116 };
117 
118 /// A manager object responsible for creating and managing enclave instances.
119 ///
120 /// EnclaveManager is a singleton class that tracks the status of enclaves
121 /// within a process. Users of this class first supply a configuration using the
122 /// static Configure() method, and then get a pointer to the singleton instance
123 /// as specified by this configuration by calling the static Instance() method.
124 /// Note that the EnclaveManager class must be configured before the instance
125 /// pointer can be obtained.
126 ///
127 /// The EnclaveManager::Configure() method takes an instance of the
128 /// EnclaveManagerOptions as its only input. This instance can be configured by
129 /// calling its public setter methods. Note that these setter methods return an
130 /// instance of the EnclaveManagerOptions() by reference so that the various
131 /// setters could be chained together.
132 ///
133 /// Example Usage:
134 /// ```
135 /// EnclaveManager::Configure(
136 /// EnclaveManagerOptions()
137 /// .set_config_server_connection_attributes(
138 /// "[::]:8000",
139 /// absl::Milliseconds(100)));
140 /// auto manager_result = EnclaveManager::Instance();
141 /// if (!manager_result.ok()) {
142 /// LOG(QFATAL) << manager_result.status();
143 /// }
144 /// EnclaveManager *manager = manager_result.ValueOrDie();
145 /// ...
146 /// ```
147 ///
148 /// One of the responsibilities of the EnclaveManager class is to provide sane
149 /// initial configuration to the enclaves it launches. The contents of the
150 /// EnclaveManagerOptions instance control how the default values for the
151 /// configuration are chosen.
152 class EnclaveManager {
153  public:
154  /// Fetches the EnclaveManager singleton instance.
155  ///
156  /// \return A StatusOr containing either the global EnclaveManager instance or
157  /// an error describing why it could not be returned.
158  static StatusOr<EnclaveManager *> Instance();
159 
160  /// Configures the enclave manager.
161  ///
162  /// \param options Configuration options as described in
163  /// EnclaveManagerOptions.
165 
166  /// Loads an enclave.
167  ///
168  /// Loads a new enclave with default enclave config settings and binds it to a
169  /// name. The actual work of opening the enclave is delegated to the passed
170  /// loader object.
171  ///
172  /// It is an error to specify a name which is already bound to an enclave.
173  ///
174  /// Example:
175  /// ```
176  /// LoadEnclave("/EchoEnclave", SgxLoader("echoService.so"));
177  /// ```
178  ///
179  /// \param name Name to bind the loaded enclave under.
180  /// \param loader Configured enclave loader to load from.
182  void *base_address = nullptr);
183 
184  /// Loads an enclave.
185  ///
186  /// Loads a new enclave with custom enclave config settings and binds it to a
187  /// name. The actual work of opening the enclave is delegated to the passed
188  /// loader object.
189  ///
190  /// It is an error to specify a name which is already bound to an enclave.
191  ///
192  /// Example:
193  ///
194  /// ```
195  /// EnclaveConfig config;
196  /// ... // populate config proto.
197  /// LoadEnclave("/EchoEnclave", SgxLoader("echoService.so"), config);
198  /// ```
199  ///
200  /// \param name Name to bind the loaded enclave under.
201  /// \param loader Configured enclave loader to load from.
202  /// \param config Enclave configuration to launch the enclave with.
204  EnclaveConfig config, void *base_address = nullptr);
205 
206  /// Fetches a client to a loaded enclave.
207  ///
208  /// \param name The name of an EnclaveClient that may be registered in the
209  /// EnclaveManager.
210  /// \return A mutable pointer to the EnclaveClient if the name is
211  /// registered. Otherwise returns nullptr.
212  EnclaveClient *GetClient(const std::string &name) const;
213 
214  /// Returns the name of an enclave client.
215  ///
216  /// \param client A pointer to a client that may be registered in the
217  /// EnclaveManager.
218  /// \return The name of an enclave client. If no enclave matches `client` the
219  /// empty string will be returned.
220  const std::string GetName(const EnclaveClient *client) const;
221 
222  /// Destroys an enclave.
223  ///
224  /// Destroys an enclave. This method calls `client's` EnterAndFinalize entry
225  /// point with final_input unless `skip_finalize` is true, then calls
226  /// `client's` DestroyEnclave method, and then removes client's name from the
227  /// EnclaveManager client registry. The manager owns the client, so removing
228  /// it calls client's destructor and frees its memory.
229  ///
230  /// \param client A client attached to the enclave to destroy.
231  /// \param final_input Input to pass the enclave's finalizer.
232  /// \param skip_finalize If true, the enclave is destroyed without invoking
233  /// its Finalize method.
235  bool skip_finalize = false);
236 
237  /// Enters an enclave and takes a snapshot of its memory. This method calls
238  /// `client's` EnterAndTakeSnapshot entry point, with snapshot layout (in
239  /// untrusted memory) stored in |snapshot_layout|.
240  ///
241  /// \param client A client attached to the enclave to enter.
242  /// \param snapshot_layout The snapshot layout in untrusted memory to be
243  /// filled up by snapshotting.
246 
247  /// Enters an enclave and restores it from an untrusted snapshot. This method
248  /// calls `client's` EnterAndRestore entry point, with snapshot layout (in
249  /// untrusted memory) passed in |snapshot_layout|.
250  ///
251  /// \param client A client attached to the enclave to enter.
252  /// \param snapshot_layout The snapshot layout in untrusted memory used to
253  /// restore enclave states.
256 
257  /// Fetches the shared resource manager object.
258  ///
259  /// \return The SharedResourceManager instance.
261  return &shared_resource_manager_;
262  }
263 
264  /// Fetches the shared resource manager object.
265  ///
266  /// \return The SharedResourceManager instance.
268  return &shared_resource_manager_;
269  }
270 
271  /// Get the loader of an enclave. This should only be used during fork in
272  /// order to load an enclave with the same loader as the parent.
273  EnclaveLoader *GetLoaderFromClient(EnclaveClient *client);
274 
275  private:
276  EnclaveManager() EXCLUSIVE_LOCKS_REQUIRED(mu_);
277  EnclaveManager(EnclaveManager const &) = delete;
278  EnclaveManager &operator=(EnclaveManager const &) = delete;
279 
280  // Retrieves and returns a HostConfig proto as specified by the
281  // EnclaveManagerOptions which the EnclaveManager was configured when its
282  // sngleton instance was created.
283  HostConfig GetHostConfig() EXCLUSIVE_LOCKS_REQUIRED(mu_);
284 
285  // Loads a new enclave with custom enclave config settings and binds it to a
286  // name. The actual work of opening the enclave is delegated to the passed
287  // loader object.
288  Status LoadEnclaveInternal(const std::string &name, const EnclaveLoader &loader,
289  const EnclaveConfig &config,
290  void *base_address = nullptr);
291 
292  // Deletes an enclave client reference that points to an enclave that no
293  // longer exists. This should only happen during fork.
294  void RemoveEnclaveReference(const std::string &name);
295 
296  // Create a thread to periodically update logic.
297  void SpawnWorkerThread();
298 
299  // Top level loop run by the background worker thread.
300  void WorkerLoop();
301 
302  // Execute a single iteration of the work loop.
303  void Tick();
304 
305  // Manager object for untrusted resources shared with enclaves.
306  SharedResourceManager shared_resource_manager_;
307 
308  // Value synchronized to CLOCK_MONOTONIC by the worker loop.
309  std::atomic<int64_t> clock_monotonic_;
310 
311  // Value synchronized to CLOCK_REALTIME by the worker loop.
312  std::atomic<int64_t> clock_realtime_;
313 
314  absl::flat_hash_map<std::string, std::unique_ptr<EnclaveClient>> client_by_name_;
315  absl::flat_hash_map<const EnclaveClient *, std::string> name_by_client_;
316 
317  absl::flat_hash_map<const EnclaveClient *, std::unique_ptr<EnclaveLoader>>
318  loader_by_client_;
319 
320  // A part of the configuration for enclaves launched by the enclave manager
321  // comes from the Asylo daemon. This member caches such configuration.
322  HostConfig host_config_;
323 
324  // Mutex guarding the static state of this class.
325  static absl::Mutex mu_;
326 
327  // Indication whether the class has been configured so that an instance could
328  // be created.
329  static bool configured_ GUARDED_BY(mu_);
330 
331  // Configuration options for this class.
332  static EnclaveManagerOptions *options_ GUARDED_BY(mu_);
333 
334  // Singleton instance of this class.
335  static EnclaveManager *instance_ GUARDED_BY(mu_);
336 };
337 
338 /// An abstract enclave loader.
339 ///
340 /// Host applications must load an enclave before using it. This is accomplished
341 /// via an architecture specific implementation of the EnclaveLoader interface.
343  public:
344  virtual ~EnclaveLoader() = default;
345 
346  protected:
347  // Only allow the enclave loading via the manager object.
348  friend class EnclaveManager;
349 
350  // Loads an enclave, returning a pointer to a client on success and a non-ok
351  // status on failure.
353  const std::string &name) const {
355  return LoadEnclave(name, nullptr, config);
356  }
357 
358  // Loads an enclave at the specified address, returning a pointer to a client
359  // on success and a non-ok status on failure.
361  const std::string &name, void *base_address,
362  const EnclaveConfig &config) const = 0;
363 
364  // Gets a copy of the loader that loaded a previous enclave. This is only used
365  // by fork to load a child enclave with the same loader as the parent.
366  virtual StatusOr<std::unique_ptr<EnclaveLoader>> Copy() const = 0;
367 };
368 
369 // Stores the mapping between signals and the enclave with a handler installed
370 // for that signal.
371 class EnclaveSignalDispatcher {
372  public:
373  static EnclaveSignalDispatcher *GetInstance();
374 
375  // Associates a signal with an enclave which registers a handler for it.
376  // It's not supported for multiple enclaves to register the same signal. In
377  // that case, the latter will overwrite the former.
378  //
379  // Returns the enclave client that previous registered |signum|, or nullptr if
380  // no enclave has registered |signum| yet.
382  LOCKS_EXCLUDED(signal_enclave_map_lock_);
383 
384  // Gets the enclave that registered a handler for |signum|.
386  LOCKS_EXCLUDED(signal_enclave_map_lock_);
387 
388  // Deregisters all the signals registered by |client|.
390  LOCKS_EXCLUDED(signal_enclave_map_lock_);
391 
392  // Looks for the enclave client that registered |signum|, and calls
393  // EnterAndHandleSignal() with that enclave client. |signum|, |info| and
394  // |ucontext| are passed into the enclave.
396  void *ucontext);
397 
398  private:
399  EnclaveSignalDispatcher() = default; // Private to enforce singleton.
400  EnclaveSignalDispatcher(EnclaveSignalDispatcher const &) = delete;
401  void operator=(EnclaveSignalDispatcher const &) = delete;
402 
403  // Mapping of signal number to the enclave client that registered it.
404  absl::flat_hash_map<int, EnclaveClient *> signal_to_client_map_
405  GUARDED_BY(signal_enclave_map_lock_);
406 
407  // A mutex that guards signal_to_client_map_ and client_to_signal_map_.
408  mutable absl::Mutex signal_enclave_map_lock_;
409 };
410 
411 } // namespace asylo
412 
413 #endif // ASYLO_PLATFORM_CORE_ENCLAVE_MANAGER_H_
Status LoadEnclave(const std::string &name, const EnclaveLoader &loader, EnclaveConfig config, void *base_address=nullptr)
Loads an enclave.
Status LoadEnclave(const std::string &name, const EnclaveLoader &loader, void *base_address=nullptr)
Loads an enclave.
Status EnterEnclaveAndHandleSignal(int signum, siginfo_t *info, void *ucontext)
virtual StatusOr< std::unique_ptr< EnclaveLoader > > Copy() const =0
const std::string GetName(const EnclaveClient *client) const
Returns the name of an enclave client.
ConfigServerConnectionAttributes(std::string address, absl::Duration timeout)
Definition: enclave_manager.h:64
static StatusOr< EnclaveManager * > Instance()
Fetches the EnclaveManager singleton instance.
Configuration server connection attributes.
Definition: enclave_manager.h:63
EnclaveManagerOptions & set_host_config(HostConfig config)
Sets the HostConfig proto within this object.
bool holds_host_config() const
Returns true if a HostConfig instance is embedded in this object.
StatusOr< absl::Duration > get_config_server_connection_timeout() const
Returns the configuration server connection timeout.
StatusOr< EnclaveClient * > GetClientForSignal(int signum) const LOCKS_EXCLUDED(signal_enclave_map_lock_)
StatusOr< std::string > get_config_server_address() const
Returns the address of the configuration server.
static Status Configure(const EnclaveManagerOptions &options)
Configures the enclave manager.
virtual ~EnclaveLoader()=default
static EnclaveSignalDispatcher * GetInstance()
SharedResourceManager * shared_resources()
Fetches the shared resource manager object.
Definition: enclave_manager.h:260
Status EnterAndTakeSnapshot(EnclaveClient *client, SnapshotLayout *snapshot_layout)
Enters an enclave and takes a snapshot of its memory.
EnclaveManagerOptions & set_config_server_connection_attributes(std::string address, absl::Duration timeout)
Configures a connection to the config server.
const EnclaveClient * RegisterSignal(int signum, EnclaveClient *client) LOCKS_EXCLUDED(signal_enclave_map_lock_)
absl::Duration connection_timeout
Definition: enclave_manager.h:69
Enclave Manager configuration.
Definition: enclave_manager.h:45
const SharedResourceManager * shared_resources() const
Fetches the shared resource manager object.
Definition: enclave_manager.h:267
Status DestroyEnclave(EnclaveClient *client, const EnclaveFinal &final_input, bool skip_finalize=false)
Destroys an enclave.
Status EnterAndRestore(EnclaveClient *client, const SnapshotLayout &snapshot_layout)
Enters an enclave and restores it from an untrusted snapshot.
EnclaveManagerOptions()
Constructs a default EnclaveManagerOptions object.
Definition: aes_gcm_siv.h:37
Status DeregisterAllSignalsForClient(EnclaveClient *client) LOCKS_EXCLUDED(signal_enclave_map_lock_)
EnclaveLoader * GetLoaderFromClient(EnclaveClient *client)
Get the loader of an enclave.
EnclaveClient * GetClient(const std::string &name) const
Fetches a client to a loaded enclave.
StatusOr< HostConfig > get_host_config() const
Returns the embedded HostConfig object.
std::string server_address
Definition: enclave_manager.h:68