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/status/status.h"
31 #include "absl/strings/string_view.h"
32 #include "absl/synchronization/mutex.h"
33 #include "absl/time/time.h"
34 #include "absl/types/variant.h"
35 #include "asylo/enclave.pb.h" // IWYU pragma: export
36 #include "asylo/platform/core/enclave_client.h"
37 #include "asylo/platform/core/enclave_config_util.h"
38 #include "asylo/platform/core/shared_resource_manager.h"
39 #include "asylo/platform/primitives/untrusted_primitives.h"
40 #include "asylo/platform/primitives/util/message.h"
41 #include "asylo/util/status.h" // IWYU pragma: export
42 #include "asylo/util/statusor.h"
43 
44 namespace asylo {
45 class EnclaveLoader;
46 
47 /// Enclave Manager configuration.
48 /// \deprecated EnclaveManager no longer needs to be configured.
50 
51 /// A manager object responsible for creating and managing enclave instances.
52 ///
53 /// EnclaveManager is a singleton class that tracks the status of enclaves
54 /// within a process. Users can get a pointer to the singleton instance by
55 /// calling the static Instance() method.
56 ///
57 /// NOTE: Configuring the EnclaveManager with Configure() is no longer required
58 /// before obtaining a pointer to the singleton instance.
59 ///
60 /// \deprecated Users of this class first supply a configuration using the
61 /// static Configure() method, and then get a pointer to the singleton instance
62 /// as specified by this configuration by calling the static Instance() method.
63 class EnclaveManager {
64  public:
65  /// Fetches the EnclaveManager singleton instance.
66  ///
67  /// \return A StatusOr containing either the global EnclaveManager instance or
68  /// an error describing why it could not be returned.
69  static StatusOr<EnclaveManager *> Instance();
70 
71  /// \deprecated EnclaveManager no longer needs to be configured.
72  /// Configures the enclave manager.
73  ///
74  /// \param options Configuration options as described in
75  /// EnclaveManagerOptions.
77 
78  /// Loads an enclave.
79  ///
80  /// Loads a new enclave utilizing the passed enclave backend loader
81  /// configuration settings. The loaded enclave is bound to the value of field
82  /// `name` set in |load_config|.
83  /// The enclave is initialized with custom enclave config settings if the
84  /// `config` field is set in |load_config|. Else, the enclave is initialized
85  /// with default Asylo enclave config settings.
86  ///
87  /// It is an error to specify a name which is already bound to an enclave.
88  ///
89  /// Example:
90  /// 1) Load an enclave with custom enclave config settings
91  ///
92  /// ```
93  /// EnclaveConfig config;
94  /// ... // populate config proto.
95  ///
96  /// EnclaveLoadConfig load_config;
97  /// load_config.set_name("example");
98  /// load_config.set_config(config);
99  ///
100  /// load_config.SetExtension(example_backend_extension);
101  /// ... // populate Asylo backend extension proto.
102  /// LoadEnclave(load_config);
103  /// ```
104  /// 2) Load an enclave with default enclave config settings
105  ///
106  /// ```
107  /// EnclaveLoadConfig load_config;
108  /// load_config.set_name("example");
109  /// load_config.SetExtension(example_backend_extension);
110  /// ... // populate Asylo backend extension proto.
111  /// LoadEnclave(load_config);
112  /// ```
113  /// \param load_config Backend configuration options to load an enclave
115 
116  /// Loads an enclave.
117  ///
118  /// Loads a new enclave with default enclave config settings and binds it to a
119  /// name. The actual work of opening the enclave is delegated to the passed
120  /// loader object.
121  ///
122  /// It is an error to specify a name which is already bound to an enclave.
123  ///
124  /// Example:
125  /// ```
126  /// LoadEnclave("/EchoEnclave", SgxLoader("echoService.so"));
127  /// ```
128  ///
129  /// \param name Name to bind the loaded enclave under.
130  /// \param loader Configured enclave loader to load from.
131  /// \param base_address Start address to load enclave(optional).
132  /// \param enclave_size The size of the enclave in memory(only needed if
133  /// |base_address| is specified).
134  /// \deprecated Use LoadEnclave(const EnclaveLoadConfig &load_config)
136  void *base_address = nullptr,
137  const size_t enclave_size = 0);
138 
139  /// Loads an enclave.
140  ///
141  /// Loads a new enclave with custom enclave config settings and binds it to a
142  /// name. The actual work of opening the enclave is delegated to the passed
143  /// loader object.
144  ///
145  /// It is an error to specify a name which is already bound to an enclave.
146  ///
147  /// Example:
148  ///
149  /// ```
150  /// EnclaveConfig config;
151  /// ... // populate config proto.
152  /// LoadEnclave("/EchoEnclave", SgxLoader("echoService.so"), config);
153  /// ```
154  ///
155  /// \param name Name to bind the loaded enclave under.
156  /// \param loader Configured enclave loader to load from.
157  /// \param config Enclave configuration to launch the enclave with.
158  /// \param base_address Start address to load enclave(optional).
159  /// \param enclave_size The size of the enclave in memory(only needed if
160  /// |base_address| is specified).
161  /// \deprecated Use LoadEnclave(const EnclaveLoadConfig &load_config)
163  EnclaveConfig config, void *base_address = nullptr,
164  const size_t enclave_size = 0);
165 
166  /// Fetches a client to a loaded enclave.
167  ///
168  /// \param name The name of an EnclaveClient that may be registered in the
169  /// EnclaveManager.
170  /// \return A mutable pointer to the EnclaveClient if the name is
171  /// registered. Otherwise returns nullptr.
173  ABSL_LOCKS_EXCLUDED(client_table_lock_);
174 
175  /// Returns the name of an enclave client.
176  ///
177  /// \param client A pointer to a client that may be registered in the
178  /// EnclaveManager.
179  /// \return The name of an enclave client. If no enclave matches `client` the
180  /// empty string will be returned.
181  const absl::string_view GetName(const EnclaveClient *client) const
182  ABSL_LOCKS_EXCLUDED(client_table_lock_);
183 
184  /// Destroys an enclave.
185  ///
186  /// Destroys an enclave. This method calls `client's` EnterAndFinalize entry
187  /// point with final_input unless `skip_finalize` is true, then calls
188  /// `client's` DestroyEnclave method, and then removes client's name from the
189  /// EnclaveManager client registry. The manager owns the client, so removing
190  /// it calls client's destructor and frees its memory. The client is destroyed
191  /// regardless of whether `client's` EnterAndFinalize method succeeds or
192  /// fails. This method must not be invoked more than once.
193  ///
194  /// \param client A client attached to the enclave to destroy.
195  /// \param final_input Input to pass the enclave's finalizer.
196  /// \param skip_finalize If true, the enclave is destroyed without invoking
197  /// its Finalize method.
198  /// \return The Status returned by the enclave's Finalize method, or an
199  /// OK Status if that was skipped.
201  bool skip_finalize = false)
202  ABSL_LOCKS_EXCLUDED(client_table_lock_);
203 
204  /// Fetches the shared resource manager object.
205  ///
206  /// \return The SharedResourceManager instance.
208  return &shared_resource_manager_;
209  }
210 
211  /// Fetches the shared resource manager object.
212  ///
213  /// \return The SharedResourceManager instance.
215  return &shared_resource_manager_;
216  }
217 
218  /// Get the load config of an enclave. This should only be used during fork
219  /// in order to load an enclave with the same load config as the parent.
221  ABSL_LOCKS_EXCLUDED(client_table_lock_);
222 
223  private:
224  EnclaveManager() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
225  EnclaveManager(EnclaveManager const &) = delete;
226  EnclaveManager &operator=(EnclaveManager const &) = delete;
227 
228  // Loads a fake enclave with custom enclave config settings and binds it to a
229  // name. An enclave loaded using this interface doesn't build on any Asylo
230  // backend technology and is strictly meant to be used for testing only. The
231  // actual work of opening the enclave is delegated to the passed loader
232  // object.
233  Status LoadFakeEnclave(absl::string_view name, const EnclaveLoader &loader,
234  const EnclaveConfig &config,
235  void *base_address = nullptr,
236  const size_t enclave_size = 0)
237  ABSL_LOCKS_EXCLUDED(client_table_lock_);
238 
239  // Deletes an enclave client reference that points to an enclave that no
240  // longer exists. This should only happen during fork.
241  void RemoveEnclaveReference(absl::string_view name)
242  ABSL_LOCKS_EXCLUDED(client_table_lock_);
243 
244  // Manager object for untrusted resources shared with enclaves.
245  SharedResourceManager shared_resource_manager_;
246 
247  // Value synchronized to CLOCK_MONOTONIC by the worker loop.
248  std::atomic<int64_t> clock_monotonic_;
249 
250  // Value synchronized to CLOCK_REALTIME by the worker loop.
251  std::atomic<int64_t> clock_realtime_;
252 
253  // A mutex guarding |client_by_name_|, |name_by_client_|, and
254  // |loader_by_client_| tables.
255  mutable absl::Mutex client_table_lock_;
256 
257  absl::flat_hash_map<std::string, std::unique_ptr<EnclaveClient>>
258  client_by_name_ ABSL_GUARDED_BY(client_table_lock_);
259  absl::flat_hash_map<const EnclaveClient *, std::string> name_by_client_
260  ABSL_GUARDED_BY(client_table_lock_);
261 
262  absl::flat_hash_map<const EnclaveClient *, EnclaveLoadConfig>
263  load_config_by_client_ ABSL_GUARDED_BY(client_table_lock_);
264 
265  // Mutex guarding the static state of this class.
266  static absl::Mutex mu_;
267 
268  // Singleton instance of this class.
269  static EnclaveManager *instance_ ABSL_GUARDED_BY(mu_);
270 };
271 
272 /// An abstract enclave loader.
273 ///
274 /// Host applications must load an enclave before using it. This is accomplished
275 /// via an architecture specific implementation of the EnclaveLoader interface.
277  public:
278  virtual ~EnclaveLoader() = default;
279 
280  protected:
281  // Only allow the enclave loading via the manager object.
282  friend class EnclaveManager;
283 
284  // Loads an enclave, returning a pointer to a client on success and a non-ok
285  // status on failure.
287  absl::string_view name) const {
289  return LoadEnclave(name, /*base_address=*/nullptr, /*enclave_size=*/0,
290  config);
291  }
292 
293  // Loads an enclave at the specified address, returning a pointer to a client
294  // on success and a non-ok status on failure.
297  const EnclaveConfig &config) const {
298  return absl::InternalError(
299  "EnclaveLoader::LoadEnclave not implemented for test enclave");
300  }
301 
302  virtual EnclaveLoadConfig GetEnclaveLoadConfig() const = 0;
303 };
304 
305 // Loads a new enclave with the provided parent enclave name, base virtual
306 // address and enclave size, as part of servicing a trusted fork() call inside
307 // the enclave. Returns a pointer to the primitives Client of the enclave
308 // loaded. The method does not set the current_client of the primitives Client
309 // with the Client it returns. That is the responsibility of the caller, if
310 // desired.
311 // This method currently only supports SGX, since fork is only supported for
312 // local SGX.
314  void *enclave_base_address,
316 
317 } // namespace asylo
318 
319 #endif // ASYLO_PLATFORM_CORE_ENCLAVE_MANAGER_H_
static StatusOr< EnclaveManager * > Instance()
Fetches the EnclaveManager singleton instance.
Status LoadEnclave(absl::string_view name, const EnclaveLoader &loader, EnclaveConfig config, void *base_address=nullptr, const size_t enclave_size=0)
Loads an enclave.
Status LoadEnclave(const EnclaveLoadConfig &load_config)
Loads an enclave.
EnclaveClient * GetClient(absl::string_view name) const ABSL_LOCKS_EXCLUDED(client_table_lock_)
Fetches a client to a loaded enclave.
ABSL_CONST_INIT const char kStatusMoveAssignmentMsg[]
static Status Configure(const EnclaveManagerOptions &options)
virtual ~EnclaveLoader()=default
SharedResourceManager * shared_resources()
Fetches the shared resource manager object.
Definition: enclave_manager.h:207
Status LoadEnclave(absl::string_view name, const EnclaveLoader &loader, void *base_address=nullptr, const size_t enclave_size=0)
Loads an enclave.
Enclave Manager configuration.
Definition: enclave_manager.h:49
const SharedResourceManager * shared_resources() const
Fetches the shared resource manager object.
Definition: enclave_manager.h:214
const absl::string_view GetName(const EnclaveClient *client) const ABSL_LOCKS_EXCLUDED(client_table_lock_)
Returns the name of an enclave client.
EnclaveLoadConfig GetLoadConfigFromClient(EnclaveClient *client) ABSL_LOCKS_EXCLUDED(client_table_lock_)
Get the load config of an enclave.
Status DestroyEnclave(EnclaveClient *client, const EnclaveFinal &final_input, bool skip_finalize=false) ABSL_LOCKS_EXCLUDED(client_table_lock_)
Destroys an enclave.
primitives::Client * LoadEnclaveInChildProcess(absl::string_view enclave_name, void *enclave_base_address, size_t enclave_size)
virtual EnclaveLoadConfig GetEnclaveLoadConfig() const =0