Asylo
trusted_primitives.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_PRIMITIVES_TRUSTED_PRIMITIVES_H_
20 #define ASYLO_PLATFORM_PRIMITIVES_TRUSTED_PRIMITIVES_H_
21 
22 #include <cstddef>
23 #include <cstdint>
24 
25 #include "asylo/platform/primitives/extent.h"
26 #include "asylo/platform/primitives/primitive_status.h"
27 #include "asylo/platform/primitives/primitives.h"
28 #include "asylo/platform/primitives/util/message.h"
29 #include "asylo/util/asylo_macros.h"
30 
31 namespace asylo {
32 namespace primitives {
33 
34 struct EntryHandler;
35 
36 /// \class TrustedPrimitives trusted_primitives.h @trusted_primitives
37 /// Trusted runtime primitive interface.
38 ///
39 /// This class declares the primitive API available to trusted application code
40 /// running inside an Asylo enclave. Each Asylo backend is responsible for
41 /// providing an implementation of this interface.
43  public:
44  /// Aborts the enclave on a best-effort basis. Since it may not be possible to
45  /// destroy the enclave completely without the cooperation of untrusted code,
46  /// the implementation should clearly document the behavior of aborting on a
47  /// particular backend.
48  ///
49  /// \param message A message for the abort method to print or log.
50  /// May be nullptr.
51  static void BestEffortAbort(const char *message);
52 
53  /// Writes a message to a stream suitable for debug output. This API is
54  /// intended for low-level debugging and should:
55  ///
56  /// * Take as few dependencies as possible.
57  /// * Make as few assumptions about the runtime as possible.
58  /// * Flush as immediately as possible.
59  /// * Not assume that the I/O or logging subsystems are usable.
60  ///
61  /// \param message The message to output.
62  static void DebugPuts(const char *message);
63 
64  /// A predicate that decides if a region of memory is internal to the enclave.
65  ///
66  /// \param addr A pointer to the start of the memory region.
67  /// \param size The number of bytes that will be tested for enclave residence.
68  /// \returns true if every byte of a `size` byte range at an address `addr`
69  /// falls inside the TCB and may not be modified by untrusted code.
70  static bool IsInsideEnclave(const void *addr,
71  size_t size) ASYLO_MUST_USE_RESULT;
72 
73  /// A predicate that decides if a region of memory is external to the enclave.
74  ///
75  /// \param addr A pointer to the start of the memory region.
76  /// \param size The number of bytes that will be tested for enclave
77  /// non-residence.
78  /// \returns true if every byte of a `size` byte range at an address `addr`
79  /// falls outside the TCB and may be modified by untrusted code.
80  static bool IsOutsideEnclave(const void *addr,
81  size_t size) ASYLO_MUST_USE_RESULT;
82 
83  /// Allocates `size` bytes of untrusted local memory.
84  ///
85  /// The allocated memory must later be freed by calling UntrustedLocalFree or
86  /// by free call in local untrusted code. Local untrusted memory may not be
87  /// addressable by the enclave directly, as this is a backend-specific
88  /// assumption. Untrusted memory contents are not secure. One must assume that
89  /// an attacker can read and write it. Note that untrusted local memory is not
90  /// the same as host memory, and that untrusted local memory is not expected
91  /// to be addressable from the untrusted application. If a backend permits
92  /// directly addressing untrusted memory, portable applications should not use
93  /// that capability. Only local primitives should use direct addressibility.
94  ///
95  /// \param size The number of bytes to allocate.
96  /// \returns A pointer to the allocated memory.
97  static void *UntrustedLocalAlloc(size_t size) noexcept ASYLO_MUST_USE_RESULT;
98 
99  /// Calls untrusted local counterpart to free memory allocated by malloc in
100  /// local untrusted code or by calling UntrustedLocalAlloc.
101  ///
102  /// \param ptr The pointer to untrusted memory to free.
103  static void UntrustedLocalFree(void *ptr) noexcept;
104 
105  /// Copies `size` bytes of memory from `src` to `dest`.
106  ///
107  /// Backends seeking to access or copy untrusted local memory should not
108  /// assume direct memory access, and instead use this function to copy to/from
109  /// the untrusted local memory.
110  ///
111  /// \param dest The trusted or untrusted local destination memory.
112  /// \param src The trusted or untrusted local source memory.
113  /// \param size The number of bytes to be copied.
114  /// \return The pointer to destination buffer where memory got copied.
115  static void *UntrustedLocalMemcpy(void *dest, const void *src,
116  size_t size) noexcept;
117 
118  /// Exits the enclave synchronously at an entry point to untrusted code
119  /// designated by `untrusted_selector`. Inputs must be pushed into `input`.
120  /// Results are returned in `output`. All extent data in `input` and `output`
121  /// are owned by them and located in trusted memory.
122  ///
123  /// \param untrusted_selector The identification number to select a registered
124  /// handler in the untrusted space.
125  /// \param input A pointer to a MessageWriter, into which all call inputs must
126  /// be pushed.
127  /// \param output A pointer to a MessageReader from which to read outputs from
128  /// the call.
129  /// \returns A status for the call action, since the call itself may fail.
133 
134  /// Registers a callback as the handler routine for an enclave entry point
135  /// trusted_selector.
136  ///
137  /// \param trusted_selector A unique-to-this-enclave identification number
138  /// which will be used to select the given EntryHandler.
139  /// \param handler The representation of a callable enclave function.
140  /// \returns an error status if a handler has already been registered for
141  /// `trusted_selector` or if an invalid selector value is passed.
143  const EntryHandler &handler)
145 
146  /// Creates a new thread.
147  ///
148  /// Depending on the backend, the implementation might or might not need to
149  /// exit the enclave for thread creation. The created thread is responsible
150  /// for making a callback for querying the thread manager to register itself
151  /// and then execute the callback function provided by the thread manager.
152  ///
153  /// \returns 0 on success.
154  static int CreateThread();
155 };
156 
157 /// \class EntryHandler trusted_primitives.h @trusted_primitives
158 /// Callback structure for dispatching messages passed to the enclave.
159 ///
160 /// Each EntryHandler represents a call to inside the enclave, and will be
161 /// registered with TrustedPrimitives::RegisterEntryHandler.
162 struct EntryHandler {
163  /// The type of all handler callbacks takes a type-erased context, a
164  /// MessageReader from which to consume inputs, and a MessageWriter in which
165  /// to write all return values.
166  using Callback = PrimitiveStatus (*)(void *context, MessageReader *in,
168 
169  /// Constructs a null handler.
170  EntryHandler() : EntryHandler(/*callback=*/nullptr, /*context=*/nullptr) {}
171 
172  /// Constructs an entry handler with a callback and null context.
173  ///
174  /// \param callback The callback this handler uses.
175  explicit EntryHandler(Callback callback)
176  : EntryHandler(callback, /*context=*/nullptr) {}
177 
178  /// Initializes an entry handler with a callback and a context pointer.
179  ///
180  /// \param callback The callback this handler uses.
181  /// \param context A type-erased non-owned pointer that is passed to the
182  /// callback when called. Since an EntryHandler is registered in an
183  /// enclave-global context, the object should live as long as the enclave.
184  EntryHandler(Callback callback, void *context)
185  : callback(callback), context(context) {}
186 
187  /// A predicate for whether the callback is initialized.
188  ///
189  /// \returns true if this handler is uninitialized.
190  bool IsNull() const { return callback == nullptr; }
191 
192  /// Implicit bool conversion for null checks.
193  operator bool() const { return IsNull(); }
194 
195  /// Callback function to invoke for this entry.
197 
198  /// Uninterpreted data passed by the runtime to invocations of the handler.
199  void *context;
200 };
201 
202 /// \class UntrustedDeleter trusted_primitives.h @trusted_primitives
203 /// Deleter for untrusted memory for use with std::unique_ptr. Calls
204 /// UntrustedLocalFree() internally.
206  inline void operator()(void *ptr) const {
208  }
209 };
210 
211 /// An alias for unique_ptr that frees data with UntrustedDeleter.
212 template <typename T>
214 
215 } // namespace primitives
216 } // namespace asylo
217 
218 #endif // ASYLO_PLATFORM_PRIMITIVES_TRUSTED_PRIMITIVES_H_
void * context
Uninterpreted data passed by the runtime to invocations of the handler.
Definition: trusted_primitives.h:199
static bool IsInsideEnclave(const void *addr, size_t size) ASYLO_MUST_USE_RESULT
A predicate that decides if a region of memory is internal to the enclave.
bool IsNull() const
A predicate for whether the callback is initialized.
Definition: trusted_primitives.h:190
Trusted runtime primitive interface.
Definition: trusted_primitives.h:42
static void DebugPuts(const char *message)
Writes a message to a stream suitable for debug output.
void operator()(void *ptr) const
Definition: trusted_primitives.h:206
operator bool() const
Implicit bool conversion for null checks.
Definition: trusted_primitives.h:193
Deleter for untrusted memory for use with std::unique_ptr.
Definition: trusted_primitives.h:205
static bool IsOutsideEnclave(const void *addr, size_t size) ASYLO_MUST_USE_RESULT
A predicate that decides if a region of memory is external to the enclave.
ABSL_CONST_INIT const char kStatusMoveAssignmentMsg[]
EntryHandler(Callback callback, void *context)
Initializes an entry handler with a callback and a context pointer.
Definition: trusted_primitives.h:184
EntryHandler(Callback callback)
Constructs an entry handler with a callback and null context.
Definition: trusted_primitives.h:175
static void UntrustedLocalFree(void *ptr) noexcept
Calls untrusted local counterpart to free memory allocated by malloc in local untrusted code or by ca...
static void * UntrustedLocalMemcpy(void *dest, const void *src, size_t size) noexcept
Copies size bytes of memory from src to dest.
static void BestEffortAbort(const char *message)
Aborts the enclave on a best-effort basis.
static void * UntrustedLocalAlloc(size_t size) noexcept ASYLO_MUST_USE_RESULT
Allocates size bytes of untrusted local memory.
static int CreateThread()
Creates a new thread.
EntryHandler()
Constructs a null handler.
Definition: trusted_primitives.h:170
Callback callback
Callback function to invoke for this entry.
Definition: trusted_primitives.h:196
Callback structure for dispatching messages passed to the enclave.
Definition: trusted_primitives.h:162
static PrimitiveStatus UntrustedCall(uint64_t untrusted_selector, MessageWriter *input, MessageReader *output) ASYLO_MUST_USE_RESULT
Exits the enclave synchronously at an entry point to untrusted code designated by untrusted_selector...
static PrimitiveStatus RegisterEntryHandler(uint64_t trusted_selector, const EntryHandler &handler) ASYLO_MUST_USE_RESULT
Registers a callback as the handler routine for an enclave entry point trusted_selector.
Definition: extent.h:29