Merge branch 'master' into jsonnet

pull/54/head
Katarzyna Miernikiewicz 2020-09-18 12:09:34 +02:00 committed by GitHub
commit 73522f4844
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
123 changed files with 6104 additions and 1076 deletions

View File

@ -1,4 +1,6 @@
---
Language: Cpp
BasedOnStyle: Google
Language: Cpp
BasedOnStyle: Google
DerivePointerAlignment: false
PointerAlignment: Left
...

6
.gitmodules vendored
View File

@ -1,3 +1,9 @@
[submodule "oss-internship-2020/jsonnet/jsonnet"]
path = oss-internship-2020/jsonnet/jsonnet
url = https://github.com/google/jsonnet.git
[submodule "oss-internship-2020/openjpeg/openjpeg"]
path = oss-internship-2020/openjpeg/openjpeg
url = https://github.com/uclouvain/openjpeg.git
[submodule "oss-internship-2020/pffft/master"]
path = oss-internship-2020/pffft/master
url = https://bitbucket.org/jpommier/pffft/src/master/

View File

@ -132,7 +132,6 @@ function(add_sapi_library)
set(_sapi_embed_dir "${CMAKE_CURRENT_BINARY_DIR}")
set(_sapi_embed_name "${_sapi_NAME}")
endif()
# TODO(cblichmann): Implement sapi_isystem
if(SAPI_ENABLE_GENERATOR)
add_custom_command(
OUTPUT "${_sapi_gen_header}"
@ -149,9 +148,14 @@ function(add_sapi_library)
VERBATIM
)
else()
set(_sapi_isystem "${_sapi_NAME}.isystem")
list_join(_sapi_full_inputs "," _sapi_full_inputs)
add_custom_command(
OUTPUT "${_sapi_gen_header}"
OUTPUT "${_sapi_gen_header}" "${_sapi_isystem}"
COMMAND sh -c
"${CMAKE_CXX_COMPILER} -E -x c++ -v /dev/null 2>&1 | \
awk '/> search starts here:/{f=1;next}/^End of search/{f=0}f{print $1}' \
> \"${_sapi_isystem}\""
COMMAND "${SAPI_PYTHON3_EXECUTABLE}" -B
"${SAPI_SOURCE_DIR}/sandboxed_api/tools/generator2/sapi_generator.py"
"--sapi_name=${_sapi_LIBRARY_NAME}"
@ -160,8 +164,10 @@ function(add_sapi_library)
"--sapi_embed_name=${_sapi_embed_name}"
"--sapi_functions=${_sapi_funcs}"
"--sapi_ns=${_sapi_NAMESPACE}"
"--sapi_isystem=${_sapi_isystem}"
"--sapi_in=${_sapi_full_inputs}"
COMMENT "Generating interface"
VERBATIM
)
endif()

View File

@ -18,7 +18,7 @@ project(absl-download NONE)
include(ExternalProject)
ExternalProject_Add(absl
GIT_REPOSITORY https://github.com/abseil/abseil-cpp
GIT_TAG 6e18c7115df9b7ca0987cc346b1b1d4b3cc829b3 # 2020-04-28
GIT_TAG 0e9921b75a0fdd639a504ec8443fc1fe801becd7 # 2020-09-02
SOURCE_DIR "${CMAKE_BINARY_DIR}/absl-src"
BINARY_DIR "${CMAKE_BINARY_DIR}/absl-build"
CONFIGURE_COMMAND ""

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,83 @@
# 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",
)
licenses(["notice"])
cc_library(
name = "guetzli_wrapper",
srcs = ["guetzli_entry_points.cc"],
hdrs = ["guetzli_entry_points.h"],
deps = [
"@com_google_sandboxed_api//sandboxed_api:lenval_core",
"@com_google_sandboxed_api//sandboxed_api:vars",
"@guetzli//:guetzli_lib",
"@png_archive//:png",
],
)
sapi_library(
name = "guetzli_sapi",
srcs = ["guetzli_transaction.cc"],
hdrs = [
"guetzli_sandbox.h",
"guetzli_transaction.h",
],
functions = [
"ProcessJpeg",
"ProcessRgb",
"WriteDataToFd",
],
input_files = ["guetzli_entry_points.h"],
lib = ":guetzli_wrapper",
lib_name = "Guetzli",
namespace = "guetzli::sandbox",
visibility = ["//visibility:public"],
)
cc_binary(
name = "guetzli_sandboxed",
srcs = ["guetzli_sandboxed.cc"],
deps = [
":guetzli_sapi",
],
)
cc_test(
name = "transaction_tests",
size = "large",
srcs = ["guetzli_transaction_test.cc"],
data = glob(["testdata/*"]),
visibility = ["//visibility:public"],
deps = [
"//:guetzli_sapi",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "sapi_lib_tests",
size = "large",
srcs = ["guetzli_sapi_test.cc"],
data = glob(["testdata/*"]),
visibility = ["//visibility:public"],
deps = [
"//:guetzli_sapi",
"@com_google_googletest//:gtest_main",
],
)

View File

@ -0,0 +1,32 @@
# Guetzli Sandbox
This is an example implementation of a sandbox for the [Guetzli](https://github.com/google/guetzli) library using [Sandboxed API](https://github.com/google/sandboxed-api).
Please read Guetzli's [documentation](https://github.com/google/guetzli#introduction) to learn more about it.
## Implementation details
Because Guetzli provides a C++ API and SAPI requires functions to be `extern "C"`, a wrapper library has been written for the compatibility. SAPI provides a Transaction class, which is a convenient way to create a wrapper for your sandboxed API that handles internal errors. The original Guetzli has a command-line utility to encode images, so a fully compatible utility that uses sandboxed Guetzli is provided.
The wrapper around Guetzli uses file descriptors to pass data to the sandbox. This approach restricts the sandbox from using the `open()` syscall and also helps to prevent making copies of data, because you need to synchronize it between processes.
## Build Guetzli Sandboxed
Right now Sandboxed API support only Linux systems, so you need one to build it. Guetzli sandboxed uses [Bazel](https://bazel.build/) as a build system so you need to [install it](https://docs.bazel.build/versions/3.4.0/install.html) before building.
To build Guetzli sandboxed encoding utility you can use this command:
`bazel build //:guetzli_sandboxed`
Then you can use it in this way:
```
guetzli_sandboxed [--quality Q] [--verbose] original.png output.jpg
guetzli_sandboxed [--quality Q] [--verbose] original.jpg output.jpg
```
Refer to Guetzli's [documentation](https://github.com/google/guetzli#using) to read more about usage.
## Examples
There are two different sets of unit tests which demonstrate how to use different parts of Guetzli sandboxed:
* `tests/guetzli_sapi_test.cc` - example usage of Guetzli sandboxed API.
* `tests/guetzli_transaction_test.cc` - example usage of Guetzli transaction.
To run tests use the following command:
`bazel test ...`
Also, there is an example of custom security policy for your sandbox in
`guetzli_sandbox.h`

View File

@ -0,0 +1,100 @@
# 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.
workspace(name = "guetzli_sandboxed")
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
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 revision instead.
# commit = "ba47adc21d4c9bc316f3c7c32b0faaef952c111e", # 2020-05-15
branch = "master",
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()
http_archive(
name = "guetzli",
build_file = "guetzli.BUILD",
sha256 = "39632357e49db83d9560bf0de560ad833352f36d23b109b0e995b01a37bddb57",
strip_prefix = "guetzli-master",
url = "https://github.com/google/guetzli/archive/master.zip",
)
http_archive(
name = "butteraugli",
build_file = "butteraugli.BUILD",
sha256 = "39632357e49db83d9560bf0de560ad833352f36d23b109b0e995b01a37bddb57",
strip_prefix = "guetzli-master/third_party/butteraugli",
url = "https://github.com/google/guetzli/archive/master.zip",
)
http_archive(
name = "png_archive",
build_file = "png.BUILD",
sha256 = "a941dc09ca00148fe7aaf4ecdd6a67579c293678ed1e1cf633b5ffc02f4f8cf7",
strip_prefix = "libpng-1.2.57",
url = "http://github.com/glennrp/libpng/archive/v1.2.57.zip",
)
http_archive(
name = "jpeg_archive",
build_file = "jpeg.BUILD",
sha256 = "240fd398da741669bf3c90366f58452ea59041cacc741a489b99f2f6a0bad052",
strip_prefix = "jpeg-9b",
url = "http://www.ijg.org/files/jpegsrc.v9b.tar.gz",
)
http_archive(
name = "net_zlib",
build_file = "zlib.BUILD",
sha256 = "c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1", # 2020-04-23
strip_prefix = "zlib-1.2.11",
urls = [
"https://mirror.bazel.build/zlib.net/zlib-1.2.11.tar.gz",
"https://www.zlib.net/zlib-1.2.11.tar.gz",
],
)
# GoogleTest/GoogleMock
maybe(
http_archive,
name = "com_google_googletest",
sha256 = "a6ab7c7d6fd4dd727f6012b5d85d71a73d3aa1274f529ecd4ad84eb9ec4ff767", # 2020-04-16
strip_prefix = "googletest-dcc92d0ab6c4ce022162a23566d44f673251eee4",
urls = ["https://github.com/google/googletest/archive/dcc92d0ab6c4ce022162a23566d44f673251eee4.zip"],
)

View File

@ -0,0 +1,28 @@
# 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.
licenses(["notice"])
cc_library(
name = "butteraugli",
srcs = [
"butteraugli/butteraugli.cc",
"butteraugli/butteraugli.h",
],
hdrs = [
"butteraugli/butteraugli.h",
],
copts = ["-Wno-sign-compare"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,32 @@
# 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.
licenses(["notice"])
cc_library(
name = "guetzli_lib",
srcs = glob(
[
"guetzli/*.h",
"guetzli/*.cc",
"guetzli/*.inc",
],
exclude = ["guetzli/guetzli.cc"],
),
copts = [ "-Wno-sign-compare" ],
visibility= [ "//visibility:public" ],
deps = [
"@butteraugli//:butteraugli",
],
)

View File

@ -0,0 +1,89 @@
# Description:
# The Independent JPEG Group's JPEG runtime library.
licenses(["notice"]) # custom notice-style license, see LICENSE
cc_library(
name = "jpeg",
srcs = [
"cderror.h",
"cdjpeg.h",
"jaricom.c",
"jcapimin.c",
"jcapistd.c",
"jcarith.c",
"jccoefct.c",
"jccolor.c",
"jcdctmgr.c",
"jchuff.c",
"jcinit.c",
"jcmainct.c",
"jcmarker.c",
"jcmaster.c",
"jcomapi.c",
"jconfig.h",
"jcparam.c",
"jcprepct.c",
"jcsample.c",
"jctrans.c",
"jdapimin.c",
"jdapistd.c",
"jdarith.c",
"jdatadst.c",
"jdatasrc.c",
"jdcoefct.c",
"jdcolor.c",
"jdct.h",
"jddctmgr.c",
"jdhuff.c",
"jdinput.c",
"jdmainct.c",
"jdmarker.c",
"jdmaster.c",
"jdmerge.c",
"jdpostct.c",
"jdsample.c",
"jdtrans.c",
"jerror.c",
"jfdctflt.c",
"jfdctfst.c",
"jfdctint.c",
"jidctflt.c",
"jidctfst.c",
"jidctint.c",
"jinclude.h",
"jmemmgr.c",
"jmemnobs.c",
"jmemsys.h",
"jmorecfg.h",
"jquant1.c",
"jquant2.c",
"jutils.c",
"jversion.h",
"transupp.h",
],
hdrs = [
"jerror.h",
"jpegint.h",
"jpeglib.h",
],
includes = ["."],
visibility = ["//visibility:public"],
)
genrule(
name = "configure",
outs = ["jconfig.h"],
cmd = "cat <<EOF >$@\n" +
"#define HAVE_PROTOTYPES 1\n" +
"#define HAVE_UNSIGNED_CHAR 1\n" +
"#define HAVE_UNSIGNED_SHORT 1\n" +
"#define HAVE_STDDEF_H 1\n" +
"#define HAVE_STDLIB_H 1\n" +
"#ifdef WIN32\n" +
"#define INLINE __inline\n" +
"#else\n" +
"#define INLINE __inline__\n" +
"#endif\n" +
"EOF\n",
)

View File

@ -0,0 +1,33 @@
# Description:
# libpng is the official PNG reference library.
licenses(["notice"]) # BSD/MIT-like license
cc_library(
name = "png",
srcs = [
"png.c",
"pngerror.c",
"pngget.c",
"pngmem.c",
"pngpread.c",
"pngread.c",
"pngrio.c",
"pngrtran.c",
"pngrutil.c",
"pngset.c",
"pngtrans.c",
"pngwio.c",
"pngwrite.c",
"pngwtran.c",
"pngwutil.c",
],
hdrs = [
"png.h",
"pngconf.h",
],
includes = ["."],
linkopts = ["-lm"],
visibility = ["//visibility:public"],
deps = ["@net_zlib//:zlib"],
)

View File

@ -0,0 +1,56 @@
# Copyright 2019 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.
licenses(["notice"])
cc_library(
name = "zlib",
srcs = [
"adler32.c",
"compress.c",
"crc32.c",
"deflate.c",
"gzclose.c",
"gzlib.c",
"gzread.c",
"gzwrite.c",
"infback.c",
"inffast.c",
"inflate.c",
"inflate.h",
"inftrees.c",
"trees.c",
"trees.h",
"uncompr.c",
"zutil.c",
],
hdrs = ["zlib.h"],
# Use -Dverbose=-1 to turn off zlib's trace logging. (#3280)
copts = [
"-w",
"-Dverbose=-1",
],
includes = ["."],
textual_hdrs = [
"crc32.h",
"deflate.h",
"gzguts.h",
"inffast.h",
"inffixed.h",
"inftrees.h",
"zconf.h",
"zutil.h",
],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,293 @@
// 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.
#include "guetzli_entry_points.h" // NOLINT(build/include)
#include <sys/stat.h>
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <string>
#include <vector>
#include "guetzli/jpeg_data_reader.h"
#include "guetzli/quality.h"
#include "png.h" // NOLINT(build/include)
#include "sandboxed_api/sandbox2/util/fileops.h"
#include "sandboxed_api/util/statusor.h"
namespace {
constexpr int kBytesPerPixel = 350;
constexpr int kLowestMemusageMB = 100;
struct GuetzliInitData {
std::string in_data;
guetzli::Params params;
guetzli::ProcessStats stats;
};
struct ImageData {
int xsize;
int ysize;
std::vector<uint8_t> rgb;
};
sapi::LenValStruct CreateLenValFromData(const void* data, size_t size) {
void* new_data = malloc(size);
memcpy(new_data, data, size);
return {size, new_data};
}
sapi::StatusOr<std::string> ReadFromFd(int fd) {
struct stat file_data;
int status = fstat(fd, &file_data);
if (status < 0) {
return absl::FailedPreconditionError("Error reading input from fd");
}
std::string result;
result.resize(file_data.st_size);
status = read(fd, result.data(), result.size());
if (status < 0) {
return absl::FailedPreconditionError("Error reading input from fd");
}
return result;
}
sapi::StatusOr<GuetzliInitData> PrepareDataForProcessing(
const ProcessingParams& processing_params) {
sapi::StatusOr<std::string> input = ReadFromFd(processing_params.remote_fd);
if (!input.ok()) {
return input.status();
}
guetzli::Params guetzli_params;
guetzli_params.butteraugli_target = static_cast<float>(
guetzli::ButteraugliScoreForQuality(processing_params.quality));
guetzli::ProcessStats stats;
if (processing_params.verbose) {
stats.debug_output_file = stderr;
}
return GuetzliInitData{std::move(input.value()), guetzli_params, stats};
}
inline uint8_t BlendOnBlack(const uint8_t val, const uint8_t alpha) {
return (static_cast<int>(val) * static_cast<int>(alpha) + 128) / 255;
}
// Modified version of ReadPNG from original guetzli.cc
sapi::StatusOr<ImageData> ReadPNG(const std::string& data) {
std::vector<uint8_t> rgb;
int xsize, ysize;
png_structp png_ptr =
png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (!png_ptr) {
return absl::FailedPreconditionError(
"Error reading PNG data from input file");
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
png_destroy_read_struct(&png_ptr, nullptr, nullptr);
return absl::FailedPreconditionError(
"Error reading PNG data from input file");
}
if (setjmp(png_jmpbuf(png_ptr)) != 0) {
// Ok we are here because of the setjmp.
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
return absl::FailedPreconditionError(
"Error reading PNG data from input file");
}
std::istringstream memstream(data, std::ios::in | std::ios::binary);
png_set_read_fn(
png_ptr, static_cast<void*>(&memstream),
[](png_structp png_ptr, png_bytep outBytes, png_size_t byteCountToRead) {
std::istringstream& memstream =
*static_cast<std::istringstream*>(png_get_io_ptr(png_ptr));
memstream.read(reinterpret_cast<char*>(outBytes), byteCountToRead);
if (memstream.eof()) png_error(png_ptr, "unexpected end of data");
if (memstream.fail()) png_error(png_ptr, "read from memory error");
});
// The png_transforms flags are as follows:
// packing == convert 1,2,4 bit images,
// strip == 16 -> 8 bits / channel,
// shift == use sBIT dynamics, and
// expand == palettes -> rgb, grayscale -> 8 bit images, tRNS -> alpha.
const unsigned int png_transforms =
PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_16;
png_read_png(png_ptr, info_ptr, png_transforms, nullptr);
png_bytep* row_pointers = png_get_rows(png_ptr, info_ptr);
xsize = png_get_image_width(png_ptr, info_ptr);
ysize = png_get_image_height(png_ptr, info_ptr);
rgb.resize(3 * xsize * ysize);
const int components = png_get_channels(png_ptr, info_ptr);
switch (components) {
case 1: {
// GRAYSCALE
for (int y = 0; y < ysize; ++y) {
const uint8_t* row_in = row_pointers[y];
uint8_t* row_out = &rgb[3 * y * xsize];
for (int x = 0; x < xsize; ++x) {
const uint8_t gray = row_in[x];
row_out[3 * x + 0] = gray;
row_out[3 * x + 1] = gray;
row_out[3 * x + 2] = gray;
}
}
break;
}
case 2: {
// GRAYSCALE + ALPHA
for (int y = 0; y < ysize; ++y) {
const uint8_t* row_in = row_pointers[y];
uint8_t* row_out = &rgb[3 * y * xsize];
for (int x = 0; x < xsize; ++x) {
const uint8_t gray = BlendOnBlack(row_in[2 * x], row_in[2 * x + 1]);
row_out[3 * x + 0] = gray;
row_out[3 * x + 1] = gray;
row_out[3 * x + 2] = gray;
}
}
break;
}
case 3: {
// RGB
for (int y = 0; y < ysize; ++y) {
const uint8_t* row_in = row_pointers[y];
uint8_t* row_out = &rgb[3 * y * xsize];
memcpy(row_out, row_in, 3 * xsize);
}
break;
}
case 4: {
// RGBA
for (int y = 0; y < ysize; ++y) {
const uint8_t* row_in = row_pointers[y];
uint8_t* row_out = &rgb[3 * y * xsize];
for (int x = 0; x < xsize; ++x) {
const uint8_t alpha = row_in[4 * x + 3];
row_out[3 * x + 0] = BlendOnBlack(row_in[4 * x + 0], alpha);
row_out[3 * x + 1] = BlendOnBlack(row_in[4 * x + 1], alpha);
row_out[3 * x + 2] = BlendOnBlack(row_in[4 * x + 2], alpha);
}
}
break;
}
default:
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
return absl::FailedPreconditionError(
"Error reading PNG data from input file");
}
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
return ImageData{xsize, ysize, std::move(rgb)};
}
bool CheckMemoryLimitExceeded(int memlimit_mb, int xsize, int ysize) {
double pixels = static_cast<double>(xsize) * ysize;
return memlimit_mb != -1 &&
(pixels * kBytesPerPixel / (1 << 20) > memlimit_mb ||
memlimit_mb < kLowestMemusageMB);
}
} // namespace
extern "C" bool ProcessJpeg(const ProcessingParams* processing_params,
sapi::LenValStruct* output) {
auto processing_data = PrepareDataForProcessing(*processing_params);
if (!processing_data.ok()) {
std::cerr << processing_data.status().ToString() << std::endl;
return false;
}
guetzli::JPEGData jpg_header;
if (!guetzli::ReadJpeg(processing_data->in_data, guetzli::JPEG_READ_HEADER,
&jpg_header)) {
std::cerr << "Error reading JPG data from input file" << std::endl;
return false;
}
if (CheckMemoryLimitExceeded(processing_params->memlimit_mb, jpg_header.width,
jpg_header.height)) {
std::cerr << "Memory limit would be exceeded" << std::endl;
return false;
}
std::string out_data;
if (!guetzli::Process(processing_data->params, &processing_data->stats,
processing_data->in_data, &out_data)) {
std::cerr << "Guezli processing failed" << std::endl;
return false;
}
*output = CreateLenValFromData(out_data.data(), out_data.size());
return true;
}
extern "C" bool ProcessRgb(const ProcessingParams* processing_params,
sapi::LenValStruct* output) {
auto processing_data = PrepareDataForProcessing(*processing_params);
if (!processing_data.ok()) {
std::cerr << processing_data.status().ToString() << std::endl;
return false;
}
auto png_data = ReadPNG(processing_data->in_data);
if (!png_data.ok()) {
std::cerr << "Error reading PNG data from input file" << std::endl;
return false;
}
if (CheckMemoryLimitExceeded(processing_params->memlimit_mb, png_data->xsize,
png_data->ysize)) {
std::cerr << "Memory limit would be exceeded" << std::endl;
return false;
}
std::string out_data;
if (!guetzli::Process(processing_data->params, &processing_data->stats,
png_data->rgb, png_data->xsize, png_data->ysize,
&out_data)) {
std::cerr << "Guetzli processing failed" << std::endl;
return false;
}
*output = CreateLenValFromData(out_data.data(), out_data.size());
return true;
}
extern "C" bool WriteDataToFd(int fd, sapi::LenValStruct* data) {
return sandbox2::file_util::fileops::WriteToFD(
fd, static_cast<const char*>(data->data), data->size);
}

View File

@ -0,0 +1,35 @@
// 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.
#ifndef GUETZLI_SANDBOXED_GUETZLI_ENTRY_POINTS_H_
#define GUETZLI_SANDBOXED_GUETZLI_ENTRY_POINTS_H_
#include "guetzli/processor.h"
#include "sandboxed_api/lenval_core.h"
#include "sandboxed_api/vars.h"
struct ProcessingParams {
int remote_fd = -1;
int verbose = 0;
int quality = 0;
int memlimit_mb = 0;
};
extern "C" bool ProcessJpeg(const ProcessingParams* processing_params,
sapi::LenValStruct* output);
extern "C" bool ProcessRgb(const ProcessingParams* processing_params,
sapi::LenValStruct* output);
extern "C" bool WriteDataToFd(int fd, sapi::LenValStruct* data);
#endif // GUETZLI_SANDBOXED_GUETZLI_ENTRY_POINTS_H_

View File

@ -0,0 +1,45 @@
// 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.
#ifndef GUETZLI_SANDBOXED_GUETZLI_SANDBOX_H_
#define GUETZLI_SANDBOXED_GUETZLI_SANDBOX_H_
#include <syscall.h>
#include "guetzli_sapi.sapi.h" // NOLINT(build/include)
namespace guetzli::sandbox {
class GuetzliSapiSandbox : public GuetzliSandbox {
public:
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
sandbox2::PolicyBuilder*) override {
return sandbox2::PolicyBuilder()
.AllowStaticStartup()
.AllowRead()
.AllowSystemMalloc()
.AllowWrite()
.AllowExit()
.AllowStat()
.AllowSyscalls({
__NR_futex, __NR_close,
__NR_recvmsg // To work with remote fd
})
.BuildOrDie();
}
};
} // namespace guetzli::sandbox
#endif // GUETZLI_SANDBOXED_GUETZLI_SANDBOX_H_

View File

@ -0,0 +1,96 @@
// 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.
#include <cstdio>
#include <iostream>
#include "guetzli_transaction.h" // NOLINT(build/include)
#include "sandboxed_api/sandbox2/util/fileops.h"
#include "sandboxed_api/util/statusor.h"
namespace {
constexpr int kDefaultJPEGQuality = 95;
constexpr int kDefaultMemlimitMB = 6000;
void Usage() {
fprintf(stderr,
"Guetzli JPEG compressor. Usage: \n"
"guetzli [flags] input_filename output_filename\n"
"\n"
"Flags:\n"
" --verbose - Print a verbose trace of all attempts to standard "
"output.\n"
" --quality Q - Visual quality to aim for, expressed as a JPEG "
"quality value.\n"
" Default value is %d.\n"
" --memlimit M - Memory limit in MB. Guetzli will fail if unable to "
"stay under\n"
" the limit. Default limit is %d MB.\n"
" --nomemlimit - Do not limit memory usage.\n",
kDefaultJPEGQuality, kDefaultMemlimitMB);
exit(1);
}
} // namespace
int main(int argc, const char** argv) {
int verbose = 0;
int quality = kDefaultJPEGQuality;
int memlimit_mb = kDefaultMemlimitMB;
int opt_idx = 1;
for (; opt_idx < argc; opt_idx++) {
if (strnlen(argv[opt_idx], 2) < 2 || argv[opt_idx][0] != '-' ||
argv[opt_idx][1] != '-')
break;
if (!strcmp(argv[opt_idx], "--verbose")) {
verbose = 1;
} else if (!strcmp(argv[opt_idx], "--quality")) {
opt_idx++;
if (opt_idx >= argc) Usage();
quality = atoi(argv[opt_idx]); // NOLINT(runtime/deprecated_fn)
} else if (!strcmp(argv[opt_idx], "--memlimit")) {
opt_idx++;
if (opt_idx >= argc) Usage();
memlimit_mb = atoi(argv[opt_idx]); // NOLINT(runtime/deprecated_fn)
} else if (!strcmp(argv[opt_idx], "--nomemlimit")) {
memlimit_mb = -1;
} else if (!strcmp(argv[opt_idx], "--")) {
opt_idx++;
break;
} else {
fprintf(stderr, "Unknown commandline flag: %s\n", argv[opt_idx]);
Usage();
}
}
if (argc - opt_idx != 2) {
Usage();
}
guetzli::sandbox::TransactionParams params = {
argv[opt_idx], argv[opt_idx + 1], verbose, quality, memlimit_mb};
guetzli::sandbox::GuetzliTransaction transaction(std::move(params));
auto result = transaction.Run();
if (!result.ok()) {
std::cerr << result.ToString() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,124 @@
// 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.
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <syscall.h>
#include <algorithm>
#include <fstream>
#include <memory>
#include <sstream>
#include "guetzli_sandbox.h" // NOLINT(build/include)
#include "gtest/gtest.h"
#include "sandboxed_api/sandbox2/util/fileops.h"
#include "sandboxed_api/vars.h"
namespace guetzli::sandbox::tests {
namespace {
constexpr absl::string_view kInPngFilename = "bees.png";
constexpr absl::string_view kInJpegFilename = "nature.jpg";
constexpr absl::string_view kPngReferenceFilename = "bees_reference.jpg";
constexpr absl::string_view kJpegReferenceFIlename = "nature_reference.jpg";
constexpr int kDefaultQualityTarget = 95;
constexpr int kDefaultMemlimitMb = 6000;
constexpr absl::string_view kRelativePathToTestdata =
"/guetzli_sandboxed/testdata/";
std::string GetPathToInputFile(absl::string_view filename) {
return absl::StrCat(getenv("TEST_SRCDIR"), kRelativePathToTestdata, filename);
}
std::string ReadFromFile(const std::string& filename) {
std::ifstream stream(filename, std::ios::binary);
if (!stream.is_open()) {
return "";
}
std::stringstream result;
result << stream.rdbuf();
return result.str();
}
} // namespace
class GuetzliSapiTest : public ::testing::Test {
protected:
void SetUp() override {
sandbox_ = std::make_unique<GuetzliSapiSandbox>();
ASSERT_EQ(sandbox_->Init(), absl::OkStatus());
api_ = std::make_unique<GuetzliApi>(sandbox_.get());
}
std::unique_ptr<GuetzliSapiSandbox> sandbox_;
std::unique_ptr<GuetzliApi> api_;
};
// This test can take up to few minutes depending on your hardware
TEST_F(GuetzliSapiTest, ProcessRGB) {
sapi::v::Fd in_fd(open(GetPathToInputFile(kInPngFilename).c_str(), O_RDONLY));
ASSERT_TRUE(in_fd.GetValue() != -1) << "Error opening input file";
ASSERT_EQ(api_->sandbox()->TransferToSandboxee(&in_fd), absl::OkStatus())
<< "Error transfering fd to sandbox";
ASSERT_TRUE(in_fd.GetRemoteFd() != -1) << "Error opening remote fd";
sapi::v::Struct<ProcessingParams> processing_params;
*processing_params.mutable_data() = {
in_fd.GetRemoteFd(), 0, kDefaultQualityTarget, kDefaultMemlimitMb};
sapi::v::LenVal output(0);
sapi::StatusOr<bool> processing_result =
api_->ProcessRgb(processing_params.PtrBefore(), output.PtrBoth());
ASSERT_TRUE(processing_result.value_or(false)) << "Error processing rgb data";
std::string reference_data =
ReadFromFile(GetPathToInputFile(kPngReferenceFilename));
ASSERT_EQ(output.GetDataSize(), reference_data.size())
<< "Incorrect result data size";
ASSERT_EQ(
std::string(output.GetData(), output.GetData() + output.GetDataSize()),
reference_data)
<< "Processed data doesn't match reference output";
}
// This test can take up to few minutes depending on your hardware
TEST_F(GuetzliSapiTest, ProcessJpeg) {
sapi::v::Fd in_fd(
open(GetPathToInputFile(kInJpegFilename).c_str(), O_RDONLY));
ASSERT_TRUE(in_fd.GetValue() != -1) << "Error opening input file";
ASSERT_EQ(api_->sandbox()->TransferToSandboxee(&in_fd), absl::OkStatus())
<< "Error transfering fd to sandbox";
ASSERT_TRUE(in_fd.GetRemoteFd() != -1) << "Error opening remote fd";
sapi::v::Struct<ProcessingParams> processing_params;
*processing_params.mutable_data() = {
in_fd.GetRemoteFd(), 0, kDefaultQualityTarget, kDefaultMemlimitMb};
sapi::v::LenVal output(0);
sapi::StatusOr<bool> processing_result =
api_->ProcessJpeg(processing_params.PtrBefore(), output.PtrBoth());
ASSERT_TRUE(processing_result.value_or(false)) << "Error processing jpg data";
std::string reference_data =
ReadFromFile(GetPathToInputFile(kJpegReferenceFIlename));
ASSERT_EQ(output.GetDataSize(), reference_data.size())
<< "Incorrect result data size";
ASSERT_EQ(
std::string(output.GetData(), output.GetData() + output.GetDataSize()),
reference_data)
<< "Processed data doesn't match reference output";
}
} // namespace guetzli::sandbox::tests

View File

@ -0,0 +1,123 @@
// 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.
#include "guetzli_transaction.h" // NOLINT(build/include)
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
#include <memory>
namespace guetzli::sandbox {
absl::Status GuetzliTransaction::Main() {
sapi::v::Fd in_fd(open(params_.in_file, O_RDONLY));
if (in_fd.GetValue() < 0) {
return absl::FailedPreconditionError("Error opening input file");
}
SAPI_ASSIGN_OR_RETURN(image_type_, GetImageTypeFromFd(in_fd.GetValue()));
SAPI_RETURN_IF_ERROR(sandbox()->TransferToSandboxee(&in_fd));
if (in_fd.GetRemoteFd() < 0) {
return absl::FailedPreconditionError(
"Error receiving remote FD: remote input fd is set to -1");
}
GuetzliApi api(sandbox());
sapi::v::LenVal output(0);
sapi::v::Struct<ProcessingParams> processing_params;
*processing_params.mutable_data() = {in_fd.GetRemoteFd(), params_.verbose,
params_.quality, params_.memlimit_mb};
auto result =
image_type_ == ImageType::kJpeg
? api.ProcessJpeg(processing_params.PtrBefore(), output.PtrBefore())
: api.ProcessRgb(processing_params.PtrBefore(), output.PtrBefore());
if (!result.value_or(false)) {
return absl::FailedPreconditionError(absl::StrCat(
"Error processing ", (image_type_ == ImageType::kJpeg ? "jpeg" : "rgb"),
" data"));
}
sapi::v::Fd out_fd(open(".", O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR));
if (out_fd.GetValue() < 0) {
return absl::FailedPreconditionError("Error creating temp output file");
}
SAPI_RETURN_IF_ERROR(sandbox()->TransferToSandboxee(&out_fd));
if (out_fd.GetRemoteFd() < 0) {
return absl::FailedPreconditionError(
"Error receiving remote FD: remote output fd is set to -1");
}
auto write_result = api.WriteDataToFd(out_fd.GetRemoteFd(), output.PtrNone());
if (!write_result.value_or(false)) {
return absl::FailedPreconditionError("Error writing file inside sandbox");
}
SAPI_RETURN_IF_ERROR(LinkOutFile(out_fd.GetValue()));
return absl::OkStatus();
}
absl::Status GuetzliTransaction::LinkOutFile(int out_fd) const {
if (access(params_.out_file, F_OK) != -1) {
if (remove(params_.out_file) < 0) {
return absl::FailedPreconditionError(absl::StrCat(
"Error deleting existing output file: ", params_.out_file));
}
}
std::string path = absl::StrCat("/proc/self/fd/", out_fd);
if (linkat(AT_FDCWD, path.c_str(), AT_FDCWD, params_.out_file,
AT_SYMLINK_FOLLOW) < 0) {
return absl::FailedPreconditionError(
absl::StrCat("Error linking: ", params_.out_file));
}
return absl::OkStatus();
}
sapi::StatusOr<ImageType> GuetzliTransaction::GetImageTypeFromFd(int fd) const {
static const unsigned char kPNGMagicBytes[] = {
0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n',
};
char read_buf[sizeof(kPNGMagicBytes)];
if (read(fd, read_buf, sizeof(kPNGMagicBytes)) != sizeof(kPNGMagicBytes)) {
return absl::FailedPreconditionError(
"Error determining type of the input file");
}
if (lseek(fd, 0, SEEK_SET) != 0) {
return absl::FailedPreconditionError(
"Error returnig cursor to the beginning");
}
return memcmp(read_buf, kPNGMagicBytes, sizeof(kPNGMagicBytes)) == 0
? ImageType::kPng
: ImageType::kJpeg;
}
} // namespace guetzli::sandbox

View File

@ -0,0 +1,59 @@
// 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.
#ifndef GUETZLI_SANDBOXED_GUETZLI_TRANSACTION_H_
#define GUETZLI_SANDBOXED_GUETZLI_TRANSACTION_H_
#include <syscall.h>
#include "guetzli_sandbox.h" // NOLINT(build/include)
#include "sandboxed_api/transaction.h"
#include "sandboxed_api/vars.h"
namespace guetzli::sandbox {
enum class ImageType { kJpeg, kPng };
struct TransactionParams {
const char* in_file = nullptr;
const char* out_file = nullptr;
int verbose = 0;
int quality = 0;
int memlimit_mb = 0;
};
// Instance of this transaction shouldn't be reused
// Create a new one for each processing operation
class GuetzliTransaction : public sapi::Transaction {
public:
explicit GuetzliTransaction(TransactionParams params, int retry_count = 0)
: sapi::Transaction(std::make_unique<GuetzliSapiSandbox>()),
params_(std::move(params)) {
set_retry_count(retry_count);
SetTimeLimit(absl::InfiniteDuration());
}
private:
absl::Status Main() final;
absl::Status LinkOutFile(int out_fd) const;
sapi::StatusOr<ImageType> GetImageTypeFromFd(int fd) const;
const TransactionParams params_;
ImageType image_type_ = ImageType::kJpeg;
};
} // namespace guetzli::sandbox
#endif // GUETZLI_SANDBOXED_GUETZLI_TRANSACTION_H_

View File

@ -0,0 +1,145 @@
// 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.
#include "guetzli_transaction.h" // NOLINT(build/include)
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fstream>
#include <memory>
#include <sstream>
#include "gtest/gtest.h"
#include "sandboxed_api/sandbox2/util/fileops.h"
namespace guetzli::sandbox::tests {
namespace {
constexpr absl::string_view kInPngFilename = "bees.png";
constexpr absl::string_view kInJpegFilename = "nature.jpg";
constexpr absl::string_view kOutJpegFilename = "out_jpeg.jpg";
constexpr absl::string_view kOutPngFilename = "out_png.png";
constexpr absl::string_view kPngReferenceFilename = "bees_reference.jpg";
constexpr absl::string_view kJpegReferenceFIlename = "nature_reference.jpg";
constexpr int kPngExpectedSize = 38'625;
constexpr int kJpegExpectedSize = 10'816;
constexpr int kDefaultQualityTarget = 95;
constexpr int kDefaultMemlimitMb = 6000;
constexpr absl::string_view kRelativePathToTestdata =
"/guetzli_sandboxed/testdata/";
std::string GetPathToFile(absl::string_view filename) {
return absl::StrCat(getenv("TEST_SRCDIR"), kRelativePathToTestdata, filename);
}
std::string ReadFromFile(const std::string& filename) {
std::ifstream stream(filename, std::ios::binary);
if (!stream.is_open()) {
return "";
}
std::stringstream result;
result << stream.rdbuf();
return result.str();
}
// Helper class to delete file after opening
class FileRemover {
public:
explicit FileRemover(const char* path)
: path_(path), fd_(open(path, O_RDONLY)) {}
~FileRemover() {
close(fd_);
remove(path_);
}
int get() const { return fd_; }
private:
const char* path_;
int fd_;
};
} // namespace
TEST(GuetzliTransactionTest, TestTransactionJpg) {
std::string in_path = GetPathToFile(kInJpegFilename);
std::string out_path = GetPathToFile(kOutJpegFilename);
TransactionParams params = {in_path.c_str(), out_path.c_str(), 0,
kDefaultQualityTarget, kDefaultMemlimitMb};
{
GuetzliTransaction transaction(std::move(params));
absl::Status result = transaction.Run();
ASSERT_TRUE(result.ok()) << result.ToString();
}
std::string reference_data =
ReadFromFile(GetPathToFile(kJpegReferenceFIlename));
FileRemover file_remover(out_path.c_str());
ASSERT_TRUE(file_remover.get() != -1) << "Error opening output file";
off_t output_size = lseek(file_remover.get(), 0, SEEK_END);
ASSERT_EQ(reference_data.size(), output_size)
<< "Different sizes of reference and returned data";
ASSERT_EQ(lseek(file_remover.get(), 0, SEEK_SET), 0)
<< "Error repositioning out file";
std::string output;
output.resize(output_size);
ssize_t status = read(file_remover.get(), output.data(), output_size);
ASSERT_EQ(status, output_size) << "Error reading data from temp output file";
ASSERT_EQ(output, reference_data) << "Returned data doesn't match reference";
}
TEST(GuetzliTransactionTest, TestTransactionPng) {
std::string in_path = GetPathToFile(kInPngFilename);
std::string out_path = GetPathToFile(kOutPngFilename);
TransactionParams params = {in_path.c_str(), out_path.c_str(), 0,
kDefaultQualityTarget, kDefaultMemlimitMb};
{
GuetzliTransaction transaction(std::move(params));
absl::Status result = transaction.Run();
ASSERT_TRUE(result.ok()) << result.ToString();
}
std::string reference_data =
ReadFromFile(GetPathToFile(kPngReferenceFilename));
FileRemover file_remover(out_path.c_str());
ASSERT_TRUE(file_remover.get() != -1) << "Error opening output file";
off_t output_size = lseek(file_remover.get(), 0, SEEK_END);
ASSERT_EQ(reference_data.size(), output_size)
<< "Different sizes of reference and returned data";
ASSERT_EQ(lseek(file_remover.get(), 0, SEEK_SET), 0)
<< "Error repositioning out file";
std::string output;
output.resize(output_size);
ssize_t status = read(file_remover.get(), output.data(), output_size);
ASSERT_EQ(status, output_size) << "Error reading data from temp output file";
ASSERT_EQ(output, reference_data) << "Returned data doesn't match refernce";
}
} // namespace guetzli::sandbox::tests

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1 @@
build/

View File

@ -0,0 +1,56 @@
# 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.
cmake_minimum_required(VERSION 3.10)
project(openjpeg-sapi C CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# To override lib option -- else SAPI won't work
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build OpenJPEG shared library and link executables against it." FORCE)
add_subdirectory(openjpeg)
set(SAPI_ROOT "../.." CACHE PATH "Path to the Sandboxed API source tree")
set(SAPI_ENABLE_EXAMPLES OFF CACHE BOOL "")
set(SAPI_ENABLE_TESTS OFF CACHE BOOL "")
set(EXECUTABLE_OUTPUT_PATH "" CACHE PATH "" FORCE)
add_subdirectory("${SAPI_ROOT}"
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
EXCLUDE_FROM_ALL)
add_sapi_library(openjp2_sapi
FUNCTIONS opj_stream_destroy
opj_stream_create_default_file_stream
opj_create_decompress
opj_image_destroy
opj_setup_decoder
opj_destroy_codec
opj_read_header
opj_decode
opj_set_default_decoder_parameters
opj_end_decompress
INPUTS ${CMAKE_CURRENT_SOURCE_DIR}/openjpeg/src/lib/openjp2/openjpeg.h
LIBRARY openjp2
LIBRARY_NAME Openjp2
NAMESPACE ""
)
target_include_directories(openjp2_sapi INTERFACE
"${PROJECT_BINARY_DIR}"
)
add_subdirectory(examples)

View File

@ -0,0 +1,29 @@
# OpenJPEG Sandboxed API
This library provides sandboxed version of the [OpenJPEG](https://github.com/uclouvain/openjpeg) library.
## Examples
The examples are sandboxed and simplified version of the main tools provided by the OpenJPEG library, namely (for now) `opj_decompress` from [here](https://github.com/uclouvain/openjpeg/blob/master/src/bin/jp2/opj_decompress.c).
In `decompress_example.cc` the library's sandboxed API is used to convert the _.jp2_ to _.pnm_ image format.
## Build
To build this example, after cloning the whole Sandbox API project, you also need to run
```
git submodule update --init --recursive
```
anywhere in the project tree in order to clone the `openjpeg` submodule.
Then in the `sandboxed-api/oss-internship-2020/openjpeg` run
```
mkdir build && cd build
cmake -G Ninja
ninja
```
To run `decompress_sandboxed`:
```
cd examples
./decompress_sandboxed absolute/path/to/the/file.jp2 absolute/path/to/the/file.pnm
```

View File

@ -0,0 +1,48 @@
# 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.
# we need to use modified versions of some of the library tools
file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/gen_files")
file(COPY "${PROJECT_SOURCE_DIR}/openjpeg/src/bin/jp2/convert.c" DESTINATION "${PROJECT_BINARY_DIR}/gen_files/")
file(COPY "${PROJECT_SOURCE_DIR}/openjpeg/src/bin/jp2/convert.h" DESTINATION "${PROJECT_BINARY_DIR}/gen_files/")
file(COPY "${PROJECT_SOURCE_DIR}/examples/convert.patch" DESTINATION "${PROJECT_BINARY_DIR}/gen_files/")
file(COPY "${PROJECT_SOURCE_DIR}/examples/convert_h.patch" DESTINATION "${PROJECT_BINARY_DIR}/gen_files/")
add_custom_command(
OUTPUT ${PROJECT_BINARY_DIR}/gen_files/convert.cc ${PROJECT_BINARY_DIR}/gen_files/convert.h
COMMAND cd ${PROJECT_BINARY_DIR}/gen_files && patch < ${PROJECT_SOURCE_DIR}/examples/convert.patch > /dev/null
COMMAND cd ${PROJECT_BINARY_DIR}/gen_files && patch < ${PROJECT_SOURCE_DIR}/examples/convert_h.patch > /dev/null
COMMAND mv ${PROJECT_BINARY_DIR}/gen_files/convert.c ${PROJECT_BINARY_DIR}/gen_files/convert.cc
)
add_library(convert_helper STATIC
${PROJECT_BINARY_DIR}/gen_files/convert.cc
${PROJECT_BINARY_DIR}/gen_files/convert.h
)
add_executable(decompress_sandboxed
decompress_example.cc
)
target_link_libraries(decompress_sandboxed PRIVATE
convert_helper
openjp2_sapi
sapi::sapi
)
target_link_libraries(convert_helper PRIVATE
openjp2_sapi
sapi::sapi
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,135 @@
--- convert.h 2020-08-27 15:46:45.028628305 +0000
+++ convert_helper.h 2020-08-27 14:26:02.155455250 +0000
@@ -1,126 +1,8 @@
-/*
- * The copyright in this software is being made available under the 2-clauses
- * BSD License, included below. This software may be subject to other third
- * party and contributor rights, including patent rights, and no such rights
- * are granted under this license.
- *
- * Copyright (c) 2002-2014, Universite catholique de Louvain (UCL), Belgium
- * Copyright (c) 2002-2014, Professor Benoit Macq
- * Copyright (c) 2001-2003, David Janssens
- * Copyright (c) 2002-2003, Yannick Verschueren
- * Copyright (c) 2003-2007, Francois-Olivier Devaux
- * Copyright (c) 2003-2014, Antonin Descampe
- * Copyright (c) 2005, Herve Drolon, FreeImage Team
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef __J2K_CONVERT_H
-#define __J2K_CONVERT_H
+// imagetopnm and the two functions it calls internaly are patched
+// versions of the library's tools; from openjpeg/src/bin/jp2/convert.c
-/**@name RAW component encoding parameters */
-/*@{*/
-typedef struct raw_comp_cparameters {
- /** subsampling in X direction */
- int dx;
- /** subsampling in Y direction */
- int dy;
- /*@}*/
-} raw_comp_cparameters_t;
-
-/**@name RAW image encoding parameters */
-/*@{*/
-typedef struct raw_cparameters {
- /** width of the raw image */
- int rawWidth;
- /** height of the raw image */
- int rawHeight;
- /** number of components of the raw image */
- int rawComp;
- /** bit depth of the raw image */
- int rawBitDepth;
- /** signed/unsigned raw image */
- OPJ_BOOL rawSigned;
- /** raw components parameters */
- raw_comp_cparameters_t *rawComps;
- /*@}*/
-} raw_cparameters_t;
-
-/* Component precision clipping */
-void clip_component(opj_image_comp_t* component, OPJ_UINT32 precision);
-/* Component precision scaling */
-void scale_component(opj_image_comp_t* component, OPJ_UINT32 precision);
-
-/* planar / interleaved conversions */
-typedef void (* convert_32s_CXPX)(const OPJ_INT32* pSrc, OPJ_INT32* const* pDst,
- OPJ_SIZE_T length);
-extern const convert_32s_CXPX convert_32s_CXPX_LUT[5];
-typedef void (* convert_32s_PXCX)(OPJ_INT32 const* const* pSrc, OPJ_INT32* pDst,
- OPJ_SIZE_T length, OPJ_INT32 adjust);
-extern const convert_32s_PXCX convert_32s_PXCX_LUT[5];
-/* bit depth conversions */
-typedef void (* convert_XXx32s_C1R)(const OPJ_BYTE* pSrc, OPJ_INT32* pDst,
- OPJ_SIZE_T length);
-extern const convert_XXx32s_C1R convert_XXu32s_C1R_LUT[9]; /* up to 8bpp */
-typedef void (* convert_32sXXx_C1R)(const OPJ_INT32* pSrc, OPJ_BYTE* pDst,
- OPJ_SIZE_T length);
-extern const convert_32sXXx_C1R convert_32sXXu_C1R_LUT[9]; /* up to 8bpp */
-
-
-/* TGA conversion */
-opj_image_t* tgatoimage(const char *filename, opj_cparameters_t *parameters);
-int imagetotga(opj_image_t * image, const char *outfile);
-
-/* BMP conversion */
-opj_image_t* bmptoimage(const char *filename, opj_cparameters_t *parameters);
-int imagetobmp(opj_image_t *image, const char *outfile);
-
-/* TIFF conversion*/
-opj_image_t* tiftoimage(const char *filename, opj_cparameters_t *parameters);
-int imagetotif(opj_image_t *image, const char *outfile);
-/**
-Load a single image component encoded in PGX file format
-@param filename Name of the PGX file to load
-@param parameters *List ?*
-@return Returns a greyscale image if successful, returns NULL otherwise
-*/
-opj_image_t* pgxtoimage(const char *filename, opj_cparameters_t *parameters);
-int imagetopgx(opj_image_t *image, const char *outfile);
-
-opj_image_t* pnmtoimage(const char *filename, opj_cparameters_t *parameters);
-int imagetopnm(opj_image_t *image, const char *outfile, int force_split);
-
-/* RAW conversion */
-int imagetoraw(opj_image_t * image, const char *outfile);
-int imagetorawl(opj_image_t * image, const char *outfile);
-opj_image_t* rawtoimage(const char *filename, opj_cparameters_t *parameters,
- raw_cparameters_t *raw_cp);
-opj_image_t* rawltoimage(const char *filename, opj_cparameters_t *parameters,
- raw_cparameters_t *raw_cp);
-
-/* PNG conversion*/
-extern int imagetopng(opj_image_t *image, const char *write_idf);
-extern opj_image_t* pngtoimage(const char *filename,
- opj_cparameters_t *parameters);
-
-#endif /* __J2K_CONVERT_H */
+#include "openjp2_sapi.sapi.h"
+const char* opj_version(void);
+static int are_comps_similar(opj_image_t* image);
+int imagetopnm(opj_image_t* image, const char* outfile, int force_split);

View File

@ -0,0 +1,157 @@
// 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.
// Perform decompression from *.jp2 to *.pnm format
#include <libgen.h>
#include <syscall.h>
#include <cstdlib>
#include <iostream>
#include <vector>
#include "gen_files/convert.h" // NOLINT(build/include)
#include "openjp2_sapi.sapi.h" // NOLINT(build/include)
class Openjp2SapiSandbox : public Openjp2Sandbox {
public:
explicit Openjp2SapiSandbox(std::string in_file)
: in_file_(std::move(in_file)) {}
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
sandbox2::PolicyBuilder*) override {
return sandbox2::PolicyBuilder()
.AllowStaticStartup()
.AllowOpen()
.AllowRead()
.AllowWrite()
.AllowStat()
.AllowSystemMalloc()
.AllowExit()
.AllowSyscalls({
__NR_futex,
__NR_close,
__NR_lseek,
})
.AddFile(in_file_)
.BuildOrDie();
}
private:
std::string in_file_;
};
int main(int argc, char* argv[]) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
google::InitGoogleLogging(argv[0]);
if (argc != 3) {
std::cerr << "Usage: " << basename(argv[0]) << " absolute/path/to/INPUT.jp2"
<< " absolute/path/to/OUTPUT.pnm\n";
return EXIT_FAILURE;
}
std::string in_file(argv[1]);
// Initialize sandbox.
Openjp2SapiSandbox sandbox(in_file);
absl::Status status = sandbox.Init();
CHECK(status.ok()) << "Sandbox initialization failed " << status;
Openjp2Api api(&sandbox);
sapi::v::ConstCStr in_file_v(in_file.c_str());
// Initialize library's main data-holders.
sapi::StatusOr<opj_stream_t*> stream =
api.opj_stream_create_default_file_stream(in_file_v.PtrBefore(), 1);
CHECK(stream.ok()) << "Stream initialization failed: " << stream.status();
sapi::v::RemotePtr stream_pointer(stream.value());
sapi::StatusOr<opj_codec_t*> codec = api.opj_create_decompress(OPJ_CODEC_JP2);
CHECK(codec.ok()) << "Codec initialization failed: " << stream.status();
sapi::v::RemotePtr codec_pointer(codec.value());
sapi::v::Struct<opj_dparameters_t> parameters;
status = api.opj_set_default_decoder_parameters(parameters.PtrBoth());
CHECK(status.ok()) << "Parameters initialization failed " << status;
sapi::StatusOr<OPJ_BOOL> bool_status =
api.opj_setup_decoder(&codec_pointer, parameters.PtrBefore());
CHECK(bool_status.ok() && bool_status.value()) << "Decoder setup failed";
// Start reading image from the input file.
sapi::v::GenericPtr image_pointer;
bool_status = api.opj_read_header(&stream_pointer, &codec_pointer,
image_pointer.PtrAfter());
CHECK(bool_status.ok() && bool_status.value())
<< "Reading image header failed";
sapi::v::Struct<opj_image_t> image;
image.SetRemote(reinterpret_cast<void*>(image_pointer.GetValue()));
CHECK(sandbox.TransferFromSandboxee(&image).ok())
<< "Transfer from sandboxee failed";
bool_status =
api.opj_decode(&codec_pointer, &stream_pointer, image.PtrAfter());
CHECK(bool_status.ok() && bool_status.value()) << "Decoding failed";
bool_status = api.opj_end_decompress(&codec_pointer, &stream_pointer);
CHECK(bool_status.ok() && bool_status.value()) << "Ending decompress failed";
int components = image.data().numcomps;
// Transfer the read data to the main process.
sapi::v::Array<opj_image_comp_t> image_components(components);
image_components.SetRemote(image.data().comps);
CHECK(sandbox.TransferFromSandboxee(&image_components).ok())
<< "Transfer from sandboxee failed";
image.mutable_data()->comps =
static_cast<opj_image_comp_t*>(image_components.GetLocal());
unsigned int width = static_cast<unsigned int>(image.data().comps[0].w);
unsigned int height = static_cast<unsigned int>(image.data().comps[0].h);
std::vector<std::vector<OPJ_INT32>> data(components);
sapi::v::Array<OPJ_INT32> image_components_data(width * height);
for (int i = 0; i < components; ++i) {
image_components_data.SetRemote(image.data().comps[i].data);
CHECK(sandbox.TransferFromSandboxee(&image_components_data).ok())
<< "Transfer from sandboxee failed";
std::vector<OPJ_INT32> component_data(
image_components_data.GetData(),
image_components_data.GetData() + (width * height));
data[i] = std::move(component_data);
image_components[i].data = &data[i][0];
}
// Convert the image to the desired format and save it to the file.
int error =
imagetopnm(static_cast<opj_image_t*>(image.GetLocal()), argv[2], 0);
CHECK(!error) << "Image convert failed";
// Clean up.
status = api.opj_image_destroy(image.PtrNone());
CHECK(status.ok()) << "Image destroy failed " << status;
status = api.opj_stream_destroy(&stream_pointer);
CHECK(status.ok()) << "Stream destroy failed " << status;
status = api.opj_destroy_codec(&codec_pointer);
CHECK(status.ok()) << "Codec destroy failed " << status;
return EXIT_SUCCESS;
}

3
oss-internship-2020/pffft/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.o
*.a
pffft_main

View File

@ -0,0 +1,104 @@
# 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.
cmake_minimum_required(VERSION 3.10)
project(pffft CXX C)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
add_library(pffft STATIC
master/pffft.c
master/pffft.h
master/fftpack.c
master/fftpack.h
)
add_executable(pffft_main
master/test_pffft.c
)
target_link_libraries(pffft_main PRIVATE
pffft
)
set(MATH_LIBS "")
include(CheckLibraryExists)
check_library_exists(m sin "" LIBM)
if(LIBM)
list(APPEND MATH_LIBS "m")
endif()
target_link_libraries(pffft PUBLIC ${MATH_LIBS})
# Adding dependencies
set(SAPI_ROOT "../.." CACHE PATH "Path to the Sandboxed API source tree")
# Then configure:
# mkdir -p build && cd build
# cmake .. -G Ninja -DSAPI_ROOT=$HOME/sapi_root
set(SAPI_ENABLE_EXAMPLES OFF CACHE BOOL "")
set(SAPI_ENABLE_TESTS OFF CACHE BOOL "")
add_subdirectory("${SAPI_ROOT}"
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
# Omit this to have the full Sandboxed API in IDE
EXCLUDE_FROM_ALL)
add_sapi_library(pffft_sapi
FUNCTIONS pffft_new_setup
pffft_destroy_setup
pffft_transform
pffft_transform_ordered
pffft_zreorder
pffft_zconvolve_accumulate
pffft_aligned_malloc
pffft_aligned_free
pffft_simd_size
cffti
cfftf
cfftb
rffti
rfftf
rfftb
cosqi
cosqf
cosqb
costi
cost
sinqi
sinqb
sinqf
sinti
sint
INPUTS master/pffft.h master/fftpack.h
LIBRARY pffft
LIBRARY_NAME Pffft
NAMESPACE ""
)
target_include_directories(pffft_sapi INTERFACE
"${PROJECT_BINARY_DIR}"
)
add_executable(pffft_sandboxed
main_pffft_sandboxed.cc
)
target_link_libraries(pffft_sandboxed PRIVATE
pffft_sapi
sapi::sapi
)

View File

@ -0,0 +1,87 @@
# Sandboxing PFFFT library
Build System: CMake
OS: Linux
### Check out the PFFFT library & CMake set up
```
git submodule update --init --recursive
mkdir -p build && cd build
cmake .. -G Ninja -DPFFFT_ROOT_DIR=$PWD
ninjas
```
### For testing:
`cd build`, then `./pffft_sandboxed`
### For debug:
display custom info with
`./pffft_sandboxed --logtostderr`
## ***About the project***
*PFFFT library is concerned with 1D Fast-Fourier Transformations finding a
compromise between accuracy and speed. It deals with real and complex
vectors, both cases being illustrated in the testing part (`test_pffft.c`
for initially and original version, `main_pffft_sandboxed.cc` for our
currently implemented sandboxed version).
The original files can be found at: https://bitbucket.org/jpommier/pffft/src.*
*The purpose of sandboxing is to limit the permissions and capabilities of
librarys methods, in order to secure the usage of them.
After obtaining the sandbox, the functions will be called through an
Sandbox API (being called `api` in the current test) and so, the
operations, system calls or namspaces access may be controlled.
From both `pffft.h` and `fftpack.h` headers, useful methods are added to
sapi library builded with CMake. There is also a need to link math library
as the transformations made require mathematical operators.
Regarding the testing of the methods, one main is doing this job by
iterating through a set of values, that represents the accuracy of
transformations and print the speed for each value and type of
transformation. More specifically, the input length is the target for
accuracy (named as `n`) and it stands for the number of data points from
the series that calculate the result of transformation. It is also
important to mention that the `complex` variable stands for a boolean value
that tells the type of transformation (0 for REAL and 1 for COMPLEX) and
it is taken into account while testing.
In the end, the performance of PFFFT library it is outlined by the output.
There are two output formats available, from which you can choose through
`--output_format=` command-line flag.
Without using this type of argument when running, the output format is set
by default.*
#### CMake observations resume:
* linking pffft and fftpack (which contains necessary functions for pffft)
* set math library
#### Sandboxed main observations resume:
* containing two testing parts (fft / pffft benchmarks)
* showing the performance of the transformations implies
testing them through various FFT dimenstions.
Variable n, the input length, will take specific values
meaning the number of points to which it is set the calculus
(more details of mathematical purpose of n - https://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm).
* output shows speed depending on the input length
* use `--output_format=0` or `--output_format=1` arguments to choose between output formats.
`0` is for a detailed output, while `1` is only displaying each transformation process speed.
### Bugs history
1. [Solved] pffft benchmark bug: "Sandbox not active"
n = 64, status OK, `pffft_transform` generates error
n > 64, status not OK
Problem on initialising `sapi::StatusOr<PFFFT_Setup *> s;` the memory that stays
for s is not the same with the address passed in `pffft_transform` function.
(`sapi::v::GenericPtr` - to be changed)
Temporary solution: change the generated files to accept
`uintptr_t` instead of `PFFFT_Setup`
Solution: using `sapi::v::RemotePtr` instead of `sapi::v::GenericPtr`
to access the memory of object `s`
2. [Unresolved] compiling bug: "No space left on device"
The building process creates some `embed` files that use lots of
memory, trying to write them on `/tmp`.
Temporary solution: clean /tmp directory by `sudo rm -rf /tmp/*`

View File

@ -0,0 +1,207 @@
// 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.
#include <gflags/gflags.h>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <glog/logging.h>
#include "pffft_sapi.sapi.h" // NOLINT(build/include)
#include "sandboxed_api/util/flag.h"
#include "sandboxed_api/vars.h"
ABSL_DECLARE_FLAG(string, sandbox2_danger_danger_permit_all);
ABSL_DECLARE_FLAG(string, sandbox2_danger_danger_permit_all_and_log);
class PffftSapiSandbox : public PffftSandbox {
public:
std::unique_ptr<sandbox2::Policy> ModifyPolicy(sandbox2::PolicyBuilder*) {
return sandbox2::PolicyBuilder()
.AllowStaticStartup()
.AllowOpen()
.AllowRead()
.AllowWrite()
.AllowSystemMalloc()
.AllowExit()
.AllowSyscalls({
__NR_futex,
__NR_close,
__NR_getrusage,
})
.BuildOrDie();
}
};
// output_format flag determines whether the output shows information in detail
// or not. By default, the flag is set as 0, meaning an elaborate display
// (see ShowOutput method).
static bool ValidateFlag(const char* flagname, int32_t value) {
if (value >= 0 && value < 32768) {
return true;
}
LOG(ERROR) << "Invalid value for --" << flagname << ".";
return false;
}
DEFINE_int32(output_format, 0, "Value to specific the output format.");
DEFINE_validator(output_format, &ValidateFlag);
double UclockSec() { return static_cast<double>(clock()) / CLOCKS_PER_SEC; }
void ShowOutput(const char* name, int n, int complex, float flops, float t0,
float t1, int max_iter) {
float mflops = flops / 1e6 / (t1 - t0 + 1e-16);
if (FLAGS_output_format) {
if (flops != -1) {
printf("|%9.0f ", mflops);
} else {
printf("| n/a ");
}
} else if (flops != -1) {
printf("n=%5d, %s %16s : %6.0f MFlops [t=%6.0f ns, %d runs]\n", n,
(complex ? "CPLX" : "REAL"), name, mflops,
(t1 - t0) / 2 / max_iter * 1e9, max_iter);
}
fflush(stdout);
}
absl::Status PffftMain() {
LOG(INFO) << "Initializing sandbox...\n";
PffftSapiSandbox sandbox;
SAPI_RETURN_IF_ERROR(sandbox.Init());
PffftApi api(&sandbox);
// kTransformSizes is a vector keeping the values by which iterates n, its
// value representing the input length. More concrete, n is the number of data
// points the caclulus is up to (determinating its accuracy). To show the
// performance of Fast-Fourier Transformations the program is testing for
// various values of n.
constexpr int kTransformSizes[] = {
64, 96, 128, 160, 192, 256, 384, 5 * 96, 512, 5 * 128,
3 * 256, 800, 1024, 2048, 2400, 4096, 8192, 9 * 1024, 16384, 32768};
for (int complex : {0, 1}) {
for (int n : kTransformSizes) {
const int n_float = n * (complex ? 2 : 1);
int n_bytes = n_float * sizeof(float);
std::vector<float> work(2 * n_float + 15, 0.0);
sapi::v::Array<float> work_array(&work[0], work.size());
std::vector<float> x(n_bytes, 0.0);
sapi::v::Array<float> x_array(&x[0], x.size());
std::vector<float> y(n_bytes, 0.0);
sapi::v::Array<float> y_array(&y[0], y.size());
std::vector<float> z(n_bytes, 0.0);
sapi::v::Array<float> z_array(&z[0], z.size());
double t0;
double t1;
double flops;
int max_iter = 5120000 / n * 4;
for (int k = 0; k < n_float; ++k) {
x[k] = 0;
}
// FFTPack benchmark
{
// SIMD_SZ == 4 (returning value of pffft_simd_size())
int simd_size_iter = max_iter / 4;
if (simd_size_iter == 0) simd_size_iter = 1;
if (complex) {
SAPI_RETURN_IF_ERROR(api.cffti(n, work_array.PtrBoth()))
} else {
SAPI_RETURN_IF_ERROR(api.rffti(n, work_array.PtrBoth()));
}
t0 = UclockSec();
for (int iter = 0; iter < simd_size_iter; ++iter) {
if (complex) {
SAPI_RETURN_IF_ERROR(
api.cfftf(n, x_array.PtrBoth(), work_array.PtrBoth()));
SAPI_RETURN_IF_ERROR(
api.cfftb(n, x_array.PtrBoth(), work_array.PtrBoth()));
} else {
SAPI_RETURN_IF_ERROR(
api.rfftf(n, x_array.PtrBoth(), work_array.PtrBoth()));
SAPI_RETURN_IF_ERROR(
api.rfftb(n, x_array.PtrBoth(), work_array.PtrBoth()));
}
}
t1 = UclockSec();
flops = (simd_size_iter * 2) *
((complex ? 5 : 2.5) * static_cast<double>(n) *
log(static_cast<double>(n)) / M_LN2);
ShowOutput("FFTPack", n, complex, flops, t0, t1, simd_size_iter);
}
// PFFFT benchmark
{
SAPI_ASSIGN_OR_RETURN(
PFFFT_Setup * s,
api.pffft_new_setup(n, complex ? PFFFT_COMPLEX : PFFFT_REAL));
sapi::v::RemotePtr s_reg(s);
t0 = UclockSec();
for (int iter = 0; iter < max_iter; ++iter) {
SAPI_RETURN_IF_ERROR(
api.pffft_transform(&s_reg, x_array.PtrBoth(), z_array.PtrBoth(),
y_array.PtrBoth(), PFFFT_FORWARD));
SAPI_RETURN_IF_ERROR(
api.pffft_transform(&s_reg, x_array.PtrBoth(), z_array.PtrBoth(),
y_array.PtrBoth(), PFFFT_FORWARD));
}
t1 = UclockSec();
SAPI_RETURN_IF_ERROR(api.pffft_destroy_setup(&s_reg));
flops = (max_iter * 2) * ((complex ? 5 : 2.5) * static_cast<double>(n) *
log(static_cast<double>(n)) / M_LN2);
ShowOutput("PFFFT", n, complex, flops, t0, t1, max_iter);
LOG(INFO) << "n = " << n << " SUCCESSFULLY";
}
}
}
return absl::OkStatus();
}
int main(int argc, char* argv[]) {
// Initialize Google's logging library.
google::InitGoogleLogging(argv[0]);
gflags::ParseCommandLineFlags(&argc, &argv, true);
if (absl::Status status = PffftMain(); !status.ok()) {
LOG(ERROR) << "Initialization failed: " << status.ToString();
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@ -147,10 +147,10 @@ cc_library(
":var_type",
"//sandboxed_api/sandbox2:comms",
"//sandboxed_api/util:status",
"//sandboxed_api/util:statusor",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/synchronization",

View File

@ -43,6 +43,8 @@ add_library(sapi_embed_file STATIC
add_library(sapi::embed_file ALIAS sapi_embed_file)
target_link_libraries(sapi_embed_file PRIVATE
absl::flat_hash_map
absl::status
absl::statusor
absl::strings
absl::synchronization
glog::glog
@ -65,6 +67,8 @@ add_library(sapi::sapi ALIAS sapi_sapi)
target_link_libraries(sapi_sapi
PRIVATE absl::flat_hash_map
absl::memory
absl::status
absl::statusor
absl::str_format
absl::strings
absl::synchronization
@ -76,7 +80,6 @@ target_link_libraries(sapi_sapi
sandbox2::strerror
sandbox2::util
sapi::embed_file
sapi::status
sapi::vars
PUBLIC absl::core_headers
sandbox2::client
@ -137,6 +140,8 @@ add_library(sapi_vars STATIC
add_library(sapi::vars ALIAS sapi_vars)
target_link_libraries(sapi_vars PRIVATE
absl::core_headers
absl::status
absl::statusor
absl::str_format
absl::strings
absl::synchronization
@ -147,7 +152,6 @@ target_link_libraries(sapi_vars PRIVATE
sapi::lenval_core
sapi::proto_arg_proto
sapi::status
sapi::statusor
sapi::var_type
)
@ -178,6 +182,7 @@ if(SAPI_ENABLE_TESTS)
)
target_link_libraries(sapi_test PRIVATE
absl::memory
absl::status
benchmark
sapi::sapi
sapi::status

View File

@ -254,9 +254,8 @@ def sapi_library(
native.genrule(
name = name + ".isystem",
outs = [name + ".isystem.list"],
cmd = """echo |
$(CC) -E -x c++ - -v 2>&1 |
awk '/> search starts here:/{flag=1;next}/End of search/{flag=0}flag' > $@
cmd = """$(CC) -E -x c++ -v /dev/null 2>&1 |
awk '/> search starts here:/{f=1;next}/^End of search/{f=0}f{print $$1}' > $@
""",
toolchains = ["@bazel_tools//tools/cpp:current_cc_toolchain"],
)

View File

@ -34,9 +34,9 @@ def sapi_deps():
maybe(
http_archive,
name = "com_google_absl",
sha256 = "6668ada01192e2b95b42bb3668cfa5282c047de5176f5e567028e12f8bfb8aef", # 2020-04-28
strip_prefix = "abseil-cpp-6e18c7115df9b7ca0987cc346b1b1d4b3cc829b3",
urls = ["https://github.com/abseil/abseil-cpp/archive/6e18c7115df9b7ca0987cc346b1b1d4b3cc829b3.zip"],
sha256 = "8061df0ebbd3f599bcd3f5e57fb8003564d50a9b6a81a7f968fb0196b952365d", # 2020-09-02
strip_prefix = "abseil-cpp-0e9921b75a0fdd639a504ec8443fc1fe801becd7",
urls = ["https://github.com/abseil/abseil-cpp/archive/0e9921b75a0fdd639a504ec8443fc1fe801becd7.zip"],
)
maybe(
http_archive,

View File

@ -14,11 +14,11 @@
# Description: Sandboxed API reimplementation of zlib's zpipe.c example.
licenses(["notice"])
load("//sandboxed_api/bazel:build_defs.bzl", "sapi_platform_copts")
load("//sandboxed_api/bazel:sapi.bzl", "sapi_library")
licenses(["notice"])
sapi_library(
name = "zlib-sapi",
srcs = [],
@ -43,5 +43,6 @@ cc_binary(
"//sandboxed_api:vars",
"//sandboxed_api/util:flags",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/status:statusor",
],
)

View File

@ -32,11 +32,11 @@ add_executable(main_zlib
main_zlib.cc
)
target_link_libraries(main_zlib PRIVATE
absl::status
sapi::base
glog::glog
sapi::flags
sapi::sapi
sapi::status
sapi::statusor
sapi::zlib_sapi
)

View File

@ -20,6 +20,7 @@
#include <glog/logging.h>
#include "absl/base/macros.h"
#include "sandboxed_api/util/flag.h"
#include "absl/status/statusor.h"
#include "sandboxed_api/examples/zlib/zlib-sapi.sapi.h"
#include "sandboxed_api/examples/zlib/zlib-sapi_embed.h"
#include "sandboxed_api/vars.h"
@ -47,7 +48,7 @@ int main(int argc, char** argv) {
<< status.message();
}
sapi::StatusOr<int> ret;
absl::StatusOr<int> ret;
int flush;
unsigned have;
sapi::v::Struct<sapi::zlib::z_stream> strm;

View File

@ -22,13 +22,13 @@
#include <vector>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "sandboxed_api/proto_arg.pb.h"
#include "sandboxed_api/util/statusor.h"
namespace sapi {
template <typename T>
sapi::StatusOr<std::vector<uint8_t>> SerializeProto(const T& proto) {
absl::StatusOr<std::vector<uint8_t>> SerializeProto(const T& proto) {
static_assert(std::is_base_of<google::protobuf::Message, T>::value,
"Template argument must be a proto message");
// Wrap protobuf in a envelope so that we know the name of the protobuf
@ -46,7 +46,7 @@ sapi::StatusOr<std::vector<uint8_t>> SerializeProto(const T& proto) {
}
template <typename T>
sapi::StatusOr<T> DeserializeProto(const char* data, size_t len) {
absl::StatusOr<T> DeserializeProto(const char* data, size_t len) {
static_assert(std::is_base_of<google::protobuf::Message, T>::value,
"Template argument must be a proto message");
ProtoArg envelope;

View File

@ -15,6 +15,7 @@
#include "sandboxed_api/rpcchannel.h"
#include <glog/logging.h>
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/synchronization/mutex.h"
#include "sandboxed_api/call.h"
@ -35,7 +36,7 @@ absl::Status RPCChannel::Call(const FuncCall& call, uint32_t tag, FuncRet* ret,
return absl::OkStatus();
}
sapi::StatusOr<FuncRet> RPCChannel::Return(v::Type exp_type) {
absl::StatusOr<FuncRet> RPCChannel::Return(v::Type exp_type) {
uint32_t tag;
uint64_t len;
FuncRet ret;
@ -202,7 +203,7 @@ absl::Status RPCChannel::Close(int remote_fd) {
return absl::OkStatus();
}
sapi::StatusOr<uint64_t> RPCChannel::Strlen(void* str) {
absl::StatusOr<uint64_t> RPCChannel::Strlen(void* str) {
absl::MutexLock lock(&mutex_);
if (!comms_->SendTLV(comms::kMsgStrlen, sizeof(str),
reinterpret_cast<uint8_t*>(&str))) {

View File

@ -18,11 +18,11 @@
#include <cstddef>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/synchronization/mutex.h"
#include "sandboxed_api/call.h"
#include "sandboxed_api/sandbox2/comms.h"
#include "sandboxed_api/var_type.h"
#include "sandboxed_api/util/statusor.h"
namespace sapi {
@ -61,13 +61,13 @@ class RPCChannel {
absl::Status Close(int remote_fd);
// Returns length of a null-terminated c-style string (invokes strlen).
sapi::StatusOr<uint64_t> Strlen(void* str);
absl::StatusOr<uint64_t> Strlen(void* str);
sandbox2::Comms* comms() const { return comms_; }
private:
// Receives the result after a call.
sapi::StatusOr<FuncRet> Return(v::Type exp_type);
absl::StatusOr<FuncRet> Return(v::Type exp_type);
sandbox2::Comms* comms_; // Owned by sandbox2;
absl::Mutex mutex_;

View File

@ -84,7 +84,9 @@ void InitDefaultPolicyBuilder(sandbox2::PolicyBuilder* builder) {
__NR_kill,
__NR_tgkill,
__NR_tkill,
#ifdef __NR_readlink
__NR_readlink,
#endif
#ifdef __NR_arch_prctl // x86-64 only
__NR_arch_prctl,
#endif
@ -391,8 +393,8 @@ absl::Status Sandbox::TransferFromSandboxee(v::Var* var) {
return var->TransferFromSandboxee(GetRpcChannel(), pid());
}
sapi::StatusOr<std::string> Sandbox::GetCString(const v::RemotePtr& str,
uint64_t max_length) {
absl::StatusOr<std::string> Sandbox::GetCString(const v::RemotePtr& str,
uint64_t max_length) {
if (!is_active()) {
return absl::UnavailableError("Sandbox not active");
}

View File

@ -102,8 +102,9 @@ class Sandbox {
absl::Status TransferToSandboxee(v::Var* var);
absl::Status TransferFromSandboxee(v::Var* var);
sapi::StatusOr<std::string> GetCString(
const v::RemotePtr& str, uint64_t max_length = 10ULL << 20 /* 10 MiB*/
absl::StatusOr<std::string> GetCString(const v::RemotePtr& str,
uint64_t max_length = 10ULL
<< 20 /* 10 MiB*/
);
// Waits until the sandbox terminated and returns the result.

View File

@ -26,6 +26,13 @@ licenses(["notice"]) # Apache 2.0
exports_files(["testdata/hostname"])
cc_library(
name = "config",
hdrs = ["config.h"],
copts = sapi_platform_copts(),
deps = ["@com_google_absl//absl/base:config"],
)
cc_library(
name = "bpfdisassembler",
srcs = ["bpfdisassembler.cc"],
@ -40,6 +47,7 @@ cc_library(
hdrs = ["regs.h"],
copts = sapi_platform_copts(),
deps = [
":config",
":syscall",
":violation_cc_proto",
"//sandboxed_api/sandbox2/util:strerror",
@ -60,6 +68,7 @@ cc_library(
copts = sapi_platform_copts(),
visibility = ["//visibility:public"],
deps = [
":config",
":util",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
@ -73,6 +82,7 @@ cc_test(
srcs = ["syscall_test.cc"],
copts = sapi_platform_copts(),
deps = [
":config",
":syscall",
"@com_google_absl//absl/strings",
"@com_google_googletest//:gtest_main",
@ -85,12 +95,13 @@ cc_library(
hdrs = ["result.h"],
copts = sapi_platform_copts(),
deps = [
":config",
":regs",
":syscall",
":util",
"//sandboxed_api/util:statusor",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
],
)
@ -272,6 +283,7 @@ cc_library(
deps = [
":client",
":comms",
":config",
":executor",
":fork_client",
":forkserver_cc_proto",
@ -300,12 +312,12 @@ cc_library(
"//sandboxed_api/util:flags",
"//sandboxed_api/util:raw_logging",
"//sandboxed_api/util:status",
"//sandboxed_api/util:statusor",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/synchronization",
@ -374,9 +386,9 @@ cc_library(
"//sandboxed_api/sandbox2/util:fileops",
"//sandboxed_api/sandbox2/util:strerror",
"//sandboxed_api/util:raw_logging",
"//sandboxed_api/util:statusor",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
"@org_kernel_libcap//:libcap",
@ -404,6 +416,7 @@ cc_library(
hdrs = ["mounts.h"],
copts = sapi_platform_copts(),
deps = [
":config",
":mounttree_cc_proto",
"//sandboxed_api/sandbox2/util:file_base",
"//sandboxed_api/sandbox2/util:fileops",
@ -411,10 +424,10 @@ cc_library(
"//sandboxed_api/sandbox2/util:strerror",
"//sandboxed_api/util:raw_logging",
"//sandboxed_api/util:status",
"//sandboxed_api/util:statusor",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_protobuf//:protobuf",
],
@ -468,6 +481,7 @@ cc_test(
],
deps = [
":comms",
":config",
":namespace",
":sandbox2",
":testing",
@ -505,12 +519,13 @@ cc_library(
copts = sapi_platform_copts(),
visibility = ["//visibility:public"],
deps = [
":config",
"//sandboxed_api/sandbox2/util:file_base",
"//sandboxed_api/sandbox2/util:fileops",
"//sandboxed_api/sandbox2/util:strerror",
"//sandboxed_api/util:raw_logging",
"//sandboxed_api/util:statusor",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
],
@ -526,9 +541,9 @@ cc_library(
":util",
"//sandboxed_api/sandbox2/util:strerror",
"//sandboxed_api/util:status",
"//sandboxed_api/util:statusor",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
],
)
@ -541,6 +556,7 @@ cc_test(
deps = [
":buffer",
":comms",
":config",
":sandbox2",
":testing",
"//sandboxed_api/util:status_matchers",
@ -573,10 +589,10 @@ cc_library(
"//sandboxed_api/util:raw_logging",
"//sandboxed_api/util:status",
"//sandboxed_api/util:status_proto",
"//sandboxed_api/util:statusor",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/synchronization",
@ -629,6 +645,7 @@ cc_test(
copts = sapi_platform_copts(),
data = ["//sandboxed_api/sandbox2/testcases:limits"],
deps = [
":config",
":limits",
":sandbox2",
":testing",
@ -671,6 +688,7 @@ cc_test(
"//sandboxed_api/sandbox2/testcases:policy",
],
deps = [
":config",
":limits",
":regs",
":sandbox2",
@ -695,6 +713,7 @@ cc_test(
],
tags = ["local"],
deps = [
":config",
":sandbox2",
":testing",
"//sandboxed_api/sandbox2/util:bpf_helper",
@ -805,6 +824,7 @@ cc_test(
"//sandboxed_api/util:status_matchers",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_glog//:glog",
"@com_google_googletest//:gtest_main",

View File

@ -17,6 +17,16 @@ add_subdirectory(unwind)
add_subdirectory(util)
add_subdirectory(network_proxy)
# sandboxed_api/sandbox2:config
add_library(sandbox2_config STATIC
config.h
)
add_library(sandbox2::config ALIAS sandbox2_config)
target_link_libraries(sandbox2_config PRIVATE
absl::config
sapi::base
)
# sandboxed_api/sandbox2:bpfdisassembler
add_library(sandbox2_bpfdisassembler STATIC
bpfdisassembler.cc
@ -37,6 +47,7 @@ add_library(sandbox2::regs ALIAS sandbox2_regs)
target_link_libraries(sandbox2_regs PRIVATE
absl::core_headers
absl::strings
sandbox2::config
sandbox2::strerror
sandbox2::syscall
sandbox2::violation_proto
@ -72,6 +83,7 @@ target_link_libraries(sandbox2_result PRIVATE
absl::base
absl::memory
absl::strings
sandbox2::config
sandbox2::regs
sandbox2::syscall
sandbox2::util
@ -271,6 +283,8 @@ target_link_libraries(sandbox2_sandbox2
absl::flat_hash_set
absl::memory
absl::optional
absl::status
absl::statusor
absl::str_format
absl::strings
absl::synchronization
@ -278,6 +292,7 @@ target_link_libraries(sandbox2_sandbox2
sandbox2::bpf_helper
sandbox2::client
sandbox2::comms
sandbox2::config
sandbox2::executor
sandbox2::file_base
sandbox2::fileops
@ -300,7 +315,6 @@ target_link_libraries(sandbox2_sandbox2
sandbox2::util
sandbox2::violation_proto
sapi::base
sapi::statusor
PUBLIC sapi::flags
sapi::status
sandbox2::logsink
@ -351,6 +365,8 @@ add_library(sandbox2_forkserver STATIC
add_library(sandbox2::forkserver ALIAS sandbox2_forkserver)
target_link_libraries(sandbox2_forkserver PRIVATE
absl::memory
absl::status
absl::statusor
absl::str_format
absl::strings
libcap::libcap
@ -369,7 +385,6 @@ target_link_libraries(sandbox2_forkserver PRIVATE
sandbox2::util
sapi::base
sapi::raw_logging
sapi::statusor
)
# sandboxed_api/sandbox2:fork_client
@ -397,9 +412,11 @@ target_link_libraries(sandbox2_mounts PRIVATE
absl::core_headers
absl::flat_hash_set
absl::status
absl::statusor
absl::str_format
absl::strings
protobuf::libprotobuf
sandbox2::config
sandbox2::file_base
sandbox2::fileops
sandbox2::minielf
@ -408,7 +425,6 @@ target_link_libraries(sandbox2_mounts PRIVATE
sapi::base
sapi::raw_logging
sapi::status
sapi::statusor
)
# sandboxed_api/sandbox2:namespace
@ -458,13 +474,14 @@ target_link_libraries(sandbox2_util
PRIVATE absl::core_headers
absl::str_format
absl::strings
sandbox2::config
sandbox2::file_base
sandbox2::fileops
sandbox2::strerror
sapi::base
sapi::raw_logging
sapi::statusor
PUBLIC absl::status
absl::statusor
)
target_compile_options(sandbox2_util PRIVATE
# The default is 16384, however we need to do a clone with a
@ -482,12 +499,13 @@ add_library(sandbox2::buffer ALIAS sandbox2_buffer)
target_link_libraries(sandbox2_buffer PRIVATE
absl::core_headers
absl::memory
absl::status
absl::statusor
absl::strings
sandbox2::strerror
sandbox2::util
sapi::base
sapi::status
sapi::statusor
)
# sandboxed_api/sandbox2:forkserver_proto
@ -527,6 +545,8 @@ add_library(sandbox2_comms STATIC
add_library(sandbox2::comms ALIAS sandbox2_comms)
target_link_libraries(sandbox2_comms
PRIVATE absl::memory
absl::status
absl::statusor
absl::str_format
absl::strings
sandbox2::strerror
@ -534,7 +554,6 @@ target_link_libraries(sandbox2_comms
sapi::base
sapi::raw_logging
sapi::status_proto
sapi::statusor
PUBLIC absl::core_headers
absl::status
absl::synchronization
@ -566,6 +585,7 @@ if(SAPI_ENABLE_TESTS)
)
target_link_libraries(syscall_test PRIVATE
absl::strings
sandbox2::config
sandbox2::syscall
sapi::test_main
)
@ -604,6 +624,7 @@ if(SAPI_ENABLE_TESTS)
absl::memory
absl::strings
sandbox2::comms
sandbox2::config
sandbox2::fileops
sandbox2::namespace
sandbox2::sandbox2
@ -628,6 +649,7 @@ if(SAPI_ENABLE_TESTS)
absl::memory
sandbox2::buffer
sandbox2::comms
sandbox2::config
sandbox2::sandbox2
sandbox2::testing
sapi::status_matchers
@ -702,6 +724,7 @@ if(SAPI_ENABLE_TESTS)
target_link_libraries(limits_test PRIVATE
absl::memory
sandbox2::bpf_helper
sandbox2::config
sandbox2::limits
sandbox2::sandbox2
sandbox2::testing
@ -751,6 +774,7 @@ if(SAPI_ENABLE_TESTS)
absl::memory
absl::strings
sandbox2::bpf_helper
sandbox2::config
sandbox2::limits
sandbox2::regs
sandbox2::sandbox2
@ -776,6 +800,7 @@ if(SAPI_ENABLE_TESTS)
absl::memory
absl::strings
sandbox2::bpf_helper
sandbox2::config
sandbox2::sandbox2
sandbox2::testing
sapi::status_matchers
@ -832,6 +857,7 @@ if(SAPI_ENABLE_TESTS)
)
target_link_libraries(stack_trace_test PRIVATE
absl::memory
absl::status
absl::strings
sandbox2::bpf_helper
sandbox2::fileops

View File

@ -21,6 +21,7 @@
#include <cerrno>
#include "absl/memory/memory.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "sandboxed_api/sandbox2/util.h"
#include "sandboxed_api/sandbox2/util/strerror.h"
@ -28,7 +29,7 @@
namespace sandbox2 {
// Creates a new Buffer that is backed by the specified file descriptor.
sapi::StatusOr<std::unique_ptr<Buffer>> Buffer::CreateFromFd(int fd) {
absl::StatusOr<std::unique_ptr<Buffer>> Buffer::CreateFromFd(int fd) {
auto buffer = absl::WrapUnique(new Buffer{});
struct stat stat_buf;
@ -53,7 +54,7 @@ sapi::StatusOr<std::unique_ptr<Buffer>> Buffer::CreateFromFd(int fd) {
// Creates a new Buffer of the specified size, backed by a temporary file that
// will be immediately deleted.
sapi::StatusOr<std::unique_ptr<Buffer>> Buffer::CreateWithSize(int64_t size) {
absl::StatusOr<std::unique_ptr<Buffer>> Buffer::CreateWithSize(int64_t size) {
int fd;
if (!util::CreateMemFd(&fd)) {
return absl::InternalError("Could not create buffer temp file");

View File

@ -19,7 +19,7 @@
#include <cstdint>
#include <memory>
#include "sandboxed_api/util/statusor.h"
#include "absl/status/statusor.h"
namespace sandbox2 {
@ -37,11 +37,11 @@ class Buffer final {
// Creates a new Buffer that is backed by the specified file descriptor.
// The Buffer takes ownership of the descriptor and will close it when
// destroyed.
static sapi::StatusOr<std::unique_ptr<Buffer>> CreateFromFd(int fd);
static absl::StatusOr<std::unique_ptr<Buffer>> CreateFromFd(int fd);
// Creates a new Buffer of the specified size, backed by a temporary file that
// will be immediately deleted.
static sapi::StatusOr<std::unique_ptr<Buffer>> CreateWithSize(int64_t size);
static absl::StatusOr<std::unique_ptr<Buffer>> CreateWithSize(int64_t size);
// Returns a pointer to the buffer, which is read/write.
uint8_t* data() const { return buf_; }

View File

@ -29,6 +29,7 @@
#include "gtest/gtest.h"
#include "absl/memory/memory.h"
#include "sandboxed_api/sandbox2/comms.h"
#include "sandboxed_api/sandbox2/config.h"
#include "sandboxed_api/sandbox2/executor.h"
#include "sandboxed_api/sandbox2/ipc.h"
#include "sandboxed_api/sandbox2/policy.h"
@ -83,19 +84,20 @@ std::unique_ptr<Policy> BufferTestcasePolicy() {
.AllowSyscall(__NR_lseek)
.AllowSyscall(__NR_close)
.BlockSyscallWithErrno(__NR_prlimit64, EPERM)
#ifdef __NR_open
.BlockSyscallWithErrno(__NR_open, ENOENT)
#endif
.BlockSyscallWithErrno(__NR_openat, ENOENT)
#ifdef __NR_access
// On Debian, even static binaries check existence of
// /etc/ld.so.nohwcap.
.BlockSyscallWithErrno(__NR_access, ENOENT)
#endif
#ifdef __NR_faccessat
.BlockSyscallWithErrno(__NR_faccessat, ENOENT)
#endif
.BuildOrDie();
#if defined(__powerpc64__)
s2p->AllowUnsafeMmapFiles();
s2p->AllowUnsafeMmapShared();
#endif /* defined(__powerpc64__) */
return s2p;
}

View File

@ -36,6 +36,7 @@
#include "google/protobuf/message.h"
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/synchronization/mutex.h"
@ -44,7 +45,6 @@
#include "sandboxed_api/util/raw_logging.h"
#include "sandboxed_api/util/status.h"
#include "sandboxed_api/util/status_macros.h"
#include "sandboxed_api/util/statusor.h"
#ifdef MEMORY_SANITIZER
#include "base/dynamic_annotations.h"
@ -265,17 +265,16 @@ bool Comms::SendTLV(uint32_t tag, uint64_t length, const uint8_t* bytes) {
}
bool Comms::RecvString(std::string* v) {
TLV tlv;
if (!RecvTLV(&tlv)) {
uint32_t tag;
if (!RecvTLV(&tag, v)) {
return false;
}
if (tlv.tag != kTagString) {
if (tag != kTagString) {
SAPI_RAW_LOG(ERROR, "Expected (kTagString == 0x%x), got: 0x%x", kTagString,
tlv.tag);
tag);
return false;
}
v->assign(reinterpret_cast<const char*>(tlv.value.data()), tlv.value.size());
return true;
}
@ -285,16 +284,16 @@ bool Comms::SendString(const std::string& v) {
}
bool Comms::RecvBytes(std::vector<uint8_t>* buffer) {
TLV tlv;
if (!RecvTLV(&tlv)) {
uint32_t tag;
if (!RecvTLV(&tag, buffer)) {
return false;
}
if (tlv.tag != kTagBytes) {
if (tag != kTagBytes) {
buffer->clear();
SAPI_RAW_LOG(ERROR, "Expected (kTagBytes == 0x%x), got: 0x%u", kTagBytes,
tlv.tag);
tag);
return false;
}
buffer->swap(tlv.value);
return true;
}
@ -347,7 +346,7 @@ bool Comms::RecvFD(int* fd) {
const auto op = [&msg](int fd) -> ssize_t {
PotentiallyBlockingRegion region;
// Use syscall, otherwise we would need to whitelist socketcall() on PPC.
// Use syscall, otherwise we would need to allow socketcall() on PPC.
return TEMP_FAILURE_RETRY(
util::Syscall(__NR_recvmsg, fd, reinterpret_cast<uintptr_t>(&msg), 0));
};
@ -462,8 +461,9 @@ bool Comms::SendFD(int fd) {
}
bool Comms::RecvProtoBuf(google::protobuf::Message* message) {
TLV tlv;
if (!RecvTLV(&tlv)) {
uint32_t tag;
std::vector<uint8_t> bytes;
if (!RecvTLV(&tag, &bytes)) {
if (IsConnected()) {
SAPI_RAW_PLOG(ERROR, "RecvProtoBuf failed for (%s)", socket_name_);
} else {
@ -473,11 +473,11 @@ bool Comms::RecvProtoBuf(google::protobuf::Message* message) {
return false;
}
if (tlv.tag != kTagProto2) {
SAPI_RAW_LOG(ERROR, "Expected tag: 0x%x, got: 0x%u", kTagProto2, tlv.tag);
if (tag != kTagProto2) {
SAPI_RAW_LOG(ERROR, "Expected tag: 0x%x, got: 0x%u", kTagProto2, tag);
return false;
}
return message->ParseFromArray(tlv.value.data(), tlv.value.size());
return message->ParseFromArray(bytes.data(), bytes.size());
}
bool Comms::SendProtoBuf(const google::protobuf::Message& message) {
@ -599,18 +599,16 @@ bool Comms::RecvTL(uint32_t* tag, uint64_t* length) {
return true;
}
bool Comms::RecvTLV(TLV* tlv) {
absl::MutexLock lock(&tlv_recv_transmission_mutex_);
uint64_t length;
if (!RecvTL(&tlv->tag, &length)) {
return false;
}
tlv->value.resize(length);
return length == 0 || Recv(tlv->value.data(), length);
bool Comms::RecvTLV(uint32_t* tag, std::vector<uint8_t>* value) {
return RecvTLVGeneric(tag, value);
}
bool Comms::RecvTLV(uint32_t* tag, std::vector<uint8_t>* value) {
bool Comms::RecvTLV(uint32_t* tag, std::string* value) {
return RecvTLVGeneric(tag, value);
}
template <typename T>
bool Comms::RecvTLVGeneric(uint32_t* tag, T* value) {
absl::MutexLock lock(&tlv_recv_transmission_mutex_);
uint64_t length;
if (!RecvTL(tag, &length)) {
@ -618,7 +616,7 @@ bool Comms::RecvTLV(uint32_t* tag, std::vector<uint8_t>* value) {
}
value->resize(length);
return length == 0 || Recv(value->data(), length);
return length == 0 || Recv(reinterpret_cast<uint8_t*>(value->data()), length);
}
bool Comms::RecvTLV(uint32_t* tag, uint64_t* length, void* buffer,

View File

@ -109,6 +109,9 @@ class Comms {
// Receive a TLV structure, the memory for the value will be allocated
// by std::vector.
bool RecvTLV(uint32_t* tag, std::vector<uint8_t>* value);
// Receive a TLV structure, the memory for the value will be allocated
// by std::string.
bool RecvTLV(uint32_t* tag, std::string* value);
// Receives a TLV value into a specified buffer without allocating memory.
bool RecvTLV(uint32_t* tag, uint64_t* length, void* buffer, uint64_t buffer_size);
@ -174,12 +177,6 @@ class Comms {
// State of the channel (enum), socket will have to be connected later on.
State state_ = State::kUnconnected;
// TLV structure used to pass messages around.
struct TLV {
uint32_t tag;
std::vector<uint8_t> value;
};
// Special struct for passing credentials or FDs. Different from the one above
// as it inlines the value. This is important as the data is transmitted using
// sendmsg/recvmsg instead of send/recv.
@ -201,8 +198,9 @@ class Comms {
bool RecvTL(uint32_t* tag, uint64_t* length)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(tlv_recv_transmission_mutex_);
// Receives whole TLV structure, allocates memory for the data.
bool RecvTLV(TLV* tlv);
// T has to be a ContiguousContainer
template <typename T>
bool RecvTLVGeneric(uint32_t* tag, T* value);
// Receives arbitrary integers.
bool RecvInt(void* buffer, uint64_t len, uint32_t tag);

View File

@ -0,0 +1,85 @@
// 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.
#ifndef SANDBOXED_API_SANDBOX2_CONFIG_H_
#define SANDBOXED_API_SANDBOX2_CONFIG_H_
#include <cstdint>
#include "absl/base/config.h"
// GCC/Clang define __x86_64__, Visual Studio uses _M_X64
#if defined(__x86_64__) || defined(_M_X64)
#define SAPI_X86_64 1
// Check various spellings for 64-bit POWER. Not checking for Visual Studio, as
// it does not support 64-bit POWER.
#elif (defined(__PPC64__) || defined(__powerpc64__) || defined(__ppc64__)) && \
defined(ABSL_IS_LITTLE_ENDIAN)
#define SAPI_PPC64_LE 1
// Spellings for AArch64
#elif defined(__aarch64__) || defined(_M_ARM64)
#define SAPI_ARM64 1
#endif
namespace sandbox2 {
namespace cpu {
// CPU architectures known to Sandbox2
enum Architecture : uint16_t {
// Linux: Use a magic value, so it can be easily spotted in the seccomp-bpf
// bytecode decompilation stream. Must be < (1<<15), as/ that's the size of
// data which can be returned by BPF.
kUnknown = 0xCAF0,
kX8664,
kX86,
kPPC64LE,
kArm64,
};
} // namespace cpu
namespace host_cpu {
// Returns the current host CPU architecture if supported. If not supported,
// returns cpu::kUnknown.
constexpr cpu::Architecture Architecture() {
#if defined(SAPI_X86_64)
return cpu::kX8664;
#elif defined(SAPI_PPC64_LE)
return cpu::kPPC64LE;
#elif defined(SAPI_ARM64)
return cpu::kArm64;
#else
return cpu::kUnknown;
#endif
}
constexpr bool IsX8664() { return Architecture() == cpu::kX8664; }
constexpr bool IsPPC64LE() { return Architecture() == cpu::kPPC64LE; }
constexpr bool IsArm64() { return Architecture() == cpu::kArm64; }
} // namespace host_cpu
static_assert(host_cpu::Architecture() != cpu::kUnknown,
"Host CPU architecture is not supported: One of x86-64, POWER64 "
"(little endian) or AArch64 is required.");
} // namespace sandbox2
#endif // SANDBOXED_API_SANDBOX2_CONFIG_H_

View File

@ -27,7 +27,6 @@ cc_binary(
deps = [
"//sandboxed_api/sandbox2",
"//sandboxed_api/sandbox2:comms",
"//sandboxed_api/sandbox2/network_proxy:filtering",
"//sandboxed_api/sandbox2/util:bpf_helper",
"//sandboxed_api/sandbox2/util:fileops",
"//sandboxed_api/sandbox2/util:runfiles",
@ -48,7 +47,9 @@ cc_binary(
"//sandboxed_api/sandbox2/util:strerror",
"//sandboxed_api/util:flags",
"//sandboxed_api/util:status",
"//sandboxed_api/util:statusor",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
],
)

View File

@ -31,13 +31,14 @@ target_link_libraries(sandbox2_networkproxy_sandbox PRIVATE
sapi::flags
)
# sandboxed_api/sandbox2/examples/networkproxy:networkproxy_bin
add_executable(sandbox2_networkproxy_bin
networkproxy_bin.cc
)
add_executable(sandbox2::networkproxy_bin ALIAS sandbox2_networkproxy_bin)
target_link_libraries(sandbox2_networkproxy_bin PRIVATE
absl::status
absl::statusor
absl::str_format
glog::glog
gflags::gflags
@ -48,6 +49,4 @@ target_link_libraries(sandbox2_networkproxy_bin PRIVATE
sapi::base
sapi::flags
sapi::status
sapi::statusor
)

View File

@ -12,15 +12,16 @@
#include <cstring>
#include "sandboxed_api/util/flag.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "sandboxed_api/sandbox2/client.h"
#include "sandboxed_api/sandbox2/comms.h"
#include "sandboxed_api/sandbox2/network_proxy/client.h"
#include "sandboxed_api/sandbox2/util/fileops.h"
#include "sandboxed_api/sandbox2/util/strerror.h"
#include "sandboxed_api/util/status.h"
#include "sandboxed_api/util/status_macros.h"
#include "sandboxed_api/util/statusor.h"
ABSL_FLAG(bool, connect_with_handler, true, "Connect using automatic mode.");
@ -58,7 +59,7 @@ absl::Status CommunicationTest(int sock) {
return absl::OkStatus();
}
sapi::StatusOr<struct sockaddr_in6> CreateAddres(int port) {
absl::StatusOr<struct sockaddr_in6> CreateAddres(int port) {
static struct sockaddr_in6 saddr {};
saddr.sin6_family = AF_INET6;
saddr.sin6_port = htons(port);
@ -86,7 +87,7 @@ absl::Status ConnectWithHandler(int s, const struct sockaddr_in6& saddr) {
return absl::OkStatus();
}
sapi::StatusOr<int> ConnectToServer(int port) {
absl::StatusOr<int> ConnectToServer(int port) {
SAPI_ASSIGN_OR_RETURN(struct sockaddr_in6 saddr, CreateAddres(port));
sandbox2::file_util::fileops::FDCloser s(socket(AF_INET6, SOCK_STREAM, 0));
@ -134,7 +135,7 @@ int main(int argc, char** argv) {
return 2;
}
sapi::StatusOr<int> sock_s = ConnectToServer(port);
absl::StatusOr<int> sock_s = ConnectToServer(port);
if (!sock_s.ok()) {
LOG(ERROR) << sock_s.status().message();
return 3;

View File

@ -52,8 +52,10 @@ std::unique_ptr<sandbox2::Policy> GetPolicy() {
// Allow the getpid() syscall.
.AllowSyscall(__NR_getpid)
#ifdef __NR_access
// On Debian, even static binaries check existence of /etc/ld.so.nohwcap.
.BlockSyscallWithErrno(__NR_access, ENOENT)
#endif
// Examples for AddPolicyOnSyscall:
.AddPolicyOnSyscall(__NR_write,

View File

@ -86,7 +86,7 @@ pid_t Executor::StartSubProcess(int32_t clone_flags, const Namespace* ns,
if (!path_.empty()) {
exec_fd_ = open(path_.c_str(), O_PATH);
if (exec_fd_ < 0) {
LOG(ERROR) << "Could not open file " << path_;
PLOG(ERROR) << "Could not open file " << path_;
return -1;
}
}

View File

@ -36,6 +36,7 @@
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
@ -55,7 +56,6 @@
#include "sandboxed_api/sandbox2/util/fileops.h"
#include "sandboxed_api/sandbox2/util/strerror.h"
#include "sandboxed_api/util/raw_logging.h"
#include "sandboxed_api/util/statusor.h"
namespace {
// "Moves" the old FD to the new FD number.
@ -142,7 +142,7 @@ absl::Status SendPid(int signaling_fd) {
return absl::OkStatus();
}
sapi::StatusOr<pid_t> ReceivePid(int signaling_fd) {
absl::StatusOr<pid_t> ReceivePid(int signaling_fd) {
union {
struct cmsghdr cmh;
char ctrl[CMSG_SPACE(sizeof(struct ucred))];

View File

@ -23,6 +23,7 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/memory/memory.h"
#include "sandboxed_api/sandbox2/config.h"
#include "sandboxed_api/sandbox2/executor.h"
#include "sandboxed_api/sandbox2/policy.h"
#include "sandboxed_api/sandbox2/policybuilder.h"

View File

@ -49,6 +49,7 @@
#include "absl/time/time.h"
#include "sandboxed_api/sandbox2/client.h"
#include "sandboxed_api/sandbox2/comms.h"
#include "sandboxed_api/sandbox2/config.h"
#include "sandboxed_api/sandbox2/executor.h"
#include "sandboxed_api/sandbox2/limits.h"
#include "sandboxed_api/sandbox2/mounts.h"
@ -761,7 +762,7 @@ void Monitor::LogSyscallViolation(const Syscall& syscall) const {
void Monitor::EventPtraceSeccomp(pid_t pid, int event_msg) {
// If the seccomp-policy is using RET_TRACE, we request that it returns the
// syscall architecture identifier in the SECCOMP_RET_DATA.
const auto syscall_arch = static_cast<Syscall::CpuArch>(event_msg);
const auto syscall_arch = static_cast<cpu::Architecture>(event_msg);
Regs regs(pid);
auto status = regs.Fetch();
if (!status.ok()) {

View File

@ -27,19 +27,20 @@
#include "google/protobuf/util/message_differencer.h"
#include "absl/container/flat_hash_set.h"
#include "absl/status/statusor.h"
#include "absl/strings/ascii.h"
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "sandboxed_api/sandbox2/config.h"
#include "sandboxed_api/sandbox2/util/fileops.h"
#include "sandboxed_api/sandbox2/util/minielf.h"
#include "sandboxed_api/sandbox2/util/path.h"
#include "sandboxed_api/sandbox2/util/strerror.h"
#include "sandboxed_api/util/raw_logging.h"
#include "sandboxed_api/util/status_macros.h"
#include "sandboxed_api/util/statusor.h"
namespace sandbox2 {
namespace {
@ -97,7 +98,7 @@ absl::string_view GetOutsidePath(const MountTree::Node& node) {
}
}
sapi::StatusOr<std::string> ExistingPathInsideDir(
absl::StatusOr<std::string> ExistingPathInsideDir(
absl::string_view dir_path, absl::string_view relative_path) {
auto path = file::CleanPath(file::JoinPath(dir_path, relative_path));
if (file_util::fileops::StripBasename(path) != dir_path) {
@ -112,6 +113,8 @@ sapi::StatusOr<std::string> ExistingPathInsideDir(
absl::Status ValidateInterpreter(absl::string_view interpreter) {
const absl::flat_hash_set<std::string> allowed_interpreters = {
"/lib64/ld-linux-x86-64.so.2",
"/lib64/ld64.so.2", // PPC64
"/lib/ld-linux-aarch64.so.1", // AArch64
};
if (!allowed_interpreters.contains(interpreter)) {
@ -132,15 +135,21 @@ std::string ResolveLibraryPath(absl::string_view lib_name,
return "";
}
constexpr absl::string_view GetPlatformCPUName() {
switch (host_cpu::Architecture()) {
case cpu::kX8664:
return "x86_64";
case cpu::kPPC64LE:
return "ppc64";
case cpu::kArm64:
return "aarch64";
default:
return "unknown";
}
}
std::string GetPlatform(absl::string_view interpreter) {
#if defined(__x86_64__)
constexpr absl::string_view kCpuPlatform = "x86_64";
#elif defined(__powerpc64__)
constexpr absl::string_view kCpuPlatform = "ppc64";
#else
constexpr absl::string_view kCpuPlatform = "unknown";
#endif
return absl::StrCat(kCpuPlatform, "-linux-gnu");
return absl::StrCat(GetPlatformCPUName(), "-linux-gnu");
}
} // namespace
@ -496,7 +505,7 @@ std::string MountFlagsToString(uint64_t flags) {
SAPI_MAP(MS_POSIXACL),
SAPI_MAP(MS_UNBINDABLE),
SAPI_MAP(MS_PRIVATE),
SAPI_MAP(MS_SLAVE),
SAPI_MAP(MS_SLAVE), // Inclusive language: system constant
SAPI_MAP(MS_SHARED),
SAPI_MAP(MS_RELATIME),
SAPI_MAP(MS_KERNMOUNT),

View File

@ -28,6 +28,7 @@
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "sandboxed_api/sandbox2/comms.h"
#include "sandboxed_api/sandbox2/config.h"
#include "sandboxed_api/sandbox2/executor.h"
#include "sandboxed_api/sandbox2/policy.h"
#include "sandboxed_api/sandbox2/policybuilder.h"

View File

@ -30,6 +30,7 @@ cc_library(
"//sandboxed_api/sandbox2:comms",
"//sandboxed_api/sandbox2/util:fileops",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_glog//:glog",
],
@ -43,9 +44,11 @@ cc_library(
visibility = ["//visibility:public"],
deps = [
"//sandboxed_api/sandbox2:comms",
"//sandboxed_api/sandbox2:config",
"//sandboxed_api/sandbox2/util:strerror",
"//sandboxed_api/util:status",
"@com_google_absl//absl/memory",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/synchronization",
"@com_google_glog//:glog",
@ -61,7 +64,8 @@ cc_library(
"//sandboxed_api/sandbox2:comms",
"//sandboxed_api/sandbox2/util:strerror",
"//sandboxed_api/util:status",
"//sandboxed_api/util:statusor",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_glog//:glog",
],

View File

@ -33,14 +33,14 @@ add_library(sandbox2_network_proxy_filtering STATIC
filtering.h
)
add_library(sandbox2::network_proxy_filtering ALIAS sandbox2_network_proxy_filtering)
target_link_libraries(sandbox2_network_proxy_filtering PRIVATE
absl::memory
glog::glog
sandbox2::comms
sandbox2::fileops
sapi::base
target_link_libraries(sandbox2_network_proxy_filtering
PRIVATE absl::memory
absl::status
glog::glog
sandbox2::comms
sandbox2::fileops
sapi::base
PUBLIC sapi::status
sapi::statusor
)
# sandboxed_api/sandbox2/network_proxy:client
@ -54,6 +54,7 @@ target_link_libraries(sandbox2_network_proxy_client PRIVATE
absl::synchronization
glog::glog
sandbox2::comms
sandbox2::config
sandbox2::strerror
sapi::base
sapi::status

View File

@ -25,9 +25,10 @@
#include <glog/logging.h>
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "sandboxed_api/sandbox2/config.h"
#include "sandboxed_api/sandbox2/util/strerror.h"
#include "sandboxed_api/util/status.h"
#include "sandboxed_api/util/status_macros.h"
namespace sandbox2 {
@ -36,23 +37,26 @@ namespace sandbox2 {
constexpr int SYS_SECCOMP = 1;
#endif
#if defined(__x86_64__)
#if defined(SAPI_X86_64)
constexpr int kRegResult = REG_RAX;
constexpr int kRegSyscall = REG_RAX;
constexpr int kRegArg0 = REG_RDI;
constexpr int kRegArg1 = REG_RSI;
constexpr int kRegArg2 = REG_RDX;
#endif
#if defined(__powerpc64__)
#elif defined(SAPI_PPC64_LE)
constexpr int kRegResult = 3;
constexpr int kRegSyscall = 0;
constexpr int kRegArg0 = 3;
constexpr int kRegArg1 = 4;
constexpr int kRegArg2 = 5;
#elif defined(SAPI_ARM64)
constexpr int kRegResult = 0;
constexpr int kRegSyscall = 8;
constexpr int kRegArg0 = 0;
constexpr int kRegArg1 = 1;
constexpr int kRegArg2 = 2;
#endif
constexpr char NetworkProxyClient::kFDName[];
int NetworkProxyClient::ConnectHandler(int sockfd, const struct sockaddr* addr,
socklen_t addrlen) {
absl::Status status = Connect(sockfd, addr, addrlen);
@ -154,20 +158,22 @@ void NetworkProxyHandler::InvokeOldAct(int nr, siginfo_t* info,
void NetworkProxyHandler::ProcessSeccompTrap(int nr, siginfo_t* info,
void* void_context) {
ucontext_t* ctx = (ucontext_t*)(void_context);
if (info->si_code != SYS_SECCOMP) {
InvokeOldAct(nr, info, void_context);
return;
}
if (!ctx) return;
auto* ctx = static_cast<ucontext_t*>(void_context);
if (!ctx) {
return;
}
#if defined(__x86_64__)
#if defined(SAPI_X86_64)
auto* registers = ctx->uc_mcontext.gregs;
#elif defined(__powerpc64__)
#elif defined(SAPI_PPC64_LE)
auto* registers = ctx->uc_mcontext.gp_regs;
using ppc_gpreg_t = std::decay<decltype(registers[0])>::type;
#elif defined(SAPI_ARM64)
auto* registers = ctx->uc_mcontext.regs;
#endif
int syscall = registers[kRegSyscall];
int sockfd;
@ -178,14 +184,13 @@ void NetworkProxyHandler::ProcessSeccompTrap(int nr, siginfo_t* info,
sockfd = static_cast<int>(registers[kRegArg0]);
addr = reinterpret_cast<const struct sockaddr*>(registers[kRegArg1]);
addrlen = static_cast<socklen_t>(registers[kRegArg2]);
#if defined(__powerpc64__)
#if defined(SAPI_PPC64_LE)
} else if (syscall == __NR_socketcall &&
static_cast<int>(registers[kRegArg0]) == SYS_CONNECT) {
ppc_gpreg_t* args = reinterpret_cast<ppc_gpreg_t*>(registers[kRegArg1]);
sockfd = static_cast<int>(args[0]);
addr = reinterpret_cast<const struct sockaddr*>(args[1]);
addrlen = static_cast<socklen_t>(args[2]);
auto* connect_args = reinterpret_cast<uint64_t*>(registers[kRegArg1]);
sockfd = static_cast<int>(connect_args[0]);
addr = reinterpret_cast<const struct sockaddr*>(connect_args[1]);
addrlen = static_cast<socklen_t>(connect_args[2]);
#endif
} else {
InvokeOldAct(nr, info, void_context);

View File

@ -17,9 +17,9 @@
#include <netinet/in.h>
#include "absl/status/status.h"
#include "absl/synchronization/mutex.h"
#include "sandboxed_api/sandbox2/comms.h"
#include "sandboxed_api/util/status.h"
namespace sandbox2 {

View File

@ -17,16 +17,17 @@
#include <arpa/inet.h>
#include <glog/logging.h>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/numbers.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_split.h"
#include "sandboxed_api/sandbox2/util/strerror.h"
#include "sandboxed_api/util/status.h"
#include "sandboxed_api/util/status_macros.h"
namespace sandbox2 {
static sapi::StatusOr<std::string> Addr6ToString(
static absl::StatusOr<std::string> Addr6ToString(
const struct sockaddr_in6* saddr) {
char addr[INET6_ADDRSTRLEN];
int port = htons(saddr->sin6_port);
@ -38,7 +39,7 @@ static sapi::StatusOr<std::string> Addr6ToString(
}
// Converts sockaddr_in structure into a string IPv4 representation.
static sapi::StatusOr<std::string> Addr4ToString(
static absl::StatusOr<std::string> Addr4ToString(
const struct sockaddr_in* saddr) {
char addr[INET_ADDRSTRLEN];
int port = htons(saddr->sin_port);
@ -50,7 +51,7 @@ static sapi::StatusOr<std::string> Addr4ToString(
}
// Converts sockaddr_in6 structure into a string IPv6 representation.
sapi::StatusOr<std::string> AddrToString(const struct sockaddr* saddr) {
absl::StatusOr<std::string> AddrToString(const struct sockaddr* saddr) {
switch (saddr->sa_family) {
case AF_INET:
return Addr4ToString(reinterpret_cast<const struct sockaddr_in*>(saddr));

View File

@ -19,14 +19,14 @@
#include <memory>
#include "absl/status/statusor.h"
#include "sandboxed_api/sandbox2/comms.h"
#include "sandboxed_api/util/statusor.h"
namespace sandbox2 {
// Converts sockaddr_in or sockaddr_in6 structure into a string
// representation.
sapi::StatusOr<std::string> AddrToString(const struct sockaddr* saddr);
absl::StatusOr<std::string> AddrToString(const struct sockaddr* saddr);
struct IPv4 {
in_addr_t ip;

View File

@ -26,6 +26,7 @@
#include <glog/logging.h>
#include "absl/memory/memory.h"
#include "absl/status/statusor.h"
#include "sandboxed_api/sandbox2/util/fileops.h"
namespace sandbox2 {
@ -104,7 +105,7 @@ void NetworkProxyServer::NotifySuccess() {
}
void NetworkProxyServer::NotifyViolation(const struct sockaddr* saddr) {
if (sapi::StatusOr<std::string> result = AddrToString(saddr); result.ok()) {
if (absl::StatusOr<std::string> result = AddrToString(saddr); result.ok()) {
violation_msg_ = std::move(result).value();
} else {
violation_msg_ = std::string(result.status().message());

View File

@ -49,8 +49,12 @@ std::unique_ptr<Policy> NotifyTestcasePolicy() {
.AllowWrite()
.AllowSyscall(__NR_close)
.AddPolicyOnSyscall(__NR_personality, {SANDBOX2_TRACE})
#ifdef __NR_open
.BlockSyscallWithErrno(__NR_open, ENOENT)
#endif
#ifdef __NR_access
.BlockSyscallWithErrno(__NR_access, ENOENT)
#endif
.BlockSyscallWithErrno(__NR_openat, ENOENT)
.BlockSyscallWithErrno(__NR_prlimit64, EPERM)
.BuildOrDie();

View File

@ -82,41 +82,41 @@ std::vector<sock_filter> Policy::GetDefaultPolicy() const {
bpf_labels l = {0};
std::vector<sock_filter> policy = {
// If compiled arch is different than the runtime one, inform the Monitor.
LOAD_ARCH,
JEQ32(Syscall::GetHostAuditArch(), JUMP(&l, past_arch_check_l)),
JEQ32(AUDIT_ARCH_X86_64, TRACE(Syscall::kX86_64)),
JEQ32(AUDIT_ARCH_I386, TRACE(Syscall::kX86_32)),
JEQ32(AUDIT_ARCH_PPC64LE, TRACE(Syscall::kPPC_64)),
TRACE(Syscall::kUnknown),
LABEL(&l, past_arch_check_l),
// If compiled arch is different than the runtime one, inform the Monitor.
LOAD_ARCH,
JEQ32(Syscall::GetHostAuditArch(), JUMP(&l, past_arch_check_l)),
#if defined(SAPI_X86_64)
JEQ32(AUDIT_ARCH_I386, TRACE(cpu::kX86)), // 32-bit sandboxee
#endif
TRACE(cpu::kUnknown),
LABEL(&l, past_arch_check_l),
// After the policy is uploaded, forkserver will execve the sandboxee. We
// need to allow this execve but not others. Since BPF does not have
// state, we need to inform the Monitor to decide, and for that we use a
// magic value in syscall args 5. Note that this value is not supposed to
// be secret, but just an optimization so that the monitor is not
// triggered on every call to execveat.
LOAD_SYSCALL_NR,
JNE32(__NR_execveat, JUMP(&l, past_execveat_l)),
ARG_32(4),
JNE32(AT_EMPTY_PATH, JUMP(&l, past_execveat_l)),
ARG_32(5),
JNE32(internal::kExecveMagic, JUMP(&l, past_execveat_l)),
SANDBOX2_TRACE,
LABEL(&l, past_execveat_l),
// After the policy is uploaded, forkserver will execve the sandboxee. We
// need to allow this execve but not others. Since BPF does not have
// state, we need to inform the Monitor to decide, and for that we use a
// magic value in syscall args 5. Note that this value is not supposed to
// be secret, but just an optimization so that the monitor is not
// triggered on every call to execveat.
LOAD_SYSCALL_NR,
JNE32(__NR_execveat, JUMP(&l, past_execveat_l)),
ARG_32(4),
JNE32(AT_EMPTY_PATH, JUMP(&l, past_execveat_l)),
ARG_32(5),
JNE32(internal::kExecveMagic, JUMP(&l, past_execveat_l)),
SANDBOX2_TRACE,
LABEL(&l, past_execveat_l),
// Forbid some syscalls because unsafe or too risky.
LOAD_SYSCALL_NR,
JEQ32(__NR_ptrace, DENY),
JEQ32(__NR_bpf, DENY),
// Forbid some syscalls because unsafe or too risky.
LOAD_SYSCALL_NR,
JEQ32(__NR_ptrace, DENY),
JEQ32(__NR_bpf, DENY),
// Disallow clone with CLONE_UNTRACED flag.
JNE32(__NR_clone, JUMP(&l, past_clone_untraced_l)),
// Regardless of arch, we only care about the lower 32-bits of the flags.
ARG_32(0),
JA32(CLONE_UNTRACED, DENY),
LABEL(&l, past_clone_untraced_l),
// Disallow clone with CLONE_UNTRACED flag.
JNE32(__NR_clone, JUMP(&l, past_clone_untraced_l)),
// Regardless of arch, we only care about the lower 32-bits of the flags.
ARG_32(0),
JA32(CLONE_UNTRACED, DENY),
LABEL(&l, past_clone_untraced_l),
};
if (bpf_resolve_jumps(&l, policy.data(), policy.size()) != 0) {
@ -129,11 +129,16 @@ std::vector<sock_filter> Policy::GetDefaultPolicy() const {
std::vector<sock_filter> Policy::GetTrackingPolicy() const {
return {
LOAD_ARCH,
JEQ32(AUDIT_ARCH_X86_64, TRACE(Syscall::kX86_64)),
JEQ32(AUDIT_ARCH_I386, TRACE(Syscall::kX86_32)),
JEQ32(AUDIT_ARCH_PPC64LE, TRACE(Syscall::kPPC_64)),
TRACE(Syscall::kUnknown),
LOAD_ARCH,
#if defined(SAPI_X86_64)
JEQ32(AUDIT_ARCH_X86_64, TRACE(cpu::kX8664)),
JEQ32(AUDIT_ARCH_I386, TRACE(cpu::kX86)),
#elif defined(SAPI_PPC64_LE)
JEQ32(AUDIT_ARCH_PPC64LE, TRACE(cpu::kPPC64LE)),
#elif defined(SAPI_ARM64)
JEQ32(AUDIT_ARCH_AARCH64, TRACE(cpu::kArm64)),
#endif
TRACE(cpu::kUnknown),
};
}

View File

@ -25,6 +25,7 @@
#include "gtest/gtest.h"
#include "absl/memory/memory.h"
#include "absl/strings/string_view.h"
#include "sandboxed_api/sandbox2/config.h"
#include "sandboxed_api/sandbox2/executor.h"
#include "sandboxed_api/sandbox2/limits.h"
#include "sandboxed_api/sandbox2/policybuilder.h"
@ -49,14 +50,21 @@ std::unique_ptr<Policy> PolicyTestcasePolicy() {
.AllowSyscall(__NR_close)
.AllowSyscall(__NR_getppid)
.AllowTCGETS()
#ifdef __NR_open
.BlockSyscallWithErrno(__NR_open, ENOENT)
#endif
.BlockSyscallWithErrno(__NR_openat, ENOENT)
#ifdef __NR_access
.BlockSyscallWithErrno(__NR_access, ENOENT)
#endif
#ifdef __NR_faccessat
.BlockSyscallWithErrno(__NR_faccessat, ENOENT)
#endif
.BlockSyscallWithErrno(__NR_prlimit64, EPERM)
.BuildOrDie();
}
#if defined(__x86_64__)
#ifdef SAPI_X86_64
// Test that 32-bit syscalls from 64-bit are disallowed.
TEST(PolicyTest, AMD64Syscall32PolicyAllowed) {
SKIP_SANITIZERS_AND_COVERAGE;
@ -72,7 +80,7 @@ TEST(PolicyTest, AMD64Syscall32PolicyAllowed) {
ASSERT_THAT(result.final_status(), Eq(Result::VIOLATION));
EXPECT_THAT(result.reason_code(), Eq(1)); // __NR_exit in 32-bit
EXPECT_THAT(result.GetSyscallArch(), Eq(Syscall::kX86_32));
EXPECT_THAT(result.GetSyscallArch(), Eq(cpu::kX86));
}
// Test that 32-bit syscalls from 64-bit for FS checks are disallowed.
@ -90,9 +98,9 @@ TEST(PolicyTest, AMD64Syscall32FsAllowed) {
ASSERT_THAT(result.final_status(), Eq(Result::VIOLATION));
EXPECT_THAT(result.reason_code(),
Eq(33)); // __NR_access in 32-bit
EXPECT_THAT(result.GetSyscallArch(), Eq(Syscall::kX86_32));
EXPECT_THAT(result.GetSyscallArch(), Eq(cpu::kX86));
}
#endif // defined(__x86_64__)
#endif
// Test that ptrace(2) is disallowed.
TEST(PolicyTest, PtraceDisallowed) {
@ -161,7 +169,9 @@ std::unique_ptr<Policy> MinimalTestcasePolicy() {
.AllowStaticStartup()
.AllowExit()
.BlockSyscallWithErrno(__NR_prlimit64, EPERM)
#ifdef __NR_access
.BlockSyscallWithErrno(__NR_access, ENOENT)
#endif
.BuildOrDie();
}
@ -196,8 +206,10 @@ TEST(MinimalTest, MinimalSharedBinaryWorks) {
.AllowOpen()
.AllowExit()
.AllowMmap()
#ifdef __NR_access
// New glibc accesses /etc/ld.so.preload
.BlockSyscallWithErrno(__NR_access, ENOENT)
#endif
.BlockSyscallWithErrno(__NR_prlimit64, EPERM)
.AddLibrariesForBinary(path)
.BuildOrDie();
@ -222,7 +234,9 @@ TEST(MallocTest, SystemMallocWorks) {
.AllowSystemMalloc()
.AllowExit()
.BlockSyscallWithErrno(__NR_prlimit64, EPERM)
#ifdef __NR_access
.BlockSyscallWithErrno(__NR_access, ENOENT)
#endif
.BuildOrDie();
Sandbox2 s2(std::move(executor), std::move(policy));
@ -246,7 +260,9 @@ TEST(MultipleSyscalls, AddPolicyOnSyscallsWorks) {
auto policy =
PolicyBuilder()
#ifdef __NR_open
.BlockSyscallWithErrno(__NR_open, ENOENT)
#endif
.BlockSyscallWithErrno(__NR_openat, ENOENT)
.AllowStaticStartup()
.AllowTcMalloc()
@ -257,7 +273,9 @@ TEST(MultipleSyscalls, AddPolicyOnSyscallsWorks) {
.AddPolicyOnSyscalls({__NR_read, __NR_write}, {ERRNO(43)})
.AddPolicyOnSyscall(__NR_umask, {DENY})
.BlockSyscallWithErrno(__NR_prlimit64, EPERM)
#ifdef __NR_access
.BlockSyscallWithErrno(__NR_access, ENOENT)
#endif
.BuildOrDie();
Sandbox2 s2(std::move(executor), std::move(policy));

View File

@ -15,13 +15,7 @@
#include "sandboxed_api/sandbox2/policybuilder.h"
#include <asm/ioctls.h> // For TCGETS
#if defined(__x86_64__)
#include <asm/prctl.h>
#endif
#if defined(__powerpc64__)
#include <asm/termbits.h> // On PPC, TCGETS macro needs termios
#endif
#include <fcntl.h> // For the fcntl flags
#include <fcntl.h> // For the fcntl flags
#include <linux/futex.h>
#include <linux/net.h> // For SYS_CONNECT
#include <linux/random.h> // For GRND_NONBLOCK
@ -34,13 +28,21 @@
#include <utility>
#include "absl/memory/memory.h"
#include "absl/status/statusor.h"
#include "absl/strings/escaping.h"
#include "absl/strings/match.h"
#include "sandboxed_api/sandbox2/config.h"
#include "sandboxed_api/sandbox2/namespace.h"
#include "sandboxed_api/sandbox2/util/bpf_helper.h"
#include "sandboxed_api/sandbox2/util/path.h"
#include "sandboxed_api/util/status_macros.h"
#if defined(SAPI_X86_64)
#include <asm/prctl.h>
#elif defined(SAPI_PPC64_LE)
#include <asm/termbits.h> // On PPC, TCGETS macro needs termios
#endif
namespace sandbox2 {
namespace {
@ -510,7 +512,7 @@ PolicyBuilder& PolicyBuilder::AllowStaticStartup() {
JEQ32(SIG_UNBLOCK, ALLOW),
});
#if defined(__x86_64__)
#ifdef SAPI_X86_64
// The second argument is a pointer.
AddPolicyOnSyscall(__NR_arch_prctl, {
ARG_32(0),
@ -518,7 +520,12 @@ PolicyBuilder& PolicyBuilder::AllowStaticStartup() {
});
#endif
if constexpr (host_cpu::IsArm64()) {
BlockSyscallWithErrno(__NR_readlinkat, ENOENT);
}
#ifdef __NR_readlink
BlockSyscallWithErrno(__NR_readlink, ENOENT);
#endif
return *this;
}
@ -526,7 +533,11 @@ PolicyBuilder& PolicyBuilder::AllowStaticStartup() {
PolicyBuilder& PolicyBuilder::AllowDynamicStartup() {
AllowRead();
AllowStat();
AllowSyscalls({__NR_lseek, __NR_close, __NR_munmap});
AllowSyscalls({__NR_lseek,
#ifdef __NR__llseek
__NR__llseek, // Newer glibc on PPC
#endif
__NR_close, __NR_munmap});
AddPolicyOnSyscall(__NR_mprotect, {
ARG_32(2),
JEQ32(PROT_READ, ALLOW),
@ -656,7 +667,7 @@ PolicyBuilder& PolicyBuilder::DangerDefaultAllowAll() {
return *this;
}
sapi::StatusOr<std::string> PolicyBuilder::ValidateAbsolutePath(
absl::StatusOr<std::string> PolicyBuilder::ValidateAbsolutePath(
absl::string_view path) {
if (!file::IsAbsolutePath(path)) {
return absl::InvalidArgumentError(
@ -665,7 +676,7 @@ sapi::StatusOr<std::string> PolicyBuilder::ValidateAbsolutePath(
return ValidatePath(path);
}
sapi::StatusOr<std::string> PolicyBuilder::ValidatePath(
absl::StatusOr<std::string> PolicyBuilder::ValidatePath(
absl::string_view path) {
std::string fixed_path = file::CleanPath(path);
if (fixed_path != path) {
@ -686,7 +697,7 @@ std::vector<sock_filter> PolicyBuilder::ResolveBpfFunc(BpfFunc f) {
return policy;
}
sapi::StatusOr<std::unique_ptr<Policy>> PolicyBuilder::TryBuild() {
absl::StatusOr<std::unique_ptr<Policy>> PolicyBuilder::TryBuild() {
auto output = absl::WrapUnique(new Policy());
if (!last_status_.ok()) {
@ -879,7 +890,9 @@ PolicyBuilder& PolicyBuilder::AddNetworkProxyPolicy() {
AllowFutexOp(FUTEX_WAIT);
AllowFutexOp(FUTEX_WAIT_BITSET);
AllowSyscalls({
#ifdef __NR_dup2
__NR_dup2,
#endif
__NR_recvmsg,
__NR_close,
__NR_gettid,
@ -899,7 +912,7 @@ PolicyBuilder& PolicyBuilder::AddNetworkProxyPolicy() {
LABEL(&labels, getsockopt_end),
};
});
#if defined(__powerpc64__)
#ifdef SAPI_PPC64_LE
AddPolicyOnSyscall(__NR_socketcall, {
ARG_32(0),
JEQ32(SYS_SOCKET, ALLOW),
@ -925,7 +938,7 @@ PolicyBuilder& PolicyBuilder::AddNetworkProxyHandlerPolicy() {
});
AddPolicyOnSyscall(__NR_connect, {TRAP(0)});
#if defined(__powerpc64__)
#ifdef SAPI_PPC64_LE
AddPolicyOnSyscall(__NR_socketcall, {
ARG_32(0),
JEQ32(SYS_CONNECT, TRAP(0)),

View File

@ -29,18 +29,16 @@
#include <glog/logging.h>
#include "absl/base/macros.h"
#include "absl/memory/memory.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "sandboxed_api/sandbox2/mounts.h"
#include "sandboxed_api/sandbox2/network_proxy/filtering.h"
#include "sandboxed_api/sandbox2/policy.h"
#include "sandboxed_api/util/statusor.h"
struct bpf_labels;
namespace sandbox2 {
constexpr char kDefaultHostname[] = "sandbox2";
// PolicyBuilder is a helper class to simplify creation of policies. The builder
// uses fluent interface for convenience and increased readability of policies.
//
@ -91,6 +89,8 @@ constexpr char kDefaultHostname[] = "sandbox2";
// For a more complicated example, see examples/persistent/persistent_sandbox.cc
class PolicyBuilder final {
public:
static constexpr absl::string_view kDefaultHostname = "sandbox2";
using BpfInitializer = std::initializer_list<sock_filter>;
using BpfFunc = const std::function<std::vector<sock_filter>(bpf_labels&)>&;
using SyscallInitializer = std::initializer_list<unsigned int>;
@ -390,7 +390,7 @@ class PolicyBuilder final {
// Builds the policy returning a unique_ptr to it. This should only be called
// once.
sapi::StatusOr<std::unique_ptr<Policy>> TryBuild();
absl::StatusOr<std::unique_ptr<Policy>> TryBuild();
// Builds the policy returning a unique_ptr to it. This should only be called
// once.
@ -532,9 +532,9 @@ class PolicyBuilder final {
std::vector<sock_filter> ResolveBpfFunc(BpfFunc f);
static sapi::StatusOr<std::string> ValidateAbsolutePath(
static absl::StatusOr<std::string> ValidateAbsolutePath(
absl::string_view path);
static sapi::StatusOr<std::string> ValidatePath(absl::string_view path);
static absl::StatusOr<std::string> ValidatePath(absl::string_view path);
void StoreDescription(PolicyBuilderDescription* pb_description);
@ -542,7 +542,7 @@ class PolicyBuilder final {
bool use_namespaces_ = true;
bool requires_namespaces_ = false;
bool allow_unrestricted_networking_ = false;
std::string hostname_ = kDefaultHostname;
std::string hostname_ = std::string(kDefaultHostname);
bool collect_stacktrace_on_violation_ = true;
bool collect_stacktrace_on_signal_ = true;

View File

@ -24,6 +24,7 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/memory/memory.h"
#include "absl/status/statusor.h"
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_split.h"
@ -57,7 +58,7 @@ class PolicyBuilderPeer {
int policy_size() const { return builder_->user_policy_.size(); }
static sapi::StatusOr<std::string> ValidateAbsolutePath(
static absl::StatusOr<std::string> ValidateAbsolutePath(
absl::string_view path) {
return PolicyBuilder::ValidateAbsolutePath(path);
}
@ -100,7 +101,7 @@ TEST_F(PolicyBuilderTest, Testpolicy_size) {
builder.AllowSystemMalloc(); assert_increased();
builder.AllowSyscall(__NR_munmap); assert_same();
builder.BlockSyscallWithErrno(__NR_munmap, 1); assert_same();
builder.BlockSyscallWithErrno(__NR_open, 1);
builder.BlockSyscallWithErrno(__NR_openat, 1);
assert_increased();
builder.AllowTCGETS(); assert_increased();

View File

@ -23,65 +23,108 @@
#include <cerrno>
#include "absl/base/macros.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "sandboxed_api/sandbox2/config.h"
#include "sandboxed_api/sandbox2/util/strerror.h"
namespace sandbox2 {
absl::Status Regs::Fetch() {
#if defined(__powerpc64__)
iovec pt_iov = {&user_regs_, sizeof(user_regs_)};
#ifndef NT_ARM_SYSTEM_CALL
#define NT_ARM_SYSTEM_CALL 0x404
#endif
if (ptrace(PTRACE_GETREGSET, pid_, NT_PRSTATUS, &pt_iov) == -1L) {
return absl::InternalError(absl::StrCat(
"ptrace(PTRACE_GETREGSET, pid=", pid_, ") failed: ", StrError(errno)));
}
if (pt_iov.iov_len != sizeof(user_regs_)) {
return absl::InternalError(absl::StrCat(
"ptrace(PTRACE_GETREGSET, pid=", pid_,
") size returned: ", pt_iov.iov_len,
" different than sizeof(user_regs_): ", sizeof(user_regs_)));
}
#else
absl::Status Regs::Fetch() {
#ifdef SAPI_X86_64
if (ptrace(PTRACE_GETREGS, pid_, 0, &user_regs_) == -1L) {
return absl::InternalError(absl::StrCat("ptrace(PTRACE_GETREGS, pid=", pid_,
") failed: ", StrError(errno)));
}
#endif
if constexpr (host_cpu::IsPPC64LE() || host_cpu::IsArm64()) {
iovec pt_iov = {&user_regs_, sizeof(user_regs_)};
if (ptrace(PTRACE_GETREGSET, pid_, NT_PRSTATUS, &pt_iov) == -1L) {
return absl::InternalError(
absl::StrCat("ptrace(PTRACE_GETREGSET, pid=", pid_,
") failed: ", StrError(errno)));
}
if (pt_iov.iov_len != sizeof(user_regs_)) {
return absl::InternalError(absl::StrCat(
"ptrace(PTRACE_GETREGSET, pid=", pid_,
") size returned: ", pt_iov.iov_len,
" different than sizeof(user_regs_): ", sizeof(user_regs_)));
}
// On AArch64, we are not done yet. Read the syscall number.
if constexpr (host_cpu::IsArm64()) {
iovec sys_iov = {&syscall_number_, sizeof(syscall_number_)};
if (ptrace(PTRACE_GETREGSET, pid_, NT_ARM_SYSTEM_CALL, &sys_iov) == -1L) {
return absl::InternalError(
absl::StrCat("ptrace(PTRACE_GETREGSET, pid=", pid_,
", NT_ARM_SYSTEM_CALL) failed: ", StrError(errno)));
}
if (sys_iov.iov_len != sizeof(syscall_number_)) {
return absl::InternalError(absl::StrCat(
"ptrace(PTRACE_GETREGSET, pid=", pid_,
", NT_ARM_SYSTEM_CALL) size returned: ", sys_iov.iov_len,
" different than sizeof(syscall_number_): ",
sizeof(syscall_number_)));
}
}
}
return absl::OkStatus();
}
absl::Status Regs::Store() {
#if defined(__powerpc64__)
iovec pt_iov = {&user_regs_, sizeof(user_regs_)};
if (ptrace(PTRACE_SETREGSET, pid_, NT_PRSTATUS, &pt_iov) == -1L) {
return absl::InternalError(absl::StrCat(
"ptrace(PTRACE_SETREGSET, pid=", pid_, ") failed: ", StrError(errno)));
}
#else
#ifdef SAPI_X86_64
if (ptrace(PTRACE_SETREGS, pid_, 0, &user_regs_) == -1) {
return absl::InternalError(absl::StrCat("ptrace(PTRACE_SETREGS, pid=", pid_,
") failed: ", StrError(errno)));
}
#endif
if constexpr (host_cpu::IsPPC64LE() || host_cpu::IsArm64()) {
iovec pt_iov = {&user_regs_, sizeof(user_regs_)};
if (ptrace(PTRACE_SETREGSET, pid_, NT_PRSTATUS, &pt_iov) == -1L) {
return absl::InternalError(
absl::StrCat("ptrace(PTRACE_SETREGSET, pid=", pid_,
") failed: ", StrError(errno)));
}
// Store syscall number on AArch64.
if constexpr (host_cpu::IsArm64()) {
iovec sys_iov = {&syscall_number_, sizeof(syscall_number_)};
if (ptrace(PTRACE_SETREGSET, pid_, NT_ARM_SYSTEM_CALL, &sys_iov) == -1L) {
return absl::InternalError(
absl::StrCat("ptrace(PTRACE_SETREGSET, pid=", pid_,
", NT_ARM_SYSTEM_CALL) failed: ", StrError(errno)));
}
}
}
return absl::OkStatus();
}
absl::Status Regs::SkipSyscallReturnValue(uint64_t value) {
#if defined(__x86_64__)
#if defined(SAPI_X86_64)
user_regs_.orig_rax = -1;
user_regs_.rax = value;
#elif defined(__powerpc64__)
#elif defined(SAPI_PPC64_LE)
user_regs_.gpr[0] = -1;
user_regs_.gpr[3] = value;
#elif defined(SAPI_ARM64)
user_regs_.regs[0] = -1;
syscall_number_ = value;
#endif
return Store();
}
Syscall Regs::ToSyscall(Syscall::CpuArch syscall_arch) const {
#if defined(__x86_64__)
if (ABSL_PREDICT_TRUE(syscall_arch == Syscall::kX86_64)) {
Syscall Regs::ToSyscall(cpu::Architecture syscall_arch) const {
#if defined(SAPI_X86_64)
if (ABSL_PREDICT_TRUE(syscall_arch == cpu::kX8664)) {
auto syscall = user_regs_.orig_rax;
Syscall::Args args = {user_regs_.rdi, user_regs_.rsi, user_regs_.rdx,
user_regs_.r10, user_regs_.r8, user_regs_.r9};
@ -89,7 +132,7 @@ Syscall Regs::ToSyscall(Syscall::CpuArch syscall_arch) const {
auto ip = user_regs_.rip;
return Syscall(syscall_arch, syscall, args, pid_, sp, ip);
}
if (syscall_arch == Syscall::kX86_32) {
if (syscall_arch == cpu::kX86) {
auto syscall = user_regs_.orig_rax & 0xFFFFFFFF;
Syscall::Args args = {
user_regs_.rbx & 0xFFFFFFFF, user_regs_.rcx & 0xFFFFFFFF,
@ -99,8 +142,8 @@ Syscall Regs::ToSyscall(Syscall::CpuArch syscall_arch) const {
auto ip = user_regs_.rip & 0xFFFFFFFF;
return Syscall(syscall_arch, syscall, args, pid_, sp, ip);
}
#elif defined(__powerpc64__)
if (ABSL_PREDICT_TRUE(syscall_arch == Syscall::kPPC_64)) {
#elif defined(SAPI_PPC64_LE)
if (ABSL_PREDICT_TRUE(syscall_arch == cpu::kPPC64LE)) {
auto syscall = user_regs_.gpr[0];
Syscall::Args args = {user_regs_.orig_gpr3, user_regs_.gpr[4],
user_regs_.gpr[5], user_regs_.gpr[6],
@ -109,12 +152,28 @@ Syscall Regs::ToSyscall(Syscall::CpuArch syscall_arch) const {
auto ip = user_regs_.nip;
return Syscall(syscall_arch, syscall, args, pid_, sp, ip);
}
#elif defined(SAPI_ARM64)
if (ABSL_PREDICT_TRUE(syscall_arch == cpu::kArm64)) {
Syscall::Args args = {
// First argument should be orig_x0, which is not available to ptrace on
// AArch64 (see
// https://undo.io/resources/arm64-vs-arm32-whats-different-linux-programmers/),
// as it will have been overwritten. For our use case, though, using
// regs[0] is fine, as we are always called on syscall entry and never
// on exit.
user_regs_.regs[0], user_regs_.regs[1], user_regs_.regs[2],
user_regs_.regs[3], user_regs_.regs[4], user_regs_.regs[5],
};
auto sp = user_regs_.sp;
auto ip = user_regs_.pc;
return Syscall(syscall_arch, syscall_number_, args, pid_, sp, ip);
}
#endif
return Syscall(pid_);
}
void Regs::StoreRegisterValuesInProtobuf(RegisterValues* values) const {
#if defined(__x86_64__)
#if defined(SAPI_X86_64)
RegisterX8664* regs = values->mutable_register_x86_64();
regs->set_r15(user_regs_.r15);
regs->set_r14(user_regs_.r14);
@ -143,7 +202,7 @@ void Regs::StoreRegisterValuesInProtobuf(RegisterValues* values) const {
regs->set_es(user_regs_.es);
regs->set_fs(user_regs_.fs);
regs->set_gs(user_regs_.gs);
#elif defined(__powerpc64__)
#elif defined(SAPI_PPC64_LE)
RegisterPowerpc64* regs = values->mutable_register_powerpc64();
for (int i = 0; i < ABSL_ARRAYSIZE(user_regs_.gpr); ++i) {
regs->add_gpr(user_regs_.gpr[i]);
@ -164,6 +223,14 @@ void Regs::StoreRegisterValuesInProtobuf(RegisterValues* values) const {
regs->set_zero1(user_regs_.zero1);
regs->set_zero2(user_regs_.zero2);
regs->set_zero3(user_regs_.zero3);
#elif defined(SAPI_ARM64)
RegisterAarch64* regs = values->mutable_register_aarch64();
for (int i = 0; i < ABSL_ARRAYSIZE(user_regs_.regs); ++i) {
regs->add_regs(user_regs_.regs[i]);
}
regs->set_sp(user_regs_.sp);
regs->set_pc(user_regs_.pc);
regs->set_pstate(user_regs_.pstate);
#endif
}

View File

@ -24,6 +24,7 @@
#include <string>
#include "absl/status/status.h"
#include "sandboxed_api/sandbox2/config.h"
#include "sandboxed_api/sandbox2/syscall.h"
#include "sandboxed_api/sandbox2/violation.pb.h"
@ -33,10 +34,6 @@ namespace sandbox2 {
// assumes the process is already attached.
class Regs {
public:
#if !defined(__x86_64__) && !defined(__powerpc64__)
static_assert(false, "No support for the current CPU architecture");
#endif
explicit Regs(pid_t pid) : pid_(pid) {}
// Copies register values from the process
@ -49,7 +46,7 @@ class Regs {
absl::Status SkipSyscallReturnValue(uint64_t value);
// Converts raw register values obtained on syscall entry to syscall info
Syscall ToSyscall(Syscall::CpuArch syscall_arch) const;
Syscall ToSyscall(cpu::Architecture syscall_arch) const;
pid_t pid() const { return pid_; }
@ -60,7 +57,7 @@ class Regs {
friend class StackTracePeer;
struct PtraceRegisters {
#if defined(__x86_64__)
#if defined(SAPI_X86_64)
uint64_t r15;
uint64_t r14;
uint64_t r13;
@ -88,7 +85,7 @@ class Regs {
uint64_t es;
uint64_t fs;
uint64_t gs;
#elif defined(__powerpc64__)
#elif defined(SAPI_PPC64_LE)
uint64_t gpr[32];
uint64_t nip;
uint64_t msr;
@ -108,6 +105,13 @@ class Regs {
uint64_t zero1;
uint64_t zero2;
uint64_t zero3;
#elif defined(SAPI_ARM64)
uint64_t regs[31];
uint64_t sp;
uint64_t pc;
uint64_t pstate;
#else
static_assert(false, "Host CPU architecture not supported, see config.h");
#endif
};
@ -116,6 +120,9 @@ class Regs {
// Registers fetched with ptrace(PR_GETREGS/GETREGSET, pid).
PtraceRegisters user_regs_ = {};
// On AArch64, obtaining the syscall number needs a specific call to ptrace()
int syscall_number_ = 0;
};
} // namespace sandbox2

View File

@ -28,6 +28,7 @@
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "sandboxed_api/sandbox2/config.h"
#include "sandboxed_api/sandbox2/regs.h"
#include "sandboxed_api/sandbox2/syscall.h"
@ -131,8 +132,8 @@ class Result {
// Returns the current syscall architecture.
// Client architecture when final_status_ == VIOLATION, might be different
// from the host architecture (32-bit vs 64-bit syscalls).
Syscall::CpuArch GetSyscallArch() const {
return syscall_ ? syscall_->arch() : Syscall::kUnknown;
cpu::Architecture GetSyscallArch() const {
return syscall_ ? syscall_->arch() : cpu::kUnknown;
}
const std::vector<std::string> stack_trace() { return stack_trace_; }

View File

@ -21,6 +21,7 @@
#include <string>
#include "absl/memory/memory.h"
#include "absl/status/statusor.h"
#include "absl/time/time.h"
#include "sandboxed_api/sandbox2/monitor.h"
#include "sandboxed_api/sandbox2/result.h"
@ -33,7 +34,7 @@ Sandbox2::~Sandbox2() {
}
}
sapi::StatusOr<Result> Sandbox2::AwaitResultWithTimeout(
absl::StatusOr<Result> Sandbox2::AwaitResultWithTimeout(
absl::Duration timeout) {
CHECK(monitor_ != nullptr) << "Sandbox was not launched yet";
CHECK(monitor_thread_ != nullptr) << "Sandbox was already waited on";

View File

@ -26,6 +26,7 @@
#include <glog/logging.h>
#include "absl/base/macros.h"
#include "absl/memory/memory.h"
#include "absl/status/statusor.h"
#include "sandboxed_api/sandbox2/comms.h"
#include "sandboxed_api/sandbox2/executor.h"
#include "sandboxed_api/sandbox2/ipc.h"
@ -33,7 +34,6 @@
#include "sandboxed_api/sandbox2/notify.h"
#include "sandboxed_api/sandbox2/policy.h"
#include "sandboxed_api/sandbox2/result.h"
#include "sandboxed_api/util/statusor.h"
namespace sandbox2 {
@ -76,7 +76,7 @@ class Sandbox2 final {
// Waits for sandbox execution to finish within the timeout.
// Returns execution result or a DeadlineExceededError if the sandboxee does
// not finish in time.
sapi::StatusOr<Result> AwaitResultWithTimeout(absl::Duration timeout);
absl::StatusOr<Result> AwaitResultWithTimeout(absl::Duration timeout);
// Requests termination of the sandboxee.
// Sandbox should still waited with AwaitResult(), as it may finish for other

View File

@ -26,6 +26,7 @@
#include "gtest/gtest.h"
#include "absl/memory/memory.h"
#include "absl/strings/str_cat.h"
#include "sandboxed_api/sandbox2/config.h"
#include "sandboxed_api/sandbox2/executor.h"
#include "sandboxed_api/sandbox2/policy.h"
#include "sandboxed_api/sandbox2/policybuilder.h"

View File

@ -31,6 +31,7 @@
#include "absl/strings/strip.h"
#include "libcap/include/sys/capability.h"
#include "sandboxed_api/sandbox2/comms.h"
#include "sandboxed_api/sandbox2/config.h"
#include "sandboxed_api/sandbox2/executor.h"
#include "sandboxed_api/sandbox2/ipc.h"
#include "sandboxed_api/sandbox2/limits.h"
@ -85,6 +86,9 @@ std::unique_ptr<Policy> StackTracePeer::GetPolicy(pid_t target_pid,
// libunwind
.AllowSyscall(__NR_fstat)
.AllowSyscall(__NR_lseek)
#ifdef __NR__llseek
.AllowSyscall(__NR__llseek) // Newer glibc on PPC
#endif
.AllowSyscall(__NR_mincore)
.AllowSyscall(__NR_mprotect)
.AllowSyscall(__NR_munmap)
@ -270,6 +274,9 @@ bool StackTracePeer::LaunchLibunwindSandbox(const Regs* regs,
}
std::vector<std::string> GetStackTrace(const Regs* regs, const Mounts& mounts) {
if constexpr (host_cpu::IsArm64()) {
return {"[Stack traces unavailable]"};
}
if (absl::GetFlag(FLAGS_sandbox_disable_all_stack_traces)) {
return {"[Stacktraces disabled]"};
}

View File

@ -12,12 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
// Implementation of the sandbox2::Syscall class.
#include "sandboxed_api/sandbox2/syscall.h"
#include <linux/audit.h>
#include <linux/elf-em.h>
#include <climits>
#include <csignal>
#include <cstring>
@ -26,6 +25,7 @@
#include <glog/logging.h>
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
#include "sandboxed_api/sandbox2/config.h"
#include "sandboxed_api/sandbox2/syscall_defs.h"
#ifndef AUDIT_ARCH_PPC64LE
@ -34,46 +34,43 @@
namespace sandbox2 {
std::string Syscall::GetArchDescription(CpuArch arch) {
std::string Syscall::GetArchDescription(cpu::Architecture arch) {
switch (arch) {
case kX86_64:
case cpu::kX8664:
return "[X86-64]";
case kX86_32:
case cpu::kX86:
return "[X86-32]";
case kPPC_64:
case cpu::kPPC64LE:
return "[PPC-64]";
case cpu::kArm64:
return "[Arm-64]";
default:
LOG(ERROR) << "Unknown CPU architecture: " << arch;
return absl::StrFormat("[UNKNOWN_ARCH:%d]", arch);
}
}
Syscall::CpuArch Syscall::GetHostArch() {
#if defined(__x86_64__)
return kX86_64;
#elif defined(__i386__)
return kX86_32;
#elif defined(__powerpc64__)
return kPPC_64;
#endif
}
uint32_t Syscall::GetHostAuditArch() {
#if defined(__x86_64__)
return AUDIT_ARCH_X86_64;
#elif defined(__i386__)
return AUDIT_ARCH_I386;
#elif defined(__powerpc64__)
return AUDIT_ARCH_PPC64LE;
#endif
switch (host_cpu::Architecture()) {
case cpu::kX8664:
return AUDIT_ARCH_X86_64;
case cpu::kPPC64LE:
return AUDIT_ARCH_PPC64LE;
case cpu::kArm64:
return AUDIT_ARCH_AARCH64;
default:
// The static_assert() in config.h should prevent us from ever getting
// here.
return 0; // Not reached
}
}
std::string Syscall::GetName() const {
absl::string_view name = SyscallTable::get(arch_).GetName(nr_);
if (name.empty()) {
return absl::StrFormat("UNKNOWN[%d/0x%x]", nr_, nr_);
if (absl::string_view name = SyscallTable::get(arch_).GetName(nr_);
!name.empty()) {
return std::string(name);
}
return std::string(name);
return absl::StrFormat("UNKNOWN[%d/0x%x]", nr_, nr_);
}
std::vector<std::string> Syscall::GetArgumentsDescription() const {

View File

@ -13,7 +13,7 @@
// limitations under the License.
// The sandbox2::Syscalls class defines mostly static helper methods which
// are used to analyze status of the ptraced process
// are used to analyze the status of the sandboxed process.
#ifndef SANDBOXED_API_SANDBOX2_SYSCALL_H__
#define SANDBOXED_API_SANDBOX2_SYSCALL_H__
@ -26,40 +26,34 @@
#include <string>
#include <vector>
#include "sandboxed_api/sandbox2/config.h"
namespace sandbox2 {
class Syscall {
public:
// Supported CPU architectures.
// Linux: Use a magic value, so it can be easily spotted in the seccomp-bpf
// bytecode decompilation stream. Must be < (1<<15), as/ that's the size of
// data which can be returned by BPF.
enum CpuArch {
kUnknown = 0xCAF0,
kX86_64,
kX86_32,
kPPC_64,
};
// Maximum number of syscall arguments
static constexpr size_t kMaxArgs = 6;
using Args = std::array<uint64_t, kMaxArgs>;
// Returns the host architecture, according to CpuArch.
static CpuArch GetHostArch();
static constexpr cpu::Architecture GetHostArch() {
return host_cpu::Architecture();
}
// Returns the host architecture, according to <linux/audit.h>.
static uint32_t GetHostAuditArch();
// Returns a description of the architecture.
static std::string GetArchDescription(CpuArch arch);
static std::string GetArchDescription(cpu::Architecture arch);
Syscall() = default;
Syscall(CpuArch arch, uint64_t nr, Args args = {})
Syscall(cpu::Architecture arch, uint64_t nr, Args args = {})
: arch_(arch), nr_(nr), args_(args) {}
pid_t pid() const { return pid_; }
uint64_t nr() const { return nr_; }
CpuArch arch() const { return arch_; }
cpu::Architecture arch() const { return arch_; }
const Args& args() const { return args_; }
uint64_t stack_pointer() const { return sp_; }
uint64_t instruction_pointer() const { return ip_; }
@ -72,12 +66,12 @@ class Syscall {
private:
friend class Regs;
Syscall(pid_t pid) : pid_(pid) {}
Syscall(CpuArch arch, uint64_t nr, Args args, pid_t pid, uint64_t sp,
uint64_t ip)
explicit Syscall(pid_t pid) : pid_(pid) {}
Syscall(cpu::Architecture arch, uint64_t nr, Args args, pid_t pid,
uint64_t sp, uint64_t ip)
: arch_(arch), nr_(nr), args_(args), pid_(pid), sp_(sp), ip_(ip) {}
CpuArch arch_ = kUnknown;
cpu::Architecture arch_ = cpu::kUnknown;
uint64_t nr_ = -1;
Args args_ = {};
pid_t pid_ = -1;

View File

@ -7,6 +7,7 @@
#include "absl/strings/escaping.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "sandboxed_api/sandbox2/config.h"
#include "sandboxed_api/sandbox2/util.h"
namespace sandbox2 {
@ -128,7 +129,6 @@ std::vector<std::string> SyscallTable::GetArgumentsDescription(
#define SYSCALLS_UNUSED00_99(prefix) \
SYSCALLS_UNUSED00_49(prefix), SYSCALLS_UNUSED50_99(prefix)
#if defined(__x86_64__)
// Syscall description table for Linux x86_64
constexpr SyscallTable::Entry kSyscallDataX8664[] = {
MakeEntry("read", kInt, kHex, kInt), // 0
@ -824,12 +824,10 @@ constexpr SyscallTable::Entry kSyscallDataX8632[] = {
MakeEntry("bpf", kHex, kHex, kHex, kHex, kHex, kHex), // 357
};
#elif defined(__powerpc64__)
// http://lxr.free-electrons.com/source/arch/powerpc/include/uapi/asm/unistd.h
// Note: PPC64 syscalls can have up to 7 register arguments, but nobody is
// using the 7th argument - probably for x64 compatibility reasons.
constexpr SyscallTable::Entry kSyscallDataPPC64[] = {
constexpr SyscallTable::Entry kSyscallDataPPC64LE[] = {
MakeEntry("restart_syscall", kGen, kGen, kGen, kGen, kGen, kGen), // 0
MakeEntry("exit", kInt, kGen, kGen, kGen, kGen, kGen), // 1
MakeEntry("fork", kGen, kGen, kGen, kGen, kGen, kGen), // 2
@ -1218,7 +1216,290 @@ constexpr SyscallTable::Entry kSyscallDataPPC64[] = {
MakeEntry("pwritev2", kHex, kHex, kHex, kHex, kHex, kHex), // 381
};
#endif
// TODO(cblichmann): Confirm the entries in this list.
// https://github.com/torvalds/linux/blob/v5.8/include/uapi/asm-generic/unistd.h
constexpr SyscallTable::Entry kSyscallDataArm64[] = {
MakeEntry("io_setup", UnknownArguments()), // 0
MakeEntry("io_destroy", UnknownArguments()), // 1
MakeEntry("io_submit", UnknownArguments()), // 2
MakeEntry("io_cancel", UnknownArguments()), // 3
MakeEntry("io_getevents", UnknownArguments()), // 4
MakeEntry("setxattr", kPath, kString, kGen, kInt, kHex, kGen), // 5
MakeEntry("lsetxattr", kPath, kString, kGen, kInt, kHex, kGen), // 6
MakeEntry("fsetxattr", UnknownArguments()), // 7
MakeEntry("getxattr", kPath, kString, kGen, kInt, kGen, kGen), // 8
MakeEntry("lgetxattr", kPath, kString, kGen, kInt, kGen, kGen), // 9
MakeEntry("fgetxattr", UnknownArguments()), // 10
MakeEntry("listxattr", kPath, kGen, kInt, kGen, kGen, kGen), // 11
MakeEntry("llistxattr", kPath, kGen, kInt, kGen, kGen, kGen), // 12
MakeEntry("flistxattr", UnknownArguments()), // 13
MakeEntry("removexattr", kPath, kString, kGen, kGen, kGen, kGen), // 14
MakeEntry("lremovexattr", UnknownArguments()), // 15
MakeEntry("fremovexattr", UnknownArguments()), // 16
MakeEntry("getcwd", UnknownArguments()), // 17
MakeEntry("lookup_dcookie", UnknownArguments()), // 18
MakeEntry("eventfd2", UnknownArguments()), // 19
MakeEntry("epoll_create1", UnknownArguments()), // 20
MakeEntry("epoll_ctl", UnknownArguments()), // 21
MakeEntry("epoll_pwait", UnknownArguments()), // 22
MakeEntry("dup", UnknownArguments()), // 23
MakeEntry("dup3", UnknownArguments()), // 24
MakeEntry("fcntl", UnknownArguments()), // 25
MakeEntry("inotify_init1", UnknownArguments()), // 26
MakeEntry("inotify_add_watch", UnknownArguments()), // 27
MakeEntry("inotify_rm_watch", UnknownArguments()), // 28
MakeEntry("ioctl", UnknownArguments()), // 29
MakeEntry("ioprio_set", UnknownArguments()), // 30
MakeEntry("ioprio_get", UnknownArguments()), // 31
MakeEntry("flock", UnknownArguments()), // 32
MakeEntry("mknodat", kGen, kPath, kGen, kGen, kGen, kGen), // 33
MakeEntry("mkdirat", kGen, kPath, kGen, kGen, kGen, kGen), // 34
MakeEntry("unlinkat", kGen, kPath, kGen, kGen, kGen, kGen), // 35
MakeEntry("symlinkat", kPath, kGen, kPath, kGen, kGen, kGen), // 36
MakeEntry("linkat", kGen, kPath, kGen, kPath, kGen, kGen), // 37
MakeEntry("renameat", kGen, kPath, kGen, kPath, kGen, kGen), // 38
MakeEntry("umount2", kPath, kHex, kGen, kGen, kGen, kGen), // 39
MakeEntry("mount", kPath, kPath, kString, kHex, kGen, kGen), // 40
MakeEntry("pivot_root", kPath, kPath, kGen, kGen, kGen, kGen), // 41
MakeEntry("nfsservctl", UnknownArguments()), // 42
MakeEntry("statfs", kPath, kGen, kGen, kGen, kGen, kGen), // 43
MakeEntry("fstatfs", UnknownArguments()), // 44
MakeEntry("truncate", kPath, kInt, kGen, kGen, kGen, kGen), // 45
MakeEntry("ftruncate", UnknownArguments()), // 46
MakeEntry("fallocate", UnknownArguments()), // 47
MakeEntry("faccessat", kGen, kPath, kGen, kGen, kGen, kGen), // 48
MakeEntry("chdir", kPath, kGen, kGen, kGen, kGen, kGen), // 49
MakeEntry("fchdir", UnknownArguments()), // 50
MakeEntry("chroot", kPath, kGen, kGen, kGen, kGen, kGen), // 51
MakeEntry("fchmod", UnknownArguments()), // 52
MakeEntry("fchmodat", kGen, kPath, kGen, kGen, kGen, kGen), // 53
MakeEntry("fchownat", kGen, kPath, kGen, kGen, kGen, kGen), // 54
MakeEntry("fchown", UnknownArguments()), // 55
MakeEntry("openat", kGen, kPath, kOct, kHex, kGen, kGen), // 56
MakeEntry("close", kInt, kGen, kGen, kGen, kGen, kGen), // 57
MakeEntry("vhangup", UnknownArguments()), // 58
MakeEntry("pipe2", UnknownArguments()), // 59
MakeEntry("quotactl", kInt, kPath, kInt, kGen, kGen, kGen), // 60
MakeEntry("getdents64", UnknownArguments()), // 61
MakeEntry("lseek", UnknownArguments()), // 62
MakeEntry("read", kInt, kHex, kInt, kGen, kGen, kGen), // 63
MakeEntry("write", kInt, kHex, kInt, kGen, kGen, kGen), // 64
MakeEntry("readv", UnknownArguments()), // 65
MakeEntry("writev", UnknownArguments()), // 66
MakeEntry("pread64", UnknownArguments()), // 67
MakeEntry("pwrite64", UnknownArguments()), // 68
MakeEntry("preadv", UnknownArguments()), // 69
MakeEntry("pwritev", UnknownArguments()), // 70
MakeEntry("sendfile", UnknownArguments()), // 71
MakeEntry("pselect6", UnknownArguments()), // 72
MakeEntry("ppoll", UnknownArguments()), // 73
MakeEntry("signalfd4", UnknownArguments()), // 74
MakeEntry("vmsplice", UnknownArguments()), // 75
MakeEntry("splice", UnknownArguments()), // 76
MakeEntry("tee", UnknownArguments()), // 77
MakeEntry("readlinkat", kGen, kPath, kGen, kGen, kGen, kGen), // 78
MakeEntry("newfstatat", kGen, kPath, kGen, kGen, kGen, kGen), // 79
MakeEntry("fstat", kInt, kHex, kGen, kGen, kGen, kGen), // 80
MakeEntry("sync", UnknownArguments()), // 81
MakeEntry("fsync", UnknownArguments()), // 82
MakeEntry("fdatasync", UnknownArguments()), // 83
MakeEntry("sync_file_range", UnknownArguments()), // 84
MakeEntry("timerfd_create", UnknownArguments()), // 85
MakeEntry("timerfd_settime", UnknownArguments()), // 86
MakeEntry("timerfd_gettime", UnknownArguments()), // 87
MakeEntry("utimensat", UnknownArguments()), // 88
MakeEntry("acct", kPath, kGen, kGen, kGen, kGen, kGen), // 89
MakeEntry("capget", UnknownArguments()), // 90
MakeEntry("capset", UnknownArguments()), // 91
MakeEntry("personality", UnknownArguments()), // 92
MakeEntry("exit", kInt, kGen, kGen, kGen, kGen, kGen), // 93
MakeEntry("exit_group", kInt, kGen, kGen, kGen, kGen, kGen), // 94
MakeEntry("waitid", UnknownArguments()), // 95
MakeEntry("set_tid_address", kHex, kGen, kGen, kGen, kGen, kGen), // 96
MakeEntry("unshare", UnknownArguments()), // 97
MakeEntry("futex", UnknownArguments()), // 98
MakeEntry("set_robust_list", UnknownArguments()), // 99
MakeEntry("get_robust_list", UnknownArguments()), // 100
MakeEntry("nanosleep", kHex, kHex, kGen, kGen, kGen, kGen), // 101
MakeEntry("getitimer", UnknownArguments()), // 102
MakeEntry("setitimer", UnknownArguments()), // 103
MakeEntry("kexec_load", UnknownArguments()), // 104
MakeEntry("init_module", UnknownArguments()), // 105
MakeEntry("delete_module", UnknownArguments()), // 106
MakeEntry("timer_create", UnknownArguments()), // 107
MakeEntry("timer_gettime", UnknownArguments()), // 108
MakeEntry("timer_getoverrun", UnknownArguments()), // 109
MakeEntry("timer_settime", UnknownArguments()), // 110
MakeEntry("timer_delete", UnknownArguments()), // 111
MakeEntry("clock_settime", UnknownArguments()), // 112
MakeEntry("clock_gettime", UnknownArguments()), // 113
MakeEntry("clock_getres", UnknownArguments()), // 114
MakeEntry("clock_nanosleep", UnknownArguments()), // 115
MakeEntry("syslog", UnknownArguments()), // 116
MakeEntry("ptrace", UnknownArguments()), // 117
MakeEntry("sched_setparam", UnknownArguments()), // 118
MakeEntry("sched_setscheduler", UnknownArguments()), // 119
MakeEntry("sched_getscheduler", UnknownArguments()), // 120
MakeEntry("sched_getparam", UnknownArguments()), // 121
MakeEntry("sched_setaffinity", UnknownArguments()), // 122
MakeEntry("sched_getaffinity", UnknownArguments()), // 123
MakeEntry("sched_yield", UnknownArguments()), // 124
MakeEntry("sched_get_priority_max", UnknownArguments()), // 125
MakeEntry("sched_get_priority_min", UnknownArguments()), // 126
MakeEntry("sched_rr_get_interval", UnknownArguments()), // 127
MakeEntry("restart_syscall", UnknownArguments()), // 128
MakeEntry("kill", kInt, kSignal, kGen, kGen, kGen, kGen), // 129
MakeEntry("tkill", kInt, kSignal, kGen, kGen, kGen, kGen), // 130
MakeEntry("tgkill", kInt, kInt, kSignal, kGen, kGen, kGen), // 131
MakeEntry("sigaltstack", UnknownArguments()), // 132
MakeEntry("rt_sigsuspend", UnknownArguments()), // 133
MakeEntry("rt_sigaction", kSignal, kHex, kHex, kInt, kGen, kGen), // 134
MakeEntry("rt_sigprocmask", UnknownArguments()), // 135
MakeEntry("rt_sigpending", UnknownArguments()), // 136
MakeEntry("rt_sigtimedwait", UnknownArguments()), // 137
MakeEntry("rt_sigqueueinfo", UnknownArguments()), // 138
MakeEntry("rt_sigreturn", UnknownArguments()), // 139
MakeEntry("setpriority", UnknownArguments()), // 140
MakeEntry("getpriority", UnknownArguments()), // 141
MakeEntry("reboot", UnknownArguments()), // 142
MakeEntry("setregid", UnknownArguments()), // 143
MakeEntry("setgid", UnknownArguments()), // 144
MakeEntry("setreuid", UnknownArguments()), // 145
MakeEntry("setuid", UnknownArguments()), // 146
MakeEntry("setresuid", UnknownArguments()), // 147
MakeEntry("getresuid", UnknownArguments()), // 148
MakeEntry("setresgid", UnknownArguments()), // 149
MakeEntry("getresgid", UnknownArguments()), // 150
MakeEntry("setfsuid", UnknownArguments()), // 151
MakeEntry("setfsgid", UnknownArguments()), // 152
MakeEntry("times", UnknownArguments()), // 153
MakeEntry("setpgid", UnknownArguments()), // 154
MakeEntry("getpgid", UnknownArguments()), // 155
MakeEntry("getsid", UnknownArguments()), // 156
MakeEntry("setsid", UnknownArguments()), // 157
MakeEntry("getgroups", UnknownArguments()), // 158
MakeEntry("setgroups", UnknownArguments()), // 159
MakeEntry("uname", UnknownArguments()), // 160
MakeEntry("sethostname", UnknownArguments()), // 161
MakeEntry("setdomainname", UnknownArguments()), // 162
MakeEntry("getrlimit", UnknownArguments()), // 163
MakeEntry("setrlimit", UnknownArguments()), // 164
MakeEntry("getrusage", UnknownArguments()), // 165
MakeEntry("umask", kHex, kGen, kGen, kGen, kGen, kGen), // 166
MakeEntry("prctl", kInt, kHex, kHex, kHex, kHex, kGen), // 167
MakeEntry("getcpu", kHex, kHex, kHex, kGen, kGen, kGen), // 168
MakeEntry("gettimeofday", kHex, kHex, kGen, kGen, kGen, kGen), // 169
MakeEntry("settimeofday", kHex, kHex, kGen, kGen, kGen, kGen), // 170
MakeEntry("adjtimex", UnknownArguments()), // 171
MakeEntry("getpid", UnknownArguments()), // 172
MakeEntry("getppid", UnknownArguments()), // 173
MakeEntry("getuid", UnknownArguments()), // 174
MakeEntry("geteuid", UnknownArguments()), // 175
MakeEntry("getgid", UnknownArguments()), // 176
MakeEntry("getegid", UnknownArguments()), // 177
MakeEntry("gettid", UnknownArguments()), // 178
MakeEntry("sysinfo", UnknownArguments()), // 179
MakeEntry("mq_open", UnknownArguments()), // 180
MakeEntry("mq_unlink", UnknownArguments()), // 181
MakeEntry("mq_timedsend", UnknownArguments()), // 182
MakeEntry("mq_timedreceive", UnknownArguments()), // 183
MakeEntry("mq_notify", UnknownArguments()), // 184
MakeEntry("mq_getsetattr", UnknownArguments()), // 185
MakeEntry("msgget", UnknownArguments()), // 186
MakeEntry("msgctl", UnknownArguments()), // 187
MakeEntry("msgrcv", UnknownArguments()), // 188
MakeEntry("msgsnd", UnknownArguments()), // 189
MakeEntry("semget", UnknownArguments()), // 190
MakeEntry("semctl", UnknownArguments()), // 191
MakeEntry("semtimedop", UnknownArguments()), // 192
MakeEntry("semop", UnknownArguments()), // 193
MakeEntry("shmget", UnknownArguments()), // 194
MakeEntry("shmctl", UnknownArguments()), // 195
MakeEntry("shmat", UnknownArguments()), // 196
MakeEntry("shmdt", UnknownArguments()), // 197
MakeEntry("socket", kAddressFamily, kInt, kInt, kGen, kGen, kGen), // 198
MakeEntry("socketpair", UnknownArguments()), // 199
MakeEntry("bind", UnknownArguments()), // 200
MakeEntry("listen", UnknownArguments()), // 201
MakeEntry("accept", UnknownArguments()), // 202
MakeEntry("connect", kInt, kSockaddr, kInt, kGen, kGen, kGen), // 203
MakeEntry("getsockname", UnknownArguments()), // 204
MakeEntry("getpeername", UnknownArguments()), // 205
MakeEntry("sendto", kInt, kGen, kInt, kHex, kSockaddr, kInt), // 206
MakeEntry("recvfrom", UnknownArguments()), // 207
MakeEntry("setsockopt", UnknownArguments()), // 208
MakeEntry("getsockopt", UnknownArguments()), // 209
MakeEntry("shutdown", UnknownArguments()), // 210
MakeEntry("sendmsg", kInt, kSockmsghdr, kHex, kGen, kGen, kGen), // 211
MakeEntry("recvmsg", UnknownArguments()), // 212
MakeEntry("readahead", UnknownArguments()), // 213
MakeEntry("brk", kHex, kGen, kGen, kGen, kGen, kGen), // 214
MakeEntry("munmap", kHex, kHex, kGen, kGen, kGen, kGen), // 215
MakeEntry("mremap", UnknownArguments()), // 216
MakeEntry("add_key", UnknownArguments()), // 217
MakeEntry("request_key", UnknownArguments()), // 218
MakeEntry("keyctl", UnknownArguments()), // 219
MakeEntry("clone", kCloneFlag, kHex, kHex, kHex, kHex, kGen), // 220
MakeEntry("execve", kPath, kHex, kHex, kGen, kGen, kGen), // 221
MakeEntry("mmap", kHex, kInt, kHex, kHex, kInt, kInt), // 222
MakeEntry("fadvise64", UnknownArguments()), // 223
MakeEntry("swapon", kPath, kHex, kGen, kGen, kGen, kGen), // 224
MakeEntry("swapoff", kPath, kGen, kGen, kGen, kGen, kGen), // 225
MakeEntry("mprotect", kHex, kHex, kHex, kGen, kGen, kGen), // 226
MakeEntry("msync", UnknownArguments()), // 227
MakeEntry("mlock", UnknownArguments()), // 228
MakeEntry("munlock", UnknownArguments()), // 229
MakeEntry("mlockall", UnknownArguments()), // 230
MakeEntry("munlockall", UnknownArguments()), // 231
MakeEntry("mincore", UnknownArguments()), // 232
MakeEntry("madvise", UnknownArguments()), // 233
MakeEntry("remap_file_pages", UnknownArguments()), // 234
MakeEntry("mbind", UnknownArguments()), // 235
MakeEntry("get_mempolicy", UnknownArguments()), // 236
MakeEntry("set_mempolicy", UnknownArguments()), // 237
MakeEntry("migrate_pages", UnknownArguments()), // 238
MakeEntry("move_pages", UnknownArguments()), // 239
MakeEntry("rt_tgsigqueueinfo", UnknownArguments()), // 240
MakeEntry("perf_event_open", UnknownArguments()), // 241
MakeEntry("accept4", UnknownArguments()), // 242
MakeEntry("recvmmsg", kInt, kHex, kHex, kHex, kGen, kGen), // 243
SYSCALLS_UNUSED("UNUSED244"), // 244
SYSCALLS_UNUSED("UNUSED245"), // 245
SYSCALLS_UNUSED("UNUSED246"), // 246
SYSCALLS_UNUSED("UNUSED247"), // 247
SYSCALLS_UNUSED("UNUSED248"), // 248
SYSCALLS_UNUSED("UNUSED249"), // 249
SYSCALLS_UNUSED("UNUSED250"), // 250
SYSCALLS_UNUSED("UNUSED251"), // 251
SYSCALLS_UNUSED("UNUSED252"), // 252
SYSCALLS_UNUSED("UNUSED253"), // 253
SYSCALLS_UNUSED("UNUSED254"), // 254
SYSCALLS_UNUSED("UNUSED255"), // 255
SYSCALLS_UNUSED("UNUSED256"), // 256
SYSCALLS_UNUSED("UNUSED257"), // 257
SYSCALLS_UNUSED("UNUSED258"), // 258
SYSCALLS_UNUSED("UNUSED259"), // 259
MakeEntry("wait4", kInt, kHex, kHex, kHex, kGen, kGen), // 260
MakeEntry("prlimit64", kInt, kInt, kHex, kHex, kGen, kGen), // 261
MakeEntry("fanotify_init", kHex, kHex, kInt, kGen, kGen, kGen), // 262
MakeEntry("fanotify_mark", kInt, kHex, kInt, kPath, kGen, kGen), // 263
MakeEntry("name_to_handle_at", kInt, kGen, kHex, kHex, kHex, kGen), // 264
MakeEntry("open_by_handle_at", kInt, kHex, kHex, kGen, kGen, kGen), // 265
MakeEntry("clock_adjtime", kInt, kHex, kGen, kGen, kGen, kGen), // 266
MakeEntry("syncfs", kInt, kGen, kGen, kGen, kGen, kGen), // 267
MakeEntry("setns", kInt, kHex, kGen, kGen, kGen, kGen), // 268
MakeEntry("sendmmsg", kInt, kHex, kInt, kHex, kGen, kGen), // 269
MakeEntry("process_vm_readv", kInt, kHex, kInt, kHex, kInt, kInt), // 270
MakeEntry("process_vm_writev", kInt, kHex, kInt, kHex, kInt, kInt), // 271
MakeEntry("kcmp", kInt, kInt, kInt, kHex, kHex, kGen), // 272
MakeEntry("finit_module", kInt, kPath, kHex, kGen, kGen, kGen), // 273
MakeEntry("sched_setattr", UnknownArguments()), // 274
MakeEntry("sched_getattr", UnknownArguments()), // 275
MakeEntry("renameat2", kGen, kPath, kGen, kPath, kGen, kGen), // 276
MakeEntry("seccomp", UnknownArguments()), // 277
MakeEntry("getrandom", UnknownArguments()), // 278
MakeEntry("memfd_create", UnknownArguments()), // 279
};
#undef SYSCALLS_UNUSED00_99
#undef SYSCALLS_UNUSED50_99
@ -1226,17 +1507,16 @@ constexpr SyscallTable::Entry kSyscallDataPPC64[] = {
#undef SYSCALLS_UNUSED0_9
#undef SYSCALLS_UNUSED
SyscallTable SyscallTable::get(Syscall::CpuArch arch) {
switch (arch) {
#if defined(__x86_64__)
case Syscall::kX86_64:
SyscallTable SyscallTable::get(cpu::Architecture arch) {
switch (host_cpu::Architecture()) {
case cpu::kX8664:
return SyscallTable(kSyscallDataX8664);
case Syscall::kX86_32:
case cpu::kX86:
return SyscallTable(kSyscallDataX8632);
#elif defined(__powerpc64__)
case Syscall::kPPC_64:
return SyscallTable(kSyscallDataPPC64);
#endif
case cpu::kPPC64LE:
return SyscallTable(kSyscallDataPPC64LE);
case cpu::kArm64:
return SyscallTable(kSyscallDataArm64);
default:
return SyscallTable();
}

View File

@ -9,6 +9,7 @@
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
#include "sandboxed_api/sandbox2/config.h"
#include "sandboxed_api/sandbox2/syscall.h"
namespace sandbox2 {
@ -23,7 +24,7 @@ class SyscallTable {
struct Entry;
// Returns the syscall table for the architecture.
static SyscallTable get(Syscall::CpuArch arch);
static SyscallTable get(cpu::Architecture arch);
int size() { return data_.size(); }

View File

@ -19,6 +19,7 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/strings/str_cat.h"
#include "sandboxed_api/sandbox2/config.h"
using ::testing::Eq;
using ::testing::StartsWith;
@ -45,7 +46,7 @@ TEST(SyscallTest, Basic) {
EXPECT_THAT(arg_desc[2], Eq("0x5 [5]"));
EXPECT_THAT(
syscall.GetDescription(),
Eq(absl::StrCat(Syscall::GetArchDescription(Syscall::GetHostArch()),
Eq(absl::StrCat(Syscall::GetArchDescription(host_cpu::Architecture()),
" read [", __NR_read,
"](0x1 [1], 0xbadbeef, 0x5 [5]) IP: 0, STACK: 0")));
}
@ -53,7 +54,7 @@ TEST(SyscallTest, Basic) {
TEST(SyscallTest, Empty) {
Syscall syscall;
EXPECT_THAT(syscall.arch(), Eq(Syscall::kUnknown));
EXPECT_THAT(syscall.arch(), Eq(cpu::kUnknown));
EXPECT_THAT(syscall.GetName(), StartsWith("UNKNOWN"));
EXPECT_THAT(syscall.GetArgumentsDescription().size(), Eq(Syscall::kMaxArgs));
}

View File

@ -41,7 +41,12 @@ STATIC_LINKOPTS = [
]
# TODO(https://github.com/bazelbuild/bazel/issues/8672): Remove this workaround
EXTRA_FULLY_STATIC_LINKOPTS = ["-l:libstdc++.a"]
# Change is scheduled for Bazel 4.0. Specifying
# `--incompatible_linkopts_to_linklibs` also works
EXTRA_FULLY_STATIC_LINKOPTS = [
"-l:libstdc++.a",
"-l:libm.a",
]
cc_binary(
name = "abort",
@ -173,6 +178,7 @@ cc_binary(
"fully_static_link", # link libc statically
],
linkstatic = 1, # prefer static libraries
deps = ["//sandboxed_api/sandbox2:config"],
)
# security: disable=cc-static-no-pie

View File

@ -159,6 +159,7 @@ set_target_properties(policy PROPERTIES
)
target_link_libraries(policy PRIVATE
sapi::base
sandbox2::config
${_sandbox2_fully_static_linkopts}
)

View File

@ -23,7 +23,9 @@
#include <cstdio>
#include <cstdlib>
#if defined(__x86_64__)
#include "sandboxed_api/sandbox2/config.h"
#ifdef SAPI_X86_64
void TestAMD64SyscallMismatch() {
int64_t result;
@ -53,7 +55,7 @@ void TestAMD64SyscallMismatchFs() {
: "rax", "rbx", "rcx");
exit(-result);
}
#endif // defined(__x86_64__)
#endif
void TestPtrace() {
ptrace(PTRACE_SEIZE, getppid(), 0, 0);
@ -97,14 +99,14 @@ int main(int argc, char** argv) {
int testno = atoi(argv[1]); // NOLINT
switch (testno) {
#if defined(__x86_64__)
#ifdef SAPI_X86_64
case 1:
TestAMD64SyscallMismatch();
break;
case 2:
TestAMD64SyscallMismatchFs();
break;
#endif // defined(__x86_64__)
#endif
case 3:
TestPtrace();
break;

View File

@ -39,13 +39,13 @@
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "absl/strings/strip.h"
#include "sandboxed_api/sandbox2/config.h"
#include "sandboxed_api/sandbox2/util/fileops.h"
#include "sandboxed_api/sandbox2/util/path.h"
#include "sandboxed_api/sandbox2/util/strerror.h"
#include "sandboxed_api/util/raw_logging.h"
namespace sandbox2 {
namespace util {
namespace sandbox2::util {
void CharPtrArrToVecString(char* const* arr, std::vector<std::string>* vec) {
for (int i = 0; arr[i]; ++i) {
@ -126,13 +126,11 @@ ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
ABSL_ATTRIBUTE_NOINLINE
pid_t CloneAndJump(int flags, jmp_buf* env_ptr) {
uint8_t stack_buf[PTHREAD_STACK_MIN] ABSL_CACHELINE_ALIGNED;
#if defined(__x86_64__) || defined(__x86__) || defined(__i386__) || \
defined(__powerpc64__)
static_assert(
host_cpu::IsX8664() || host_cpu::IsPPC64LE() || host_cpu::IsArm64(),
"Host CPU architecture not supported, see config.h");
// Stack grows down.
void* stack = stack_buf + sizeof(stack_buf);
#else
#error "Architecture is not supported"
#endif
int r;
{
r = clone(&ChildFunc, stack, flags, env_ptr, nullptr, nullptr, nullptr);
@ -182,9 +180,9 @@ bool CreateMemFd(int* fd, const char* name) {
return true;
}
sapi::StatusOr<int> Communicate(const std::vector<std::string>& argv,
const std::vector<std::string>& envv,
std::string* output) {
absl::StatusOr<int> Communicate(const std::vector<std::string>& argv,
const std::vector<std::string>& envv,
std::string* output) {
int cout_pipe[2];
posix_spawn_file_actions_t action;
@ -280,7 +278,7 @@ std::string GetRlimitName(int resource) {
}
}
sapi::StatusOr<std::string> ReadCPathFromPid(pid_t pid, uintptr_t ptr) {
absl::StatusOr<std::string> ReadCPathFromPid(pid_t pid, uintptr_t ptr) {
std::string path(PATH_MAX, '\0');
iovec local_iov[] = {{&path[0], path.size()}};
@ -321,5 +319,4 @@ sapi::StatusOr<std::string> ReadCPathFromPid(pid_t pid, uintptr_t ptr) {
return path;
}
} // namespace util
} // namespace sandbox2
} // namespace sandbox2::util

View File

@ -25,7 +25,7 @@
#include <vector>
#include "absl/base/macros.h"
#include "sandboxed_api/util/statusor.h"
#include "absl/status/statusor.h"
namespace sandbox2 {
namespace util {
@ -62,9 +62,9 @@ bool CreateMemFd(int* fd, const char* name = "buffer_file");
// Executes a the program given by argv and the specified environment and
// captures any output to stdout/stderr.
sapi::StatusOr<int> Communicate(const std::vector<std::string>& argv,
const std::vector<std::string>& envv,
std::string* output);
absl::StatusOr<int> Communicate(const std::vector<std::string>& argv,
const std::vector<std::string>& envv,
std::string* output);
// Returns signal description.
std::string GetSignalName(int signo);
@ -74,7 +74,7 @@ std::string GetRlimitName(int resource);
// Reads a path string (NUL-terminated, shorter than PATH_MAX) from another
// process memory
sapi::StatusOr<std::string> ReadCPathFromPid(pid_t pid, uintptr_t ptr);
absl::StatusOr<std::string> ReadCPathFromPid(pid_t pid, uintptr_t ptr);
} // namespace util
} // namespace sandbox2

View File

@ -139,9 +139,9 @@ cc_library(
"//sandboxed_api/sandbox2:util",
"//sandboxed_api/util:raw_logging",
"//sandboxed_api/util:status",
"//sandboxed_api/util:statusor",
"@com_google_absl//absl/base:endian",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
],
)
@ -173,8 +173,8 @@ cc_library(
deps = [
":fileops",
":strerror",
"//sandboxed_api/util:statusor",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
],
)
@ -199,8 +199,8 @@ cc_library(
hdrs = ["maps_parser.h"],
copts = sapi_platform_copts(),
deps = [
"//sandboxed_api/util:statusor",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
],
)

View File

@ -80,7 +80,6 @@ target_link_libraries(sandbox2_util_minielf PRIVATE
sandbox2::util
sapi::base
sapi::raw_logging
sapi::statusor
)
# sandboxed_api/sandbox2/util:temp_file
@ -95,7 +94,7 @@ target_link_libraries(sandbox2_util_temp_file
sandbox2::strerror
sapi::base
PUBLIC absl::status
sapi::statusor
absl::statusor
)
# sandboxed_api/sandbox2/util:maps_parser
@ -106,9 +105,9 @@ add_library(sandbox2_util_maps_parser STATIC
add_library(sandbox2::maps_parser ALIAS sandbox2_util_maps_parser)
target_link_libraries(sandbox2_util_maps_parser PRIVATE
absl::status
absl::statusor
absl::strings
sapi::base
sapi::statusor
)
# sandboxed_api/sandbox2/util:runfiles

View File

@ -15,11 +15,12 @@
#include "sandboxed_api/sandbox2/util/maps_parser.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_split.h"
namespace sandbox2 {
sapi::StatusOr<std::vector<MapsEntry>> ParseProcMaps(
absl::StatusOr<std::vector<MapsEntry>> ParseProcMaps(
const std::string& contents) {
// Note: The format string
// https://github.com/torvalds/linux/blob/v4.14/fs/proc/task_mmu.c#L289

View File

@ -19,7 +19,7 @@
#include <string>
#include <vector>
#include "sandboxed_api/util/statusor.h"
#include "absl/status/statusor.h"
namespace sandbox2 {
@ -37,7 +37,7 @@ struct MapsEntry {
std::string path;
};
sapi::StatusOr<std::vector<MapsEntry>> ParseProcMaps(
absl::StatusOr<std::vector<MapsEntry>> ParseProcMaps(
const std::string& contents);
} // namespace sandbox2

Some files were not shown because too many files have changed in this diff Show More