Add external embedding example

This change contains a "hello world"-style example library to be
sandboxed. It consists of a stand-alone CMake and Bazel project that
uses Sandboxed API as its dependency.

To use Sandboxed API in an external project, it should be enough to
copy the files in the `sandboxed_api/examples/hello_sapi` directory
as a starting point.
This commit is contained in:
Christian Blichmann 2020-05-14 11:40:02 +02:00
parent ba47adc21d
commit 2c8c9a489a
No known key found for this signature in database
GPG Key ID: 19DC5E747974E966
7 changed files with 329 additions and 0 deletions

View File

@ -0,0 +1,2 @@
# Build in C++17 mode without a custom CROSSTOOL
build --cxxopt=-std=c++17

View File

@ -0,0 +1,60 @@
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
load(
"@com_google_sandboxed_api//sandboxed_api/bazel:sapi.bzl",
"sapi_library",
)
# Library with code that should be sandboxed
cc_library(
name = "hello_lib",
srcs = ["hello_lib.cc"],
alwayslink = 1,
)
# Sandboxed API for the library above
sapi_library(
name = "hello_sapi",
functions = [
"AddTwoIntegers",
],
input_files = ["hello_lib.cc"],
lib = ":hello_lib",
lib_name = "Hello",
visibility = ["//visibility:public"],
)
# Main executable demonstrating how the sandboxed library is used
cc_binary(
name = "hello",
srcs = ["hello_main.cc"],
copts = ["-I."], # To find the generated header
deps = [":hello_sapi"],
)
# Another example using the same library, but using the Transaction API that
# automatically retries sandbox operations. Also demonstates error handling
# and a custom security policy.
cc_binary(
name = "hello_transacted",
srcs = ["hello_transacted.cc"],
copts = ["-I."], # To find the generated header
deps = [
":hello_sapi",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status",
"@com_google_sandboxed_api//sandboxed_api/util:status",
],
)

View File

@ -0,0 +1,82 @@
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Example that demonstrates how to embed Sandboxed API into a project using
# CMake.
cmake_minimum_required(VERSION 3.12)
project(hello_sapi_project CXX)
# Path to the Sandboxed API source tree. Unlike Bazel, CMake does not download
# downstream dependencies by default. So the option below needs to be adjusted
# to point to a local checkout or a Git submodule.
# The default value is chosen so that this example can be easily tried out for
# a regular checkout of Sandboxed API.
set(SAPI_ROOT "${PROJECT_SOURCE_DIR}/../../.."
CACHE PATH "Path to the Sandboxed API source tree")
# Configure options and include Sandboxed API as a sub-directory.
set(SAPI_ENABLE_EXAMPLES OFF CACHE BOOL "")
set(SAPI_ENABLE_TESTS OFF CACHE BOOL "")
add_subdirectory("${SAPI_ROOT}"
"${CMAKE_BINARY_DIR}/sandboxed-api-build" EXCLUDE_FROM_ALL)
# Interface library with common settings for this projects
add_library(hello_base INTERFACE)
add_library(hello::base ALIAS hello_base)
target_compile_features(hello_base INTERFACE cxx_std_17)
target_include_directories(hello_base INTERFACE
"${PROJECT_BINARY_DIR}" # To find the generated SAPI header
)
# Library with code that should be sandboxed
add_library(hello_lib STATIC
hello_lib.cc
)
target_link_libraries(hello_lib PRIVATE
hello::base
)
# Sandboxed API for the library above
add_sapi_library(hello_sapi
FUNCTIONS AddTwoIntegers
INPUTS hello_lib.cc
LIBRARY hello_lib
LIBRARY_NAME Hello
NAMESPACE ""
)
add_library(hello::sapi ALIAS hello_sapi)
# Main executable demonstrating how the sandboxed library is used
add_executable(hello
hello_main.cc
)
target_link_libraries(hello PRIVATE
hello::base
hello::sapi
sapi::sapi
)
# Another example using the same library, but using the Transaction API that
# automatically retries sandbox operations. Also demonstates error handling
# and a custom security policy.
add_executable(hello_transacted
hello_transacted.cc
)
target_link_libraries(hello_transacted PRIVATE
hello::base
hello::sapi
sapi::sapi
)

View File

@ -0,0 +1,49 @@
# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Example workspace demonstrating how to embed Sandboxed API into a project
# using Bazel.
workspace(name = "com_google_sandboxed_api_hello")
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
# Include the Sandboxed API dependency if it does not already exist in this
# project. This ensures that this workspace plays well with other external
# dependencies that might use Sandboxed API.
maybe(
git_repository,
name = "com_google_sandboxed_api",
# This example depends on the latest master. In an embedding project, it
# is advisable to pin Sandboxed API to a specific version.
# commit = "ba47adc21d4c9bc316f3c7c32b0faaef952c111e", # 2020-05-15
remote = "https://github.com/google/sandboxed-api.git",
)
# From here on, Sandboxed API files are available. The statements below setup
# transitive dependencies such as Abseil. Like above, those will only be
# included if they don't already exist in the project.
load(
"@com_google_sandboxed_api//sandboxed_api/bazel:sapi_deps.bzl",
"sapi_deps",
)
sapi_deps()
# Need to separately setup Protobuf dependencies in order for the build rules
# to work.
load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")
protobuf_deps()

View File

@ -0,0 +1,19 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Adds two integer values and returns the result, serving as an example
// function that will be sandboxed.
extern "C" int AddTwoIntegers(int a, int b) {
return a + b;
}

View File

@ -0,0 +1,38 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// A minimal "hello world" style example of how to use Sandboxed API. This
// example does not include any error handling and will simply abort if
// something goes wrong.
// As the library function that is being called into is pure computation (i.e.
// does not issue any syscalls), the restricted default sandbox policy is being
// used.
#include <cstdlib>
#include <iostream>
#include "hello_sapi.sapi.h" // Generated header
int main() {
std::cout << "Calling into a sandboxee to add two numbers...\n";
HelloSandbox sandbox;
sandbox.Init().IgnoreError();
HelloApi api(&sandbox);
std::cout << " 1000 + 337 = " << api.AddTwoIntegers(1000, 337).value()
<< "\n";
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,79 @@
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// These are needed for the __NR_xxx syscall numbers
#include <linux/audit.h>
#include <sys/syscall.h>
#include <iostream>
#include <memory>
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "hello_sapi.sapi.h" // Generated header
#include "sandboxed_api/sandbox2/policy.h"
#include "sandboxed_api/sandbox2/policybuilder.h"
#include "sandboxed_api/transaction.h"
#include "sandboxed_api/util/status_macros.h"
namespace {
class CustomHelloSandbox : public HelloSandbox {
public:
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
sandbox2::PolicyBuilder*) override {
// Return a new policy.
return sandbox2::PolicyBuilder()
.AllowRead()
.AllowWrite()
.AllowOpen()
.AllowSystemMalloc()
.AllowHandleSignals()
.AllowExit()
.AllowStat()
.AllowTime()
.AllowGetIDs()
.AllowGetPIDs()
.AllowSyscalls({
__NR_tgkill,
__NR_recvmsg,
__NR_sendmsg,
__NR_lseek,
__NR_nanosleep,
__NR_futex,
__NR_close,
})
.AddFile("/etc/localtime")
.BuildOrDie();
}
};
} // namespace
int main() {
std::cout << "Calling into a sandboxee to add two numbers...\n";
sapi::BasicTransaction transaction(absl::make_unique<CustomHelloSandbox>());
absl::Status status =
transaction.Run([](sapi::Sandbox* sandbox) -> absl::Status {
HelloApi api(sandbox);
SAPI_ASSIGN_OR_RETURN(int result, api.AddTwoIntegers(1000, 337));
std::cout << " 1000 + 337 = " << result << "\n";
return absl::OkStatus();
});
if (!status.ok()) {
std::cerr << "Error during sandbox call: " << status.message() << "\n";
}
}