1*ec63e07aSXin Li // Copyright 2019 Google LLC 2*ec63e07aSXin Li // 3*ec63e07aSXin Li // Licensed under the Apache License, Version 2.0 (the "License"); 4*ec63e07aSXin Li // you may not use this file except in compliance with the License. 5*ec63e07aSXin Li // You may obtain a copy of the License at 6*ec63e07aSXin Li // 7*ec63e07aSXin Li // https://www.apache.org/licenses/LICENSE-2.0 8*ec63e07aSXin Li // 9*ec63e07aSXin Li // Unless required by applicable law or agreed to in writing, software 10*ec63e07aSXin Li // distributed under the License is distributed on an "AS IS" BASIS, 11*ec63e07aSXin Li // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*ec63e07aSXin Li // See the License for the specific language governing permissions and 13*ec63e07aSXin Li // limitations under the License. 14*ec63e07aSXin Li 15*ec63e07aSXin Li #ifndef SANDBOXED_API_TRANSACTION_H_ 16*ec63e07aSXin Li #define SANDBOXED_API_TRANSACTION_H_ 17*ec63e07aSXin Li 18*ec63e07aSXin Li #include <ctime> 19*ec63e07aSXin Li #include <functional> 20*ec63e07aSXin Li #include <memory> 21*ec63e07aSXin Li #include <utility> 22*ec63e07aSXin Li 23*ec63e07aSXin Li #include "absl/base/attributes.h" 24*ec63e07aSXin Li #include "absl/log/check.h" 25*ec63e07aSXin Li #include "absl/log/log.h" 26*ec63e07aSXin Li #include "absl/status/status.h" 27*ec63e07aSXin Li #include "absl/strings/str_cat.h" 28*ec63e07aSXin Li #include "absl/time/time.h" 29*ec63e07aSXin Li #include "sandboxed_api/sandbox.h" 30*ec63e07aSXin Li 31*ec63e07aSXin Li #define TRANSACTION_FAIL_IF_NOT(x, y) \ 32*ec63e07aSXin Li if (!(x)) { \ 33*ec63e07aSXin Li return absl::FailedPreconditionError(y); \ 34*ec63e07aSXin Li } 35*ec63e07aSXin Li 36*ec63e07aSXin Li namespace sapi { 37*ec63e07aSXin Li 38*ec63e07aSXin Li // The Transaction class allows to perform operations in the sandboxee, 39*ec63e07aSXin Li // repeating them if necessary (if the sandboxing, or IPC failed). 40*ec63e07aSXin Li // 41*ec63e07aSXin Li // We provide two different implementations of transactions: 42*ec63e07aSXin Li // 1) Single function transactions - They consist out of a single function 43*ec63e07aSXin Li // Main() that will be invoked as body of the transaction. For this, 44*ec63e07aSXin Li // inherit from the Transaction class and implement Main(). 45*ec63e07aSXin Li // 2) Function pointer based transactions - The BasicTransaction class accepts 46*ec63e07aSXin Li // functions that take a sandbox object (along with arbitrary other 47*ec63e07aSXin Li // parameters) and return a status. This way no custom implementation of a 48*ec63e07aSXin Li // Transaction class is required. 49*ec63e07aSXin Li // 50*ec63e07aSXin Li // Additionally both methods support Init() and Finish() functions. 51*ec63e07aSXin Li // Init() will be called after the sandbox has been set up. 52*ec63e07aSXin Li // Finish() will be called when the transaction object goes out of scope. 53*ec63e07aSXin Li class TransactionBase { 54*ec63e07aSXin Li public: 55*ec63e07aSXin Li TransactionBase(const TransactionBase&) = delete; 56*ec63e07aSXin Li TransactionBase& operator=(const TransactionBase&) = delete; 57*ec63e07aSXin Li 58*ec63e07aSXin Li virtual ~TransactionBase(); 59*ec63e07aSXin Li 60*ec63e07aSXin Li // Getter/Setter for retry_count_. retry_count()61*ec63e07aSXin Li int retry_count() const { return retry_count_; } set_retry_count(int value)62*ec63e07aSXin Li void set_retry_count(int value) { 63*ec63e07aSXin Li CHECK_GE(value, 0); 64*ec63e07aSXin Li retry_count_ = value; 65*ec63e07aSXin Li } 66*ec63e07aSXin Li 67*ec63e07aSXin Li // Getter/Setter for time_limit_. GetTimeLimit()68*ec63e07aSXin Li time_t GetTimeLimit() const { return time_limit_; } SetTimeLimit(time_t time_limit)69*ec63e07aSXin Li void SetTimeLimit(time_t time_limit) { time_limit_ = time_limit; } SetTimeLimit(absl::Duration time_limit)70*ec63e07aSXin Li void SetTimeLimit(absl::Duration time_limit) { 71*ec63e07aSXin Li time_limit_ = absl::ToTimeT(absl::UnixEpoch() + time_limit); 72*ec63e07aSXin Li } 73*ec63e07aSXin Li IsInitialized()74*ec63e07aSXin Li bool IsInitialized() const { return initialized_; } 75*ec63e07aSXin Li 76*ec63e07aSXin Li // Getter for the sandbox_. sandbox()77*ec63e07aSXin Li Sandbox* sandbox() const { return sandbox_.get(); } 78*ec63e07aSXin Li 79*ec63e07aSXin Li // Restarts the sandbox. 80*ec63e07aSXin Li // WARNING: This will invalidate any references to the remote process, make 81*ec63e07aSXin Li // sure you don't keep any vars or FDs to the remote process when 82*ec63e07aSXin Li // calling this. Restart()83*ec63e07aSXin Li absl::Status Restart() { 84*ec63e07aSXin Li if (initialized_) { 85*ec63e07aSXin Li Finish().IgnoreError(); 86*ec63e07aSXin Li initialized_ = false; 87*ec63e07aSXin Li } 88*ec63e07aSXin Li return sandbox_->Restart(true); 89*ec63e07aSXin Li } 90*ec63e07aSXin Li 91*ec63e07aSXin Li protected: TransactionBase(std::unique_ptr<Sandbox> sandbox)92*ec63e07aSXin Li explicit TransactionBase(std::unique_ptr<Sandbox> sandbox) 93*ec63e07aSXin Li : time_limit_(absl::ToTimeT(absl::UnixEpoch() + kDefaultTimeLimit)), 94*ec63e07aSXin Li sandbox_(std::move(sandbox)) {} 95*ec63e07aSXin Li 96*ec63e07aSXin Li // Runs the main (retrying) transaction loop. 97*ec63e07aSXin Li absl::Status RunTransactionLoop(const std::function<absl::Status()>& f); 98*ec63e07aSXin Li 99*ec63e07aSXin Li private: 100*ec63e07aSXin Li // Number of default transaction execution re-tries, in case of failures. 101*ec63e07aSXin Li static constexpr int kDefaultRetryCount = 1; 102*ec63e07aSXin Li 103*ec63e07aSXin Li // Wall-time limit for a single transaction execution (60 s.). 104*ec63e07aSXin Li static constexpr absl::Duration kDefaultTimeLimit = absl::Seconds(60); 105*ec63e07aSXin Li 106*ec63e07aSXin Li // Executes a single function in the sandbox, used in the main transaction 107*ec63e07aSXin Li // loop. Asserts that the sandbox has been set up and Init() was called. 108*ec63e07aSXin Li absl::Status RunTransactionFunctionInSandbox( 109*ec63e07aSXin Li const std::function<absl::Status()>& f); 110*ec63e07aSXin Li 111*ec63e07aSXin Li // Initialization routine of the sandboxed process that will be called only 112*ec63e07aSXin Li // once upon sandboxee startup. Init()113*ec63e07aSXin Li virtual absl::Status Init() { return absl::OkStatus(); } 114*ec63e07aSXin Li 115*ec63e07aSXin Li // End routine for the sandboxee that gets calls when the transaction is 116*ec63e07aSXin Li // destroyed/restarted to clean up resources. Finish()117*ec63e07aSXin Li virtual absl::Status Finish() { return absl::OkStatus(); } 118*ec63e07aSXin Li 119*ec63e07aSXin Li // Number of tries this transaction will be re-executed until it succeeds. 120*ec63e07aSXin Li int retry_count_ = kDefaultRetryCount; 121*ec63e07aSXin Li 122*ec63e07aSXin Li // Time (wall-time) limit for a single Run() call (in seconds). 0 means: no 123*ec63e07aSXin Li // wall-time limit. 124*ec63e07aSXin Li time_t time_limit_; 125*ec63e07aSXin Li 126*ec63e07aSXin Li // Has Init() finished with success? 127*ec63e07aSXin Li bool initialized_ = false; 128*ec63e07aSXin Li 129*ec63e07aSXin Li // The main sapi::Sandbox object. 130*ec63e07aSXin Li std::unique_ptr<Sandbox> sandbox_; 131*ec63e07aSXin Li }; 132*ec63e07aSXin Li 133*ec63e07aSXin Li // Regular style transactions, based on inheriting. 134*ec63e07aSXin Li class Transaction : public TransactionBase { 135*ec63e07aSXin Li public: 136*ec63e07aSXin Li Transaction(const Transaction&) = delete; 137*ec63e07aSXin Li Transaction& operator=(const Transaction&) = delete; 138*ec63e07aSXin Li using TransactionBase::TransactionBase; 139*ec63e07aSXin Li 140*ec63e07aSXin Li // Run the transaction. Run()141*ec63e07aSXin Li absl::Status Run() { 142*ec63e07aSXin Li return RunTransactionLoop([this] { return Main(); }); 143*ec63e07aSXin Li } 144*ec63e07aSXin Li 145*ec63e07aSXin Li protected: 146*ec63e07aSXin Li // The main sandboxee routine: Can be called multiple times. Main()147*ec63e07aSXin Li virtual absl::Status Main() { return absl::OkStatus(); } 148*ec63e07aSXin Li }; 149*ec63e07aSXin Li 150*ec63e07aSXin Li // Callback style transactions: 151*ec63e07aSXin Li class BasicTransaction final : public TransactionBase { 152*ec63e07aSXin Li private: 153*ec63e07aSXin Li using InitFunction = std::function<absl::Status(Sandbox*)>; 154*ec63e07aSXin Li using FinishFunction = std::function<absl::Status(Sandbox*)>; 155*ec63e07aSXin Li 156*ec63e07aSXin Li public: BasicTransaction(std::unique_ptr<Sandbox> sandbox)157*ec63e07aSXin Li explicit BasicTransaction(std::unique_ptr<Sandbox> sandbox) 158*ec63e07aSXin Li : TransactionBase(std::move(sandbox)), 159*ec63e07aSXin Li init_function_(nullptr), 160*ec63e07aSXin Li finish_function_(nullptr) {} 161*ec63e07aSXin Li 162*ec63e07aSXin Li template <typename F> BasicTransaction(std::unique_ptr<Sandbox> sandbox,F init_function)163*ec63e07aSXin Li BasicTransaction(std::unique_ptr<Sandbox> sandbox, F init_function) 164*ec63e07aSXin Li : TransactionBase(std::move(sandbox)), 165*ec63e07aSXin Li init_function_(static_cast<InitFunction>(init_function)), 166*ec63e07aSXin Li finish_function_(nullptr) {} 167*ec63e07aSXin Li 168*ec63e07aSXin Li template <typename F, typename G> BasicTransaction(std::unique_ptr<Sandbox> sandbox,F init_function,G fini_function)169*ec63e07aSXin Li BasicTransaction(std::unique_ptr<Sandbox> sandbox, F init_function, 170*ec63e07aSXin Li G fini_function) 171*ec63e07aSXin Li : TransactionBase(std::move(sandbox)), 172*ec63e07aSXin Li init_function_(static_cast<InitFunction>(init_function)), 173*ec63e07aSXin Li finish_function_(static_cast<FinishFunction>(fini_function)) {} 174*ec63e07aSXin Li 175*ec63e07aSXin Li // Run any function as body of the transaction that matches our expectations 176*ec63e07aSXin Li // (that is: Returning a Status and accepting a Sandbox object as first 177*ec63e07aSXin Li // parameter). 178*ec63e07aSXin Li template <typename T, typename... Args> Run(T func,Args &&...args)179*ec63e07aSXin Li absl::Status Run(T func, Args&&... args) { 180*ec63e07aSXin Li return RunTransactionLoop( 181*ec63e07aSXin Li [&] { return func(sandbox(), std::forward<Args>(args)...); }); 182*ec63e07aSXin Li } 183*ec63e07aSXin Li 184*ec63e07aSXin Li private: 185*ec63e07aSXin Li InitFunction init_function_; 186*ec63e07aSXin Li FinishFunction finish_function_; 187*ec63e07aSXin Li Init()188*ec63e07aSXin Li absl::Status Init() final { 189*ec63e07aSXin Li return init_function_ ? init_function_(sandbox()) : absl::OkStatus(); 190*ec63e07aSXin Li } 191*ec63e07aSXin Li Finish()192*ec63e07aSXin Li absl::Status Finish() final { 193*ec63e07aSXin Li return finish_function_ ? finish_function_(sandbox()) : absl::OkStatus(); 194*ec63e07aSXin Li } 195*ec63e07aSXin Li }; 196*ec63e07aSXin Li 197*ec63e07aSXin Li } // namespace sapi 198*ec63e07aSXin Li 199*ec63e07aSXin Li #endif // SANDBOXED_API_TRANSACTION_H_ 200