• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef SANDBOXED_API_SANDBOX_H_
16 #define SANDBOXED_API_SANDBOX_H_
17 
18 #include <cstddef>
19 #include <cstdint>
20 #include <ctime>
21 #include <initializer_list>
22 #include <memory>
23 #include <string>
24 #include <vector>
25 
26 #include "sandboxed_api/file_toc.h"
27 #include "absl/base/attributes.h"
28 #include "absl/base/macros.h"
29 #include "absl/base/thread_annotations.h"
30 #include "absl/log/globals.h"
31 #include "absl/log/log.h"
32 #include "absl/status/status.h"
33 #include "absl/status/statusor.h"
34 #include "absl/strings/str_cat.h"
35 #include "absl/synchronization/mutex.h"
36 #include "absl/time/time.h"
37 #include "absl/types/span.h"
38 #include "sandboxed_api/config.h"
39 #include "sandboxed_api/rpcchannel.h"
40 #include "sandboxed_api/sandbox2/client.h"
41 #include "sandboxed_api/sandbox2/comms.h"
42 #include "sandboxed_api/sandbox2/policy.h"
43 #include "sandboxed_api/sandbox2/policybuilder.h"
44 #include "sandboxed_api/sandbox2/sandbox2.h"
45 #include "sandboxed_api/vars.h"
46 
47 namespace sapi {
48 
49 // Context holding, potentially shared, fork client.
50 class ForkClientContext {
51  public:
ForkClientContext(const FileToc * embed_lib_toc)52   explicit ForkClientContext(const FileToc* embed_lib_toc)
53       : embed_lib_toc_(embed_lib_toc) {}
54 
55  private:
56   friend class Sandbox;
57   const FileToc* embed_lib_toc_;
58   absl::Mutex mu_;
59   std::unique_ptr<sandbox2::ForkClient> client_ ABSL_GUARDED_BY(mu_);
60   std::unique_ptr<sandbox2::Executor> executor_ ABSL_GUARDED_BY(mu_);
61 };
62 
63 // The Sandbox class represents the sandboxed library. It provides users with
64 // means to communicate with it (make function calls, transfer memory).
65 class Sandbox {
66  public:
Sandbox(ForkClientContext * fork_client_context ABSL_ATTRIBUTE_LIFETIME_BOUND)67   explicit Sandbox(
68       ForkClientContext* fork_client_context ABSL_ATTRIBUTE_LIFETIME_BOUND)
69       : fork_client_context_(fork_client_context) {}
70 
71   explicit Sandbox(const FileToc* embed_lib_toc ABSL_ATTRIBUTE_LIFETIME_BOUND);
72 
73   explicit Sandbox(std::nullptr_t);
74 
75   Sandbox(const Sandbox&) = delete;
76   Sandbox& operator=(const Sandbox&) = delete;
77 
78   virtual ~Sandbox();
79 
80   void SetForkClientContext(ForkClientContext* fork_client_context);
81 
82   // Initializes a new sandboxing session.
83   absl::Status Init(bool use_unotify_monitor = false);
84 
85   // Returns whether the current sandboxing session is active.
86   bool is_active() const;
87 
88   // Terminates the current sandboxing session (if it exists).
89   void Terminate(bool attempt_graceful_exit = true);
90 
91   // Restarts the sandbox.
Restart(bool attempt_graceful_exit)92   absl::Status Restart(bool attempt_graceful_exit) {
93     Terminate(attempt_graceful_exit);
94     return Init();
95   }
96 
comms()97   sandbox2::Comms* comms() const { return comms_; }
98 
rpc_channel()99   RPCChannel* rpc_channel() const { return rpc_channel_.get(); }
100 
pid()101   int pid() const { return pid_; }
102 
103   // Synchronizes the underlying memory for the pointer before the call.
104   absl::Status SynchronizePtrBefore(v::Callable* ptr);
105 
106   // Synchronizes the underlying memory for pointer after the call.
107   absl::Status SynchronizePtrAfter(v::Callable* ptr) const;
108 
109   // Makes a call to the sandboxee.
110   template <typename... Args>
Call(const std::string & func,v::Callable * ret,Args &&...args)111   absl::Status Call(const std::string& func, v::Callable* ret, Args&&... args) {
112     static_assert(sizeof...(Args) <= FuncCall::kArgsMax,
113                   "Too many arguments to sapi::Sandbox::Call()");
114     return Call(func, ret, {std::forward<Args>(args)...});
115   }
116   virtual absl::Status Call(const std::string& func, v::Callable* ret,
117                             std::initializer_list<v::Callable*> args);
118 
119   // Allocates memory in the sandboxee, automatic_free indicates whether the
120   // memory should be freed on the remote side when the 'var' goes out of scope.
121   absl::Status Allocate(v::Var* var, bool automatic_free = false);
122 
123   // Frees memory in the sandboxee.
124   absl::Status Free(v::Var* var);
125 
126   // Finds the address of a symbol in the sandboxee.
127   absl::Status Symbol(const char* symname, void** addr);
128 
129   // Transfers memory to the sandboxee's address space from the hostcode.
130   // Returns the status of the operation. Requires a v::Var object to be set up
131   // with a suitable memory buffer allocated in the hostcode.
132   //
133   // Example Usage:
134   //    std::string buffer(size_of_memory_in_sandboxee, ' ');
135   //    sapi::v::Array<uint8_t> sapi_buffer(
136   //       reinterpret_cast<uint8_t*>(buffer.data()), buffer.size());
137   //    SAPI_RETURN_IF_ERROR(sandbox.Allocate(&sapi_buffer));
138   //    SAPI_RETURN_IF_ERROR(sandbox.TransferFromSandboxee(&sapi_buffer));
139   absl::Status TransferToSandboxee(v::Var* var);
140 
141   // Transfers memory from the sandboxee's address space to the hostcode.
142   // Returns the status of the operation. Requires a v::Var object to be set up
143   // suitable memory buffer allocated in the hostcode. This call
144   // does not alter the memory in the sandboxee. It is therefore safe to
145   // const_cast `addr_of_memory_in_sandboxee` if necessary.
146   //
147   // Example Usage:
148   //    std::string buffer(size_of_memory_in_sandboxee, ' ');
149   //    sapi::v::Array<uint8_t> sapi_buffer(
150   //       reinterpret_cast<uint8_t*>(buffer.data()), buffer.size());
151   //    sapi_buffer.SetRemote(addr_of_memory_in_sandboxee);
152   //    SAPI_RETURN_IF_ERROR(sandbox.TransferFromSandboxee(&sapi_buffer));
153   absl::Status TransferFromSandboxee(v::Var* var);
154 
155   // Allocates and transfers a buffer to the sandboxee's address space from the
156   // hostcode. Returns a status on failure, or a unique_ptr to
157   // sapi::v::Array<const uint8_t> on success.
158   absl::StatusOr<std::unique_ptr<sapi::v::Array<const uint8_t>>>
159   AllocateAndTransferToSandboxee(absl::Span<const uint8_t> buffer);
160 
161   absl::StatusOr<std::string> GetCString(const v::RemotePtr& str,
162                                          size_t max_length = 10ULL
163                                                              << 20 /* 10 MiB*/
164   );
165 
166   // Waits until the sandbox terminated and returns the result.
167   const sandbox2::Result& AwaitResult();
result()168   const sandbox2::Result& result() const { return result_; }
169 
170   absl::Status SetWallTimeLimit(absl::Duration limit) const;
171 
172  protected:
173 
174   // Gets extra arguments to be passed to the sandboxee.
GetArgs(std::vector<std::string> * args)175   virtual void GetArgs(std::vector<std::string>* args) const {
176     args->push_back(absl::StrCat("--stderrthreshold=",
177                                  static_cast<int>(absl::StderrThreshold())));
178   }
179 
180   // Gets the environment variables passed to the sandboxee.
GetEnvs(std::vector<std::string> * envs)181   virtual void GetEnvs(std::vector<std::string>* envs) const {
182     // Do nothing by default.
183   }
184 
185  private:
186   // Returns the sandbox policy. Subclasses can modify the default policy
187   // builder, or return a completely new policy.
188   virtual std::unique_ptr<sandbox2::Policy> ModifyPolicy(
189       sandbox2::PolicyBuilder* builder);
190 
191   // Path of the sandboxee:
192   //  - relative to runfiles directory: ::sapi::GetDataDependencyFilePath()
193   //    will be applied to it,
194   //  - absolute: will be used as is.
GetLibPath()195   virtual std::string GetLibPath() const { return ""; }
196 
197   // Modifies the Executor object if needed.
ModifyExecutor(sandbox2::Executor * executor)198   virtual void ModifyExecutor(sandbox2::Executor* executor) {
199     // Do nothing by default.
200   }
201 
202   // Provides a custom notifier for sandboxee events. May return nullptr.
CreateNotifier()203   virtual std::unique_ptr<sandbox2::Notify> CreateNotifier() { return nullptr; }
204 
205   // The main sandbox2::Sandbox2 object.
206   std::unique_ptr<sandbox2::Sandbox2> s2_;
207   // Marks whether Sandbox2 result was already fetched.
208   // We cannot just delete s2_ as Terminate might be called from another thread
209   // and comms object can be still in use then.
210   bool s2_awaited_ = false;
211 
212   // Result of the most recent sandbox execution
213   sandbox2::Result result_;
214 
215   // Comms with the sandboxee.
216   sandbox2::Comms* comms_ = nullptr;
217   // RPCChannel object.
218   std::unique_ptr<RPCChannel> rpc_channel_;
219   // The main pid of the sandboxee.
220   pid_t pid_ = 0;
221 
222   // FileTOC with the embedded library, takes precedence over GetLibPath if
223   // present (not nullptr).
224   const FileToc* embed_lib_toc_;
225 
226   ForkClientContext* fork_client_context_;
227   // Set if the object owns the client context instance.
228   std::unique_ptr<ForkClientContext> owned_fork_client_context_;
229 };
230 
231 }  // namespace sapi
232 
233 #endif  // SANDBOXED_API_SANDBOX_H_
234