mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
Modernize the transaction API
PiperOrigin-RevId: 295712938 Change-Id: Iaf4c9668bb0b48555679fef822fe424277540d1f
This commit is contained in:
parent
5b1119aa6d
commit
d578b18c22
|
@ -58,7 +58,7 @@ class SumTransaction : public sapi::Transaction {
|
||||||
};
|
};
|
||||||
|
|
||||||
sapi::Status SumTransaction::Main() {
|
sapi::Status SumTransaction::Main() {
|
||||||
SumApi f(GetSandbox());
|
SumApi f(sandbox());
|
||||||
SAPI_ASSIGN_OR_RETURN(int v, f.sum(1000, 337));
|
SAPI_ASSIGN_OR_RETURN(int v, f.sum(1000, 337));
|
||||||
LOG(INFO) << "1000 + 337 = " << v;
|
LOG(INFO) << "1000 + 337 = " << v;
|
||||||
TRANSACTION_FAIL_IF_NOT(v == 1337, "1000 + 337 != 1337");
|
TRANSACTION_FAIL_IF_NOT(v == 1337, "1000 + 337 != 1337");
|
||||||
|
@ -89,10 +89,10 @@ sapi::Status SumTransaction::Main() {
|
||||||
// Gets symbol address and prints its value.
|
// Gets symbol address and prints its value.
|
||||||
int* ssaddr;
|
int* ssaddr;
|
||||||
SAPI_RETURN_IF_ERROR(
|
SAPI_RETURN_IF_ERROR(
|
||||||
GetSandbox()->Symbol("sumsymbol", reinterpret_cast<void**>(&ssaddr)));
|
sandbox()->Symbol("sumsymbol", reinterpret_cast<void**>(&ssaddr)));
|
||||||
sapi::v::Int sumsymbol;
|
sapi::v::Int sumsymbol;
|
||||||
sumsymbol.SetRemote(ssaddr);
|
sumsymbol.SetRemote(ssaddr);
|
||||||
SAPI_RETURN_IF_ERROR(GetSandbox()->TransferFromSandboxee(&sumsymbol));
|
SAPI_RETURN_IF_ERROR(sandbox()->TransferFromSandboxee(&sumsymbol));
|
||||||
LOG(INFO) << "sumsymbol value (exp: 5): " << sumsymbol.GetValue()
|
LOG(INFO) << "sumsymbol value (exp: 5): " << sumsymbol.GetValue()
|
||||||
<< ", address: " << ssaddr;
|
<< ", address: " << ssaddr;
|
||||||
TRANSACTION_FAIL_IF_NOT(sumsymbol.GetValue() == 5,
|
TRANSACTION_FAIL_IF_NOT(sumsymbol.GetValue() == 5,
|
||||||
|
@ -120,7 +120,7 @@ sapi::Status SumTransaction::Main() {
|
||||||
LOG(INFO) << "Print: '" << hwstr << "' via puts()";
|
LOG(INFO) << "Print: '" << hwstr << "' via puts()";
|
||||||
sapi::v::Array<const char> hwarr(hwstr, sizeof(hwstr));
|
sapi::v::Array<const char> hwarr(hwstr, sizeof(hwstr));
|
||||||
sapi::v::Int ret;
|
sapi::v::Int ret;
|
||||||
SAPI_RETURN_IF_ERROR(GetSandbox()->Call("puts", &ret, hwarr.PtrBefore()));
|
SAPI_RETURN_IF_ERROR(sandbox()->Call("puts", &ret, hwarr.PtrBefore()));
|
||||||
TRANSACTION_FAIL_IF_NOT(ret.GetValue() == 15, "puts('Hello World!!!') != 15");
|
TRANSACTION_FAIL_IF_NOT(ret.GetValue() == 15, "puts('Hello World!!!') != 15");
|
||||||
|
|
||||||
sapi::v::Int vp;
|
sapi::v::Int vp;
|
||||||
|
@ -144,13 +144,13 @@ sapi::Status SumTransaction::Main() {
|
||||||
// Fd transfer test.
|
// Fd transfer test.
|
||||||
int fdesc = open("/proc/self/exe", O_RDONLY);
|
int fdesc = open("/proc/self/exe", O_RDONLY);
|
||||||
sapi::v::Fd fd(fdesc);
|
sapi::v::Fd fd(fdesc);
|
||||||
SAPI_RETURN_IF_ERROR(GetSandbox()->TransferToSandboxee(&fd));
|
SAPI_RETURN_IF_ERROR(sandbox()->TransferToSandboxee(&fd));
|
||||||
LOG(INFO) << "remote_fd = " << fd.GetRemoteFd();
|
LOG(INFO) << "remote_fd = " << fd.GetRemoteFd();
|
||||||
TRANSACTION_FAIL_IF_NOT(fd.GetRemoteFd() == 3, "remote_fd != 3");
|
TRANSACTION_FAIL_IF_NOT(fd.GetRemoteFd() == 3, "remote_fd != 3");
|
||||||
|
|
||||||
fdesc = open("/proc/self/comm", O_RDONLY);
|
fdesc = open("/proc/self/comm", O_RDONLY);
|
||||||
sapi::v::Fd fd2(fdesc);
|
sapi::v::Fd fd2(fdesc);
|
||||||
SAPI_RETURN_IF_ERROR(GetSandbox()->TransferToSandboxee(&fd2));
|
SAPI_RETURN_IF_ERROR(sandbox()->TransferToSandboxee(&fd2));
|
||||||
LOG(INFO) << "remote_fd2 = " << fd2.GetRemoteFd();
|
LOG(INFO) << "remote_fd2 = " << fd2.GetRemoteFd();
|
||||||
TRANSACTION_FAIL_IF_NOT(fd2.GetRemoteFd() == 4, "remote_fd2 != 4");
|
TRANSACTION_FAIL_IF_NOT(fd2.GetRemoteFd() == 4, "remote_fd2 != 4");
|
||||||
|
|
||||||
|
@ -158,19 +158,19 @@ sapi::Status SumTransaction::Main() {
|
||||||
char buffer[1024] = {0};
|
char buffer[1024] = {0};
|
||||||
sapi::v::Array<char> buf(buffer, sizeof(buffer));
|
sapi::v::Array<char> buf(buffer, sizeof(buffer));
|
||||||
sapi::v::UInt size(128);
|
sapi::v::UInt size(128);
|
||||||
SAPI_RETURN_IF_ERROR(GetSandbox()->Call("read", &ret, &fd2, buf.PtrBoth(), &size));
|
SAPI_RETURN_IF_ERROR(sandbox()->Call("read", &ret, &fd2, buf.PtrBoth(), &size));
|
||||||
LOG(INFO) << "Read from /proc/self/comm = [" << buffer << "]";
|
LOG(INFO) << "Read from /proc/self/comm = [" << buffer << "]";
|
||||||
|
|
||||||
// Close test.
|
// Close test.
|
||||||
SAPI_RETURN_IF_ERROR(fd2.CloseRemoteFd(GetSandbox()->GetRpcChannel()));
|
SAPI_RETURN_IF_ERROR(fd2.CloseRemoteFd(sandbox()->GetRpcChannel()));
|
||||||
memset(buffer, 0, sizeof(buffer));
|
memset(buffer, 0, sizeof(buffer));
|
||||||
SAPI_RETURN_IF_ERROR(GetSandbox()->Call("read", &ret, &fd2, buf.PtrBoth(), &size));
|
SAPI_RETURN_IF_ERROR(sandbox()->Call("read", &ret, &fd2, buf.PtrBoth(), &size));
|
||||||
LOG(INFO) << "Read from closed /proc/self/comm = [" << buffer << "]";
|
LOG(INFO) << "Read from closed /proc/self/comm = [" << buffer << "]";
|
||||||
|
|
||||||
// Pass fd as function arg example.
|
// Pass fd as function arg example.
|
||||||
fdesc = open("/proc/self/statm", O_RDONLY);
|
fdesc = open("/proc/self/statm", O_RDONLY);
|
||||||
sapi::v::Fd fd3(fdesc);
|
sapi::v::Fd fd3(fdesc);
|
||||||
SAPI_RETURN_IF_ERROR(GetSandbox()->TransferToSandboxee(&fd3));
|
SAPI_RETURN_IF_ERROR(sandbox()->TransferToSandboxee(&fd3));
|
||||||
SAPI_ASSIGN_OR_RETURN(int r2, f.read_int(fd3.GetRemoteFd()));
|
SAPI_ASSIGN_OR_RETURN(int r2, f.read_int(fd3.GetRemoteFd()));
|
||||||
LOG(INFO) << "statm value (should not be 0) = " << r2;
|
LOG(INFO) << "statm value (should not be 0) = " << r2;
|
||||||
|
|
||||||
|
|
|
@ -72,10 +72,10 @@ void BenchmarkSandboxRestartOverhead(benchmark::State& state) {
|
||||||
BENCHMARK(BenchmarkSandboxRestartOverhead);
|
BENCHMARK(BenchmarkSandboxRestartOverhead);
|
||||||
|
|
||||||
void BenchmarkSandboxRestartForkserverOverhead(benchmark::State& state) {
|
void BenchmarkSandboxRestartForkserverOverhead(benchmark::State& state) {
|
||||||
sapi::BasicTransaction st{absl::make_unique<StringopSandbox>()};
|
sapi::BasicTransaction st(absl::make_unique<StringopSandbox>());
|
||||||
for (auto _ : state) {
|
for (auto _ : state) {
|
||||||
EXPECT_THAT(st.Run(InvokeNop), IsOk());
|
EXPECT_THAT(st.Run(InvokeNop), IsOk());
|
||||||
EXPECT_THAT(st.GetSandbox()->Restart(true), IsOk());
|
EXPECT_THAT(st.sandbox()->Restart(true), IsOk());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BENCHMARK(BenchmarkSandboxRestartForkserverOverhead);
|
BENCHMARK(BenchmarkSandboxRestartForkserverOverhead);
|
||||||
|
@ -84,7 +84,7 @@ void BenchmarkSandboxRestartForkserverOverheadForced(benchmark::State& state) {
|
||||||
sapi::BasicTransaction st{absl::make_unique<StringopSandbox>()};
|
sapi::BasicTransaction st{absl::make_unique<StringopSandbox>()};
|
||||||
for (auto _ : state) {
|
for (auto _ : state) {
|
||||||
EXPECT_THAT(st.Run(InvokeNop), IsOk());
|
EXPECT_THAT(st.Run(InvokeNop), IsOk());
|
||||||
EXPECT_THAT(st.GetSandbox()->Restart(false), IsOk());
|
EXPECT_THAT(st.sandbox()->Restart(false), IsOk());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BENCHMARK(BenchmarkSandboxRestartForkserverOverheadForced);
|
BENCHMARK(BenchmarkSandboxRestartForkserverOverheadForced);
|
||||||
|
|
|
@ -23,23 +23,23 @@ constexpr absl::Duration TransactionBase::kDefaultTimeLimit;
|
||||||
sapi::Status TransactionBase::RunTransactionFunctionInSandbox(
|
sapi::Status TransactionBase::RunTransactionFunctionInSandbox(
|
||||||
const std::function<sapi::Status()>& f) {
|
const std::function<sapi::Status()>& f) {
|
||||||
// Run Main(), invoking Init() if this hasn't been yet done.
|
// Run Main(), invoking Init() if this hasn't been yet done.
|
||||||
SAPI_RETURN_IF_ERROR(GetSandbox()->Init());
|
SAPI_RETURN_IF_ERROR(sandbox_->Init());
|
||||||
|
|
||||||
// Set the wall-time limit for this transaction run, and clean it up
|
// Set the wall-time limit for this transaction run, and clean it up
|
||||||
// afterwards, no matter what the result.
|
// afterwards, no matter what the result.
|
||||||
SAPI_RETURN_IF_ERROR(GetSandbox()->SetWallTimeLimit(GetTimeLimit()));
|
SAPI_RETURN_IF_ERROR(sandbox_->SetWallTimeLimit(GetTimeLimit()));
|
||||||
struct TimeCleanup {
|
struct TimeCleanup {
|
||||||
~TimeCleanup() {
|
~TimeCleanup() {
|
||||||
if (capture->GetSandbox()->IsActive()) {
|
if (capture->sandbox_->IsActive()) {
|
||||||
capture->GetSandbox()->SetWallTimeLimit(0).IgnoreError();
|
capture->sandbox_->SetWallTimeLimit(0).IgnoreError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TransactionBase* capture;
|
TransactionBase* capture;
|
||||||
} sandbox_cleanup{this};
|
} sandbox_cleanup = {this};
|
||||||
|
|
||||||
if (!GetInited()) {
|
if (!initialized_) {
|
||||||
SAPI_RETURN_IF_ERROR(Init());
|
SAPI_RETURN_IF_ERROR(Init());
|
||||||
SetInited(true);
|
initialized_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return f();
|
return f();
|
||||||
|
@ -50,24 +50,24 @@ sapi::Status TransactionBase::RunTransactionLoop(
|
||||||
// Try to run Main() for a few times, return error if none of the tries
|
// Try to run Main() for a few times, return error if none of the tries
|
||||||
// succeeded.
|
// succeeded.
|
||||||
sapi::Status status;
|
sapi::Status status;
|
||||||
for (int i = 0; i <= GetRetryCnt(); i++) {
|
for (int i = 0; i <= retry_count_; ++i) {
|
||||||
status = RunTransactionFunctionInSandbox(f);
|
status = RunTransactionFunctionInSandbox(f);
|
||||||
if (status.ok()) {
|
if (status.ok()) {
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
GetSandbox()->Terminate();
|
sandbox_->Terminate();
|
||||||
SetInited(false);
|
initialized_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(ERROR) << "Tried " << (GetRetryCnt() + 1) << " times to run the "
|
LOG(ERROR) << "Tried " << (retry_count_ + 1) << " times to run the "
|
||||||
<< "transaction, but it failed. SAPI error: '" << status
|
<< "transaction, but it failed. SAPI error: '" << status
|
||||||
<< "'. Latest sandbox error: '"
|
<< "'. Latest sandbox error: '"
|
||||||
<< GetSandbox()->AwaitResult().ToString() << "'";
|
<< sandbox_->AwaitResult().ToString() << "'";
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
TransactionBase::~TransactionBase() {
|
TransactionBase::~TransactionBase() {
|
||||||
if (GetInited()) {
|
if (initialized_) {
|
||||||
Finish().IgnoreError();
|
Finish().IgnoreError();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,13 +51,14 @@ class TransactionBase {
|
||||||
public:
|
public:
|
||||||
TransactionBase(const TransactionBase&) = delete;
|
TransactionBase(const TransactionBase&) = delete;
|
||||||
TransactionBase& operator=(const TransactionBase&) = delete;
|
TransactionBase& operator=(const TransactionBase&) = delete;
|
||||||
|
|
||||||
virtual ~TransactionBase();
|
virtual ~TransactionBase();
|
||||||
|
|
||||||
// Getter/Setter for retry_cnt_.
|
// Getter/Setter for retry_count_.
|
||||||
int GetRetryCnt() const { return retry_cnt_; }
|
int retry_count() const { return retry_count_; }
|
||||||
void SetRetryCnt(int retry_count) {
|
void set_retry_count(int value) {
|
||||||
CHECK_GE(retry_count, 0);
|
CHECK_GE(value, 0);
|
||||||
retry_cnt_ = retry_count;
|
retry_count_ = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getter/Setter for time_limit_.
|
// Getter/Setter for time_limit_.
|
||||||
|
@ -67,30 +68,28 @@ class TransactionBase {
|
||||||
time_limit_ = absl::ToTimeT(absl::UnixEpoch() + time_limit);
|
time_limit_ = absl::ToTimeT(absl::UnixEpoch() + time_limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getter/Setter for inited_.
|
bool IsInitialized() const { return initialized_; }
|
||||||
bool GetInited() const { return inited_; }
|
|
||||||
void SetInited(bool inited) { inited_ = inited; }
|
|
||||||
|
|
||||||
// Getter for the sandbox_.
|
// Getter for the sandbox_.
|
||||||
Sandbox* GetSandbox() { return sandbox_.get(); }
|
Sandbox* sandbox() const { return sandbox_.get(); }
|
||||||
|
|
||||||
// Restarts the sandbox.
|
// Restarts the sandbox.
|
||||||
// WARNING: This will invalidate any references to the remote process, make
|
// WARNING: This will invalidate any references to the remote process, make
|
||||||
// sure you don't keep any var's or FD's to the remote process when calling
|
// sure you don't keep any vars or FDs to the remote process when
|
||||||
// this.
|
// calling this.
|
||||||
sapi::Status Restart() {
|
sapi::Status Restart() {
|
||||||
if (inited_) {
|
if (initialized_) {
|
||||||
Finish().IgnoreError();
|
Finish().IgnoreError();
|
||||||
inited_ = false;
|
initialized_ = false;
|
||||||
}
|
}
|
||||||
return sandbox_->Restart(true);
|
return sandbox_->Restart(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit TransactionBase(std::unique_ptr<Sandbox> sandbox)
|
explicit TransactionBase(std::unique_ptr<Sandbox> sandbox)
|
||||||
: retry_cnt_(kDefaultRetryCnt),
|
: retry_count_(kDefaultRetryCount),
|
||||||
time_limit_(absl::ToTimeT(absl::UnixEpoch() + kDefaultTimeLimit)),
|
time_limit_(absl::ToTimeT(absl::UnixEpoch() + kDefaultTimeLimit)),
|
||||||
inited_(false),
|
initialized_(false),
|
||||||
sandbox_(std::move(sandbox)) {}
|
sandbox_(std::move(sandbox)) {}
|
||||||
|
|
||||||
// Runs the main (retrying) transaction loop.
|
// Runs the main (retrying) transaction loop.
|
||||||
|
@ -98,7 +97,7 @@ class TransactionBase {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Number of default transaction execution re-tries, in case of failures.
|
// Number of default transaction execution re-tries, in case of failures.
|
||||||
static constexpr int kDefaultRetryCnt = 1;
|
static constexpr int kDefaultRetryCount = 1;
|
||||||
|
|
||||||
// Wall-time limit for a single transaction execution (60 s.).
|
// Wall-time limit for a single transaction execution (60 s.).
|
||||||
static constexpr absl::Duration kDefaultTimeLimit = absl::Seconds(60);
|
static constexpr absl::Duration kDefaultTimeLimit = absl::Seconds(60);
|
||||||
|
@ -108,7 +107,7 @@ class TransactionBase {
|
||||||
sapi::Status RunTransactionFunctionInSandbox(
|
sapi::Status RunTransactionFunctionInSandbox(
|
||||||
const std::function<sapi::Status()>& f);
|
const std::function<sapi::Status()>& f);
|
||||||
|
|
||||||
// Initialization routine of the sandboxed process that ill be called only
|
// Initialization routine of the sandboxed process that will be called only
|
||||||
// once upon sandboxee startup.
|
// once upon sandboxee startup.
|
||||||
virtual sapi::Status Init() { return sapi::OkStatus(); }
|
virtual sapi::Status Init() { return sapi::OkStatus(); }
|
||||||
|
|
||||||
|
@ -117,14 +116,14 @@ class TransactionBase {
|
||||||
virtual sapi::Status Finish() { return sapi::OkStatus(); }
|
virtual sapi::Status Finish() { return sapi::OkStatus(); }
|
||||||
|
|
||||||
// Number of tries this transaction will be re-executed until it succeeds.
|
// Number of tries this transaction will be re-executed until it succeeds.
|
||||||
int retry_cnt_;
|
int retry_count_;
|
||||||
|
|
||||||
// Time (wall-time) limit for a single Run() call (in seconds). 0 means: no
|
// Time (wall-time) limit for a single Run() call (in seconds). 0 means: no
|
||||||
// wall-time limit.
|
// wall-time limit.
|
||||||
time_t time_limit_;
|
time_t time_limit_;
|
||||||
|
|
||||||
// Has Init() finished with success?
|
// Has Init() finished with success?
|
||||||
bool inited_;
|
bool initialized_;
|
||||||
|
|
||||||
// The main sapi::Sandbox object.
|
// The main sapi::Sandbox object.
|
||||||
std::unique_ptr<Sandbox> sandbox_;
|
std::unique_ptr<Sandbox> sandbox_;
|
||||||
|
@ -172,13 +171,13 @@ class BasicTransaction final : public TransactionBase {
|
||||||
init_function_(static_cast<InitFunction>(init_function)),
|
init_function_(static_cast<InitFunction>(init_function)),
|
||||||
finish_function_(static_cast<FinishFunction>(fini_function)) {}
|
finish_function_(static_cast<FinishFunction>(fini_function)) {}
|
||||||
|
|
||||||
// Run any function as body of the transaction that matches our expectations (
|
// Run any function as body of the transaction that matches our expectations
|
||||||
// that is: Returning a sapi::Status and accepting a Sandbox object as first
|
// (that is: Returning a Status and accepting a Sandbox object as first
|
||||||
// parameter).
|
// parameter).
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
sapi::Status Run(T func, Args&&... args) {
|
sapi::Status Run(T func, Args&&... args) {
|
||||||
return RunTransactionLoop(
|
return RunTransactionLoop(
|
||||||
[&] { return func(GetSandbox(), std::forward<Args>(args)...); });
|
[&] { return func(sandbox(), std::forward<Args>(args)...); });
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -186,11 +185,11 @@ class BasicTransaction final : public TransactionBase {
|
||||||
FinishFunction finish_function_;
|
FinishFunction finish_function_;
|
||||||
|
|
||||||
sapi::Status Init() final {
|
sapi::Status Init() final {
|
||||||
return init_function_ ? init_function_(GetSandbox()) : sapi::OkStatus();
|
return init_function_ ? init_function_(sandbox()) : sapi::OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
sapi::Status Finish() final {
|
sapi::Status Finish() final {
|
||||||
return finish_function_ ? finish_function_(GetSandbox()) : sapi::OkStatus();
|
return finish_function_ ? finish_function_(sandbox()) : sapi::OkStatus();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user