Merge branch 'main' into c-blosc

This commit is contained in:
Christian Blichmann 2022-02-16 10:02:08 +01:00 committed by GitHub
commit c93dae9519
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 3593 additions and 219 deletions

View File

@ -13,36 +13,55 @@ jobs:
include: include:
- container: fedora:35 - container: fedora:35
compiler: gcc # GCC 11 compiler: gcc # GCC 11
ignore-errors: false ignore-errors: true # Stack trace test fails on Fedora (issue #118)
# TODO(cblichmann): Add clang-13 build to matrix (currently fails)
runs-on: ubuntu-latest runs-on: ubuntu-latest
continue-on-error: ${{ matrix.ignore-errors }} continue-on-error: ${{ matrix.ignore-errors }}
container: env:
image: ${{ matrix.container }} RUN_CMD: docker exec --tty ${{matrix.compiler}}-build-container
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Prepare container
# Note: For the sandbox tests to work, we need a privileged, unconfined
# container that retains its capabilities.
run: |
docker run --name ${{matrix.compiler}}-build-container \
--tty \
--privileged \
--cap-add ALL \
--security-opt apparmor:unconfined \
-v $GITHUB_WORKSPACE:$GITHUB_WORKSPACE \
-e TERM=dumb \
-e BUILD_TYPE \
-e GITHUB_WORKSPACE \
-d ${{matrix.container}} \
sleep infinity
- name: Install build tools - name: Install build tools
run: | run: |
dnf update -y $RUN_CMD dnf update -y --quiet
dnf install -y git make automake patch glibc-static libstdc++-static \ $RUN_CMD dnf install -y --quiet git make automake patch glibc-static \
cmake ninja-build python3 python3-pip clang-devel libcap-devel libstdc++-static cmake ninja-build python3 python3-pip clang-devel \
libcap-devel
- name: Install/configure Clang compiler toolchain
if: matrix.compiler == 'clang'
run: |
echo "CXX=clang++" >> $GITHUB_ENV
echo "CC=clang" >> $GITHUB_ENV
- name: Create Build Environment - name: Create Build Environment
run: | run: |
pip3 install absl-py clang $RUN_CMD pip3 install --progress-bar=off absl-py clang
cmake -E make_directory $GITHUB_WORKSPACE/build $RUN_CMD cmake -E make_directory $GITHUB_WORKSPACE/build
- name: Configure CMake - name: Configure CMake
run: cmake $GITHUB_WORKSPACE -G Ninja -DCMAKE_BUILD_TYPE=$BUILD_TYPE run: |
$RUN_CMD cmake -S $GITHUB_WORKSPACE -B $GITHUB_WORKSPACE/build \
-G Ninja -DCMAKE_BUILD_TYPE=$BUILD_TYPE
- name: Build - name: Build
run: cmake --build $GITHUB_WORKSPACE --config $BUILD_TYPE run: |
$RUN_CMD cmake --build $GITHUB_WORKSPACE/build --config $BUILD_TYPE
- name: Test
run: |
$RUN_CMD ctest --test-dir $GITHUB_WORKSPACE/build -C $BUILD_TYPE \
--output-on-failure \
-R SapiTest

View File

@ -62,17 +62,17 @@ jobs:
- name: Create Build Environment - name: Create Build Environment
run: | run: |
pip3 install absl-py clang pip3 install absl-py clang
cmake -E make_directory ${{runner.workspace}}/build cmake -E make_directory $GITHUB_WORKSPACE/build
- name: Configure CMake - name: Configure CMake
working-directory: ${{runner.workspace}}/build run: |
run: cmake $GITHUB_WORKSPACE -G Ninja -DCMAKE_BUILD_TYPE=$BUILD_TYPE cmake $GITHUB_WORKSPACE -G Ninja -DCMAKE_BUILD_TYPE=$BUILD_TYPE
- name: Build - name: Build
working-directory: ${{runner.workspace}}/build run: |
run: cmake --build . --config $BUILD_TYPE cmake --build $GITHUB_WORKSPACE --config $BUILD_TYPE
# TODO(cblichmann): Before enabling this, make sure all OSS tests pass - name: Test
#- name: Test run: |
# working-directory: ${{runner.workspace}}/build ctest $GITHUB_WORKSPACE -C $BUILD_TYPE --output-on-failure \
# run: ctest -C $BUILD_TYPE -R SapiTest

3
.gitmodules vendored
View File

@ -4,9 +4,6 @@
[submodule "oss-internship-2020/openjpeg/openjpeg"] [submodule "oss-internship-2020/openjpeg/openjpeg"]
path = oss-internship-2020/openjpeg/openjpeg path = oss-internship-2020/openjpeg/openjpeg
url = https://github.com/uclouvain/openjpeg.git 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/
[submodule "oss-internship-2020/gdal/gdal"] [submodule "oss-internship-2020/gdal/gdal"]
path = oss-internship-2020/gdal/gdal path = oss-internship-2020/gdal/gdal
url = https://github.com/OSGeo/gdal/ url = https://github.com/OSGeo/gdal/

View File

@ -100,8 +100,7 @@ function(add_sapi_library)
list(APPEND _sapi_exported_funcs "LINKER:--export-dynamic-symbol,${func}") list(APPEND _sapi_exported_funcs "LINKER:--export-dynamic-symbol,${func}")
endforeach() endforeach()
if(NOT _sapi_exported_funcs) if(NOT _sapi_exported_funcs)
set(_sapi_exported_funcs LINKER:--whole-archive set(_sapi_exported_funcs LINKER:--allow-multiple-definition)
LINKER:--allow-multiple-definition)
endif() endif()
# The sandboxed binary # The sandboxed binary
@ -112,7 +111,7 @@ function(add_sapi_library)
add_executable("${_sapi_bin}" "${_sapi_force_cxx_linkage}") add_executable("${_sapi_bin}" "${_sapi_force_cxx_linkage}")
target_link_libraries("${_sapi_bin}" PRIVATE target_link_libraries("${_sapi_bin}" PRIVATE
-fuse-ld=gold -fuse-ld=gold
"${_sapi_LIBRARY}" -Wl,--whole-archive "${_sapi_LIBRARY}" -Wl,--no-whole-archive
sapi::client sapi::client
${CMAKE_DL_LIBS} ${CMAKE_DL_LIBS}
) )

View File

@ -14,7 +14,12 @@
# Append to this list whenever a new sandboxed library is added to `contrib/`. # Append to this list whenever a new sandboxed library is added to `contrib/`.
set(SAPI_CONTRIB_SANDBOXES set(SAPI_CONTRIB_SANDBOXES
hunspell
jsonnet jsonnet
libidn2
pffft
turbojpeg
zopfli
zstd zstd
) )

View File

@ -6,11 +6,15 @@ libraries.
## Projects Sandboxed ## Projects Sandboxed
Directory | Project | Home Page | Integration Directory | Project | Home Page | Integration
----------- | --------------------------------------------------------------- | -------------------------------------------------------------------- | ----------- ------------ | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------ | -----------
`c-blosc/` | c-blosc A blocking, shuffling and loss-less compression library | [github.com/Blosc/c-blosc](https://github.com/Blosc/c-blosc) | CMake `c-blosc/` | c-blosc - A blocking, shuffling and loss-less compression library | [github.com/Blosc/c-blosc](https://github.com/Blosc/c-blosc) | CMake
`jsonnet/` | Jsonnet - The Data Templating Language | [github.com/google/jsonnet](https://github.com/google/jsonnet) | CMake
`hunspell/` | Hunspell - The most popular spellchecking library | [github.com/hunspell/hunspell](https://github.com/hunspell/hunspell) | CMake `hunspell/` | Hunspell - The most popular spellchecking library | [github.com/hunspell/hunspell](https://github.com/hunspell/hunspell) | CMake
`jsonnet/` | Jsonnet - The Data Templating Language | [github.com/google/jsonnet](https://github.com/google/jsonnet) | CMake
`pffft/` | PFFFT - a pretty fast Fourier Transform | [bitbucket.org/jpommier/pffft.git](https://bitbucket.org/jpommier/pffft.git) | CMake
`zopfli` | Zopfli - Compression Algorithm | [github.com/google/zopfli](https://github.com/google/zopfli) | CMake
`zstd/` | Zstandard - Fast real-time compression algorithm | [github.com/facebook/zstd](https://github.com/facebook/zstd) | CMake `zstd/` | Zstandard - Fast real-time compression algorithm | [github.com/facebook/zstd](https://github.com/facebook/zstd) | CMake
`libidn2/` | libidn2 - GNU IDN library | [www.gnu.org/software/libidn/#libidn2](https://www.gnu.org/software/libidn/#libidn2) | CMake
`turbojpeg/` | High-level JPEG library | [libjpeg-turbo.org/About/TurboJPEG](https://libjpeg-turbo.org/About/TurboJPEG) | CMake
## Projects Shipping with Sandboxed API Sandboxes ## Projects Shipping with Sandboxed API Sandboxes

View File

@ -21,15 +21,14 @@ set(CMAKE_CXX_STANDARD_REQUIRED True)
set(SAPI_ROOT "" CACHE PATH "Path to the Sandboxed API source tree") set(SAPI_ROOT "" CACHE PATH "Path to the Sandboxed API source tree")
add_subdirectory( if(NOT TARGET sapi::sapi)
"${SAPI_ROOT}" set(SAPI_ROOT "../.." CACHE PATH "Path to the Sandboxed API source tree")
add_subdirectory("${SAPI_ROOT}"
"${CMAKE_BINARY_DIR}/sandboxed-api-build" "${CMAKE_BINARY_DIR}/sandboxed-api-build"
EXCLUDE_FROM_ALL EXCLUDE_FROM_ALL)
) endif()
FetchContent_Declare(
libhunspell
FetchContent_Declare(libhunspell
GIT_REPOSITORY https://github.com/hunspell/hunspell.git GIT_REPOSITORY https://github.com/hunspell/hunspell.git
GIT_TAG 31e6d6323026a3bef12c5912ce032d88bfef2091 GIT_TAG 31e6d6323026a3bef12c5912ce032d88bfef2091
) )
@ -44,13 +43,23 @@ if(NOT libhunspell_POPULATED)
if(NOT _sapi_CONFIG_STATUS STREQUAL "${libhunspell_CONFIG_STATUS}") if(NOT _sapi_CONFIG_STATUS STREQUAL "${libhunspell_CONFIG_STATUS}")
message("-- Configuring libhunspell...") message("-- Configuring libhunspell...")
execute_process( execute_process(
COMMAND autoreconf -vfi COMMAND autoreconf -i
COMMAND ./configure --disable-dependency-tracking
WORKING_DIRECTORY "${libhunspell_SOURCE_DIR}" WORKING_DIRECTORY "${libhunspell_SOURCE_DIR}"
RESULT_VARIABLE libhunspell_config_result RESULT_VARIABLE _sapi_libhunspell_autoreconf_result
) )
if(NOT libhunspell_config_result EQUAL "0") if(NOT _sapi_libhunspell_autoreconf_result EQUAL "0")
message(FATAL_ERROR "Configuration for libhunspell failed") message(FATAL_ERROR "Configuration for libhunspell failed: "
"${_sapi_libhunspell_autoreconf_result}")
endif()
execute_process(
COMMAND ./configure --disable-dependency-tracking
--quiet
WORKING_DIRECTORY "${libhunspell_SOURCE_DIR}"
RESULT_VARIABLE _sapi_libhunspell_config_result
)
if(NOT _sapi_libhunspell_config_result EQUAL "0")
message(FATAL_ERROR "Configuration for libhunspell failed: "
"${_sapi_libhunspell_config_result}")
endif() endif()
file(SHA256 "${libhunspell_SOURCE_DIR}/config.status" _sapi_CONFIG_STATUS) file(SHA256 "${libhunspell_SOURCE_DIR}/config.status" _sapi_CONFIG_STATUS)
set(libhunspell_CONFIG_STATUS "${_sapi_CONFIG_STATUS}" CACHE INTERNAL "") set(libhunspell_CONFIG_STATUS "${_sapi_CONFIG_STATUS}" CACHE INTERNAL "")
@ -58,37 +67,37 @@ if(NOT libhunspell_POPULATED)
endif() endif()
add_library(hunspell STATIC add_library(hunspell STATIC
${libhunspell_SOURCE_DIR}/src/hunspell/affentry.cxx "${libhunspell_SOURCE_DIR}/src/hunspell/affentry.cxx"
${libhunspell_SOURCE_DIR}/src/hunspell/affentry.hxx "${libhunspell_SOURCE_DIR}/src/hunspell/affentry.hxx"
${libhunspell_SOURCE_DIR}/src/hunspell/affixmgr.cxx "${libhunspell_SOURCE_DIR}/src/hunspell/affixmgr.cxx"
${libhunspell_SOURCE_DIR}/src/hunspell/affixmgr.hxx "${libhunspell_SOURCE_DIR}/src/hunspell/affixmgr.hxx"
${libhunspell_SOURCE_DIR}/src/hunspell/atypes.hxx "${libhunspell_SOURCE_DIR}/src/hunspell/atypes.hxx"
${libhunspell_SOURCE_DIR}/src/hunspell/baseaffix.hxx "${libhunspell_SOURCE_DIR}/src/hunspell/baseaffix.hxx"
${libhunspell_SOURCE_DIR}/src/hunspell/csutil.cxx "${libhunspell_SOURCE_DIR}/src/hunspell/csutil.cxx"
${libhunspell_SOURCE_DIR}/src/hunspell/csutil.hxx "${libhunspell_SOURCE_DIR}/src/hunspell/csutil.hxx"
${libhunspell_SOURCE_DIR}/src/hunspell/filemgr.cxx "${libhunspell_SOURCE_DIR}/src/hunspell/filemgr.cxx"
${libhunspell_SOURCE_DIR}/src/hunspell/filemgr.hxx "${libhunspell_SOURCE_DIR}/src/hunspell/filemgr.hxx"
${libhunspell_SOURCE_DIR}/src/hunspell/hashmgr.cxx "${libhunspell_SOURCE_DIR}/src/hunspell/hashmgr.cxx"
${libhunspell_SOURCE_DIR}/src/hunspell/hashmgr.hxx "${libhunspell_SOURCE_DIR}/src/hunspell/hashmgr.hxx"
${libhunspell_SOURCE_DIR}/src/hunspell/htypes.hxx "${libhunspell_SOURCE_DIR}/src/hunspell/htypes.hxx"
${libhunspell_SOURCE_DIR}/src/hunspell/hunspell.cxx "${libhunspell_SOURCE_DIR}/src/hunspell/hunspell.cxx"
${libhunspell_SOURCE_DIR}/src/hunspell/hunspell.h "${libhunspell_SOURCE_DIR}/src/hunspell/hunspell.h"
${libhunspell_SOURCE_DIR}/src/hunspell/hunspell.hxx "${libhunspell_SOURCE_DIR}/src/hunspell/hunspell.hxx"
${libhunspell_SOURCE_DIR}/src/hunspell/hunzip.cxx "${libhunspell_SOURCE_DIR}/src/hunspell/hunzip.cxx"
${libhunspell_SOURCE_DIR}/src/hunspell/hunzip.hxx "${libhunspell_SOURCE_DIR}/src/hunspell/hunzip.hxx"
${libhunspell_SOURCE_DIR}/src/hunspell/langnum.hxx "${libhunspell_SOURCE_DIR}/src/hunspell/langnum.hxx"
${libhunspell_SOURCE_DIR}/src/hunspell/phonet.cxx "${libhunspell_SOURCE_DIR}/src/hunspell/phonet.cxx"
${libhunspell_SOURCE_DIR}/src/hunspell/phonet.hxx "${libhunspell_SOURCE_DIR}/src/hunspell/phonet.hxx"
${libhunspell_SOURCE_DIR}/src/hunspell/replist.cxx "${libhunspell_SOURCE_DIR}/src/hunspell/replist.cxx"
${libhunspell_SOURCE_DIR}/src/hunspell/replist.hxx "${libhunspell_SOURCE_DIR}/src/hunspell/replist.hxx"
${libhunspell_SOURCE_DIR}/src/hunspell/suggestmgr.cxx "${libhunspell_SOURCE_DIR}/src/hunspell/suggestmgr.cxx"
${libhunspell_SOURCE_DIR}/src/hunspell/suggestmgr.hxx "${libhunspell_SOURCE_DIR}/src/hunspell/suggestmgr.hxx"
${libhunspell_SOURCE_DIR}/src/hunspell/utf_info.hxx "${libhunspell_SOURCE_DIR}/src/hunspell/utf_info.hxx"
${libhunspell_SOURCE_DIR}/src/hunspell/w_char.hxx "${libhunspell_SOURCE_DIR}/src/hunspell/w_char.hxx"
) )
target_include_directories(hunspell PUBLIC target_include_directories(hunspell PUBLIC
${libhunspell_SOURCE_DIR}/src/hunspell "${libhunspell_SOURCE_DIR}/src/hunspell"
) )
set(libhunspell_INCLUDE_DIR "${libhunspell_SOURCE_DIR}/src/hunspell") set(libhunspell_INCLUDE_DIR "${libhunspell_SOURCE_DIR}/src/hunspell")
@ -112,7 +121,7 @@ add_sapi_library(
Hunspell_free_list Hunspell_free_list
INPUTS INPUTS
${libhunspell_INCLUDE_DIR}/hunspell.h "${libhunspell_INCLUDE_DIR}/hunspell.h"
LIBRARY hunspell LIBRARY hunspell
LIBRARY_NAME Hunspell LIBRARY_NAME Hunspell

View File

@ -35,6 +35,7 @@ class HunspellSapiSandbox : public HunspellSandbox {
.AllowOpen() .AllowOpen()
.AllowRead() .AllowRead()
.AllowWrite() .AllowWrite()
.AllowGetPIDs()
.AllowSystemMalloc() .AllowSystemMalloc()
.AllowExit() .AllowExit()
.AllowSyscalls({ .AllowSyscalls({

View File

@ -1,6 +1,9 @@
# Jsonnet Sandboxed API # Jsonnet Sandboxed API
This library provides a sandboxed version of the This library was sandboxed as part of Google's summer 2020 internship program
([blog post](https://security.googleblog.com/2020/12/improving-open-source-security-during.html)).
This directory contains a sandbox for the
[Jsonnet](https://github.com/google/jsonnet) library. [Jsonnet](https://github.com/google/jsonnet) library.
## How to use from an existing Project ## How to use from an existing Project

View File

@ -12,50 +12,48 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
cmake_minimum_required(VERSION 3.10) cmake_minimum_required(VERSION 3.13..3.22)
project(pffft CXX C) project(pffft CXX C)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True) set(CMAKE_CXX_STANDARD_REQUIRED True)
if(NOT TARGET sapi::sapi)
set(SAPI_ROOT "../.." CACHE PATH "Path to the Sandboxed API source tree")
add_subdirectory("${SAPI_ROOT}"
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
EXCLUDE_FROM_ALL)
endif()
include(CheckLibraryExists)
FetchContent_Declare(pffft
GIT_REPOSITORY https://bitbucket.org/jpommier/pffft.git
GIT_TAG 988259a41d1522047a9420e6265a6ba8289c1654 # 2021-12-02
)
FetchContent_MakeAvailable(pffft)
add_library(pffft STATIC add_library(pffft STATIC
master/pffft.c "${pffft_SOURCE_DIR}/pffft.c"
master/pffft.h "${pffft_SOURCE_DIR}/pffft.h"
master/fftpack.c "${pffft_SOURCE_DIR}/fftpack.c"
master/fftpack.h "${pffft_SOURCE_DIR}/fftpack.h"
) )
add_executable(pffft_main add_executable(pffft_main
master/test_pffft.c "${pffft_SOURCE_DIR}/test_pffft.c"
) )
target_link_libraries(pffft_main PRIVATE target_link_libraries(pffft_main PRIVATE
pffft pffft
) )
set(MATH_LIBS "") check_library_exists(m sin "" _sapi_HAVE_LIBM)
include(CheckLibraryExists) if(_sapi_HAVE_LIBM)
check_library_exists(m sin "" LIBM) target_link_libraries(pffft PUBLIC
if(LIBM) m
list(APPEND MATH_LIBS "m") )
endif() 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 add_sapi_library(pffft_sapi
FUNCTIONS pffft_new_setup FUNCTIONS pffft_new_setup
pffft_destroy_setup pffft_destroy_setup
@ -83,22 +81,23 @@ add_sapi_library(pffft_sapi
sinti sinti
sint sint
INPUTS master/pffft.h master/fftpack.h INPUTS "${pffft_SOURCE_DIR}/pffft.h"
"${pffft_SOURCE_DIR}/fftpack.h"
LIBRARY pffft LIBRARY pffft
LIBRARY_NAME Pffft LIBRARY_NAME Pffft
NAMESPACE "" NAMESPACE ""
) )
add_library(sapi_contrib::pffft ALIAS pffft_sapi)
target_include_directories(pffft_sapi INTERFACE target_include_directories(pffft_sapi INTERFACE
"${PROJECT_BINARY_DIR}" "${PROJECT_BINARY_DIR}"
"${SAPI_SOURCE_DIR}"
) )
add_executable(pffft_sandboxed add_executable(pffft_sandboxed
main_pffft_sandboxed.cc main_pffft_sandboxed.cc
) )
target_link_libraries(pffft_sandboxed PRIVATE target_link_libraries(pffft_sandboxed PRIVATE
pffft_sapi sapi_contrib::pffft
sapi::sapi sapi::sapi
) )

View File

@ -1,16 +1,35 @@
# Sandboxing PFFFT library # Sandboxing PFFFT library
This library was sandboxed as part of Google's summer 2020 internship program
([blog post](https://security.googleblog.com/2020/12/improving-open-source-security-during.html)).
Build System: CMake Build System: CMake
OS: Linux OS: Linux
### Check out the PFFFT library & CMake set up ### How to use from an existing Project
```
git submodule update --init --recursive
mkdir -p build && cd build If your project does not include Sandboxed API as a dependency yet, add the
cmake .. -G Ninja -DPFFFT_ROOT_DIR=$PWD following lines to the main `CMakeLists.txt`:
ninjas
```cmake
include(FetchContent)
FetchContent_Declare(sandboxed-api
GIT_REPOSITORY https://github.com/google/sandboxed-api
GIT_TAG main # Or pin a specific commit/tag
)
FetchContent_MakeAvailable(sandboxed-api) # CMake 3.14 or higher
add_sapi_subdirectory(contrib/pffft)
``` ```
The `add_sapi_subdirectory()` macro sets up the source and binary directories
for the sandboxed jsonnet targets.
Afterwards your project's code can link to `sapi_contrib::pffft` and use the
generated header `pffft_sapi.sapi.h`. An example sandbox policy can be found
in `main_pffft_sandboxed.cc`.
### For testing: ### For testing:
`cd build`, then `./pffft_sandboxed` `cd build`, then `./pffft_sandboxed`
@ -19,14 +38,15 @@ display custom info with
`./pffft_sandboxed --logtostderr` `./pffft_sandboxed --logtostderr`
## ***About the project*** ## ***About the project***
*PFFFT library is concerned with 1D Fast-Fourier Transformations finding a
PFFFT library is concerned with 1D Fast-Fourier Transformations finding a
compromise between accuracy and speed. It deals with real and complex compromise between accuracy and speed. It deals with real and complex
vectors, both cases being illustrated in the testing part (`test_pffft.c` vectors, both cases being illustrated in the testing part (`test_pffft.c`
for initially and original version, `main_pffft_sandboxed.cc` for our for initially and original version, `main_pffft_sandboxed.cc` for our
currently implemented sandboxed version). currently implemented sandboxed version).
The original files can be found at: https://bitbucket.org/jpommier/pffft/src.* 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 The purpose of sandboxing is to limit the permissions and capabilities of
librarys methods, in order to secure the usage of them. librarys methods, in order to secure the usage of them.
After obtaining the sandbox, the functions will be called through an After obtaining the sandbox, the functions will be called through an
Sandbox API (being called `api` in the current test) and so, the Sandbox API (being called `api` in the current test) and so, the
@ -50,10 +70,12 @@ Without using this type of argument when running, the output format is set
by default.* by default.*
#### CMake observations resume: #### CMake observations resume:
* linking pffft and fftpack (which contains necessary functions for pffft) * linking pffft and fftpack (which contains necessary functions for pffft)
* set math library * set math library
#### Sandboxed main observations resume: #### Sandboxed main observations resume:
* containing two testing parts (fft / pffft benchmarks) * containing two testing parts (fft / pffft benchmarks)
* showing the performance of the transformations implies * showing the performance of the transformations implies
testing them through various FFT dimenstions. testing them through various FFT dimenstions.

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include <gflags/gflags.h> #include <syscall.h>
#include <cmath> #include <cmath>
#include <cstdio> #include <cstdio>
@ -21,6 +21,7 @@
#include <ctime> #include <ctime>
#include <glog/logging.h> #include <glog/logging.h>
#include "gflags/gflags.h"
#include "pffft_sapi.sapi.h" // NOLINT(build/include) #include "pffft_sapi.sapi.h" // NOLINT(build/include)
#include "sandboxed_api/util/flag.h" #include "sandboxed_api/util/flag.h"
#include "sandboxed_api/vars.h" #include "sandboxed_api/vars.h"

View File

@ -0,0 +1,44 @@
# Copyright 2022 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
#
# https://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.13..3.22)
project(turbojpeg-sapi CXX C)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
if(NOT TARGET sapi::sapi)
set(SAPI_ROOT "../.." CACHE PATH "Path to the Sandboxed API source tree")
add_subdirectory("${SAPI_ROOT}"
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
EXCLUDE_FROM_ALL)
endif()
find_package(PkgConfig REQUIRED)
pkg_check_modules(TURBOJPEG REQUIRED IMPORTED_TARGET libturbojpeg)
add_sapi_library(turbojpeg_sapi
INPUTS "${TURBOJPEG_INCLUDEDIR}/turbojpeg.h"
LIBRARY turbojpeg
LIBRARY_NAME TurboJPEG
NAMESPACE "turbojpeg_sapi"
)
add_library(sapi_contrib::turbojpeg ALIAS turbojpeg_sapi)
target_include_directories(turbojpeg_sapi INTERFACE
"${PROJECT_BINARY_DIR}"
)
if(SAPI_ENABLE_TESTS)
add_subdirectory(tests)
endif()

View File

@ -0,0 +1,26 @@
# Copyright 2022 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
#
# https://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(GoogleTest)
add_executable(turbojpeg_sapi_test turbojpeg_sapi_test.cc)
target_link_libraries(turbojpeg_sapi_test PRIVATE
turbojpeg_sapi
sapi::base
gtest
gmock
)
gtest_discover_tests(turbojpeg_sapi_test PROPERTIES ENVIRONMENT "TEST_FILES_DIR=${PROJECT_SOURCE_DIR}/tests")

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

View File

@ -0,0 +1,181 @@
// Copyright 2022 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
//
// https://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.
#define _GNU_SOURCE 1
#include "../turbojpeg_sapi.h" // NOLINT(build/include)
#include <turbojpeg.h>
#include <cerrno>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include "gflags/gflags.h"
#include "glog/logging.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "sandboxed_api/testing.h"
#include "sandboxed_api/util/fileops.h"
#include "sandboxed_api/util/path.h"
#include "sandboxed_api/util/status_matchers.h"
#include "turbojpeg_sapi.sapi.h" // NOLINT(build/include)
namespace {
using ::sapi::IsOk;
using ::testing::Eq;
using ::testing::Gt;
using ::testing::Not;
using ::testing::NotNull;
using ::testing::StrEq;
class TurboJpegSapiSandboxTest : public testing::Test {
protected:
static void SetUpTestSuite() {
ASSERT_THAT(getenv("TEST_FILES_DIR"), NotNull());
sandbox_ = new TurboJpegSapiSandbox();
ASSERT_THAT(sandbox_->Init(), IsOk());
api_ = new turbojpeg_sapi::TurboJPEGApi(sandbox_);
}
static void TearDownTestSuite() {
delete api_;
delete sandbox_;
}
static std::string GetTurboJpegErrorStr(sapi::v::Ptr* handle) {
auto errmsg_ptr = api_->tjGetErrorStr2(handle);
if (!errmsg_ptr.ok()) return "Error getting error message";
auto errmsg =
sandbox_->GetCString(sapi::v::RemotePtr(errmsg_ptr.value()), 256);
if (!errmsg.ok()) return "Error getting error message";
return errmsg.value();
}
static turbojpeg_sapi::TurboJPEGApi* api_;
static TurboJpegSapiSandbox* sandbox_;
};
turbojpeg_sapi::TurboJPEGApi* TurboJpegSapiSandboxTest::api_;
TurboJpegSapiSandbox* TurboJpegSapiSandboxTest::sandbox_;
std::string GetTestFilePath(const std::string& filename) {
return sapi::file::JoinPath(getenv("TEST_FILES_DIR"), filename);
}
std::streamsize GetStreamSize(std::ifstream& stream) {
stream.seekg(0, std::ios_base::end);
std::streamsize ssize = stream.tellg();
stream.seekg(0, std::ios_base::beg);
return ssize;
}
absl::StatusOr<std::vector<uint8_t>> ReadFile(const std::string& in_file,
size_t expected_size = SIZE_MAX) {
std::ifstream f(GetTestFilePath(in_file));
if (!f.is_open()) {
return absl::UnavailableError("File could not be opened");
}
std::streamsize ssize = GetStreamSize(f);
if (expected_size != SIZE_MAX && ssize != expected_size) {
return absl::UnavailableError("Incorrect size of file");
}
std::vector<uint8_t> inbuf(ssize);
f.read(reinterpret_cast<char*>(inbuf.data()), ssize);
if (ssize != f.gcount()) {
return absl::UnavailableError("Premature end of file");
}
if (f.fail() || f.eof()) {
return absl::UnavailableError("Error reading file");
}
return inbuf;
}
TEST_F(TurboJpegSapiSandboxTest, Compressor) {
absl::StatusOr<void*> compression_handle_raw = api_->tjInitCompress();
ASSERT_THAT(compression_handle_raw, IsOk());
ASSERT_THAT(compression_handle_raw.value(), NotNull());
sapi::v::RemotePtr compression_handle{compression_handle_raw.value()};
auto result = ReadFile("sample.rgb", 12 * 67 * 3);
ASSERT_THAT(result, IsOk());
sapi::v::Array array(result->data(), result->size());
sapi::v::GenericPtr buffer;
{
sapi::v::ULong length{0};
auto result = api_->tjCompress2(&compression_handle, array.PtrBefore(), 12,
36, 67, TJPF_RGB, buffer.PtrAfter(),
length.PtrBoth(), TJSAMP_444, 10, 0);
ASSERT_THAT(result, IsOk());
ASSERT_THAT(result.value(), Eq(0))
<< "Error from sandboxee: "
<< GetTurboJpegErrorStr(&compression_handle);
ASSERT_TRUE(buffer.GetValue());
ASSERT_TRUE(buffer.GetRemote());
ASSERT_THAT(length.GetValue(), Gt(0));
}
auto value = buffer.GetValue();
auto destroy_result = api_->tjDestroy(&compression_handle);
ASSERT_THAT(destroy_result, IsOk());
ASSERT_THAT(destroy_result.value(), Eq(0));
}
TEST_F(TurboJpegSapiSandboxTest, Decompressor) {
absl::StatusOr<void*> decompression_handle_raw = api_->tjInitDecompress();
ASSERT_THAT(decompression_handle_raw, IsOk());
ASSERT_THAT(decompression_handle_raw.value(), NotNull());
sapi::v::RemotePtr decompression_handle{decompression_handle_raw.value()};
auto result = ReadFile("sample.jpeg");
ASSERT_THAT(result, IsOk());
sapi::v::Array array(result->data(), result->size());
sapi::v::Int width{0};
sapi::v::Int height{0};
sapi::v::Int subsamp{0};
sapi::v::Int colorspace{0};
auto decompress_result = api_->tjDecompressHeader3(
&decompression_handle, array.PtrBefore(), result->size(),
width.PtrAfter(), height.PtrAfter(), subsamp.PtrAfter(),
colorspace.PtrAfter());
ASSERT_THAT(decompress_result, IsOk());
ASSERT_THAT(decompress_result.value(), Eq(0))
<< "Error from sandboxee: "
<< GetTurboJpegErrorStr(&decompression_handle);
ASSERT_THAT(width.GetValue(), Eq(67));
ASSERT_THAT(height.GetValue(), Eq(12));
ASSERT_THAT(subsamp.GetValue(), Eq(TJSAMP_GRAY));
ASSERT_THAT(colorspace.GetValue(), Eq(TJCS_GRAY));
auto arr = sapi::v::Array<unsigned char>(12 * 67 * 3);
decompress_result = api_->tjDecompress2(
&decompression_handle, array.PtrBefore(), result->size(), arr.PtrAfter(),
12, 36, 67, TJCS_RGB, 0);
ASSERT_THAT(decompress_result, IsOk());
EXPECT_THAT(decompress_result.value(), Eq(0))
<< "Error from sandboxee: "
<< GetTurboJpegErrorStr(&decompression_handle);
decompress_result = api_->tjDestroy(&decompression_handle);
ASSERT_THAT(decompress_result, IsOk());
ASSERT_THAT(decompress_result.value(), Eq(0));
}
} // namespace
int main(int argc, char* argv[]) {
::google::InitGoogleLogging(program_invocation_short_name);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@ -0,0 +1,44 @@
// Copyright 2022 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
//
// https://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 CONTRIB_TURBOJPEG_TURBOJPEG_SAPI_H_
#define CONTRIB_TURBOJPEG_TURBOJPEG_SAPI_H_
#include <syscall.h>
#include "sandboxed_api/util/fileops.h"
#include "turbojpeg_sapi.sapi.h" // NOLINT(build/include)
class TurboJpegSapiSandbox : public turbojpeg_sapi::TurboJPEGSandbox {
public:
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
sandbox2::PolicyBuilder*) override {
return sandbox2::PolicyBuilder()
.AllowSystemMalloc()
.AllowRead()
.AllowStat()
.AllowWrite()
.AllowExit()
.AllowSyscalls({
__NR_futex,
__NR_close,
__NR_lseek,
__NR_getpid,
__NR_clock_gettime,
})
.AllowLlvmSanitizers()
.BuildOrDie();
}
};
#endif // CONTRIB_TURBOJPEG_TURBOJPEG_SAPI_H_

View File

@ -0,0 +1,68 @@
# Copyright 2022 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
#
# https://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.13..3.22)
project(sapi_zopfli CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
if(NOT TARGET sapi::sapi)
set(SAPI_ROOT "../.." CACHE PATH "Path to the Sandboxed API source tree")
add_subdirectory("${SAPI_ROOT}"
"${CMAKE_BINARY_DIR}/sandboxed-api-build"
EXCLUDE_FROM_ALL)
endif()
FetchContent_Declare(zopfli
GIT_REPOSITORY https://github.com/google/zopfli.git
GIT_TAG 831773bc28e318b91a3255fa12c9fcde1606058b
)
FetchContent_MakeAvailable(zopfli)
add_sapi_library(
sapi_zopfli
FUNCTIONS
ZopfliInitOptions
ZopfliCompress
ZopfliDeflate
ZopfliZlibCompress
ZopfliGzipCompress
INPUTS
${zopfli_SOURCE_DIR}/src/zopfli/deflate.h
${zopfli_SOURCE_DIR}/src/zopfli/gzip_container.h
${zopfli_SOURCE_DIR}/src/zopfli/zlib_container.h
LIBRARY Zopfli::libzopfli
LIBRARY_NAME Zopfli
NAMESPACE ""
)
add_library(sapi_contrib::zopfli ALIAS sapi_zopfli)
target_include_directories(sapi_zopfli INTERFACE
"${PROJECT_BINARY_DIR}"
"${SAPI_SOURCE_DIR}"
)
if(SAPI_ENABLE_EXAMPLES)
add_subdirectory(example)
endif()
if(SAPI_ENABLE_TESTS)
add_subdirectory(test)
endif()

View File

@ -0,0 +1,23 @@
# Copyright 2022 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
#
# https://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.
add_executable(sapi_minizopfli
main.cc
../utils/utils_zopfli.cc
)
target_link_libraries(sapi_minizopfli PRIVATE
sapi_contrib::zopfli
sapi::sapi
absl::flags_parse
)

View File

@ -0,0 +1,73 @@
// Copyright 2022 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
//
// https://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 <unistd.h>
#include <fstream>
#include <iostream>
#include <string>
#include "sandboxed_api/util/flag.h"
#include "absl/flags/parse.h"
#include "contrib/zopfli/sandboxed.h"
#include "contrib/zopfli/utils/utils_zopfli.h"
ABSL_FLAG(bool, zlib, false, "zlib compression");
ABSL_FLAG(bool, gzip, false, "gzip compression");
int main(int argc, char* argv[]) {
std::string prog_name(argv[0]);
google::InitGoogleLogging(argv[0]);
std::vector<char*> args = absl::ParseCommandLine(argc, argv);
if (args.size() != 3) {
std::cerr << "Usage:\n " << prog_name << " INPUT OUTPUT\n";
return EXIT_FAILURE;
}
std::ifstream infile(args[1], std::ios::binary);
if (!infile.is_open()) {
std::cerr << "Unable to open " << args[1] << std::endl;
return EXIT_FAILURE;
}
std::ofstream outfile(args[2], std::ios::binary);
if (!outfile.is_open()) {
std::cerr << "Unable to open " << args[2] << std::endl;
return EXIT_FAILURE;
}
ZopfliSapiSandbox sandbox;
if (!sandbox.Init().ok()) {
std::cerr << "Unable to start sandbox\n";
return EXIT_FAILURE;
}
ZopfliApi api(&sandbox);
ZopfliFormat format = ZOPFLI_FORMAT_DEFLATE;
if (absl::GetFlag(FLAGS_zlib)) {
format = ZOPFLI_FORMAT_ZLIB;
} else if (absl::GetFlag(FLAGS_gzip)) {
format = ZOPFLI_FORMAT_GZIP;
}
absl::Status status = Compress(api, infile, outfile, format);
if (!status.ok()) {
std::cerr << "Unable to compress file.\n";
std::cerr << status << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

BIN
contrib/zopfli/files/binary Normal file

Binary file not shown.

2000
contrib/zopfli/files/text Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,49 @@
// Copyright 2022 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
//
// https://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 CONTRIB_ZOPFLI_SANDBOXED_
#define CONTRIB_ZOPFLI_SANDBOXED_
#include <libgen.h>
#include <syscall.h>
#include <cerrno>
#include <memory>
#include "sapi_zopfli.sapi.h" // NOLINT(build/include)
class ZopfliSapiSandbox : public ZopfliSandbox {
public:
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
sandbox2::PolicyBuilder *) override {
return sandbox2::PolicyBuilder()
.AllowStaticStartup()
.AllowWrite()
.AllowExit()
.AllowMmap()
.AllowSystemMalloc()
.AllowSyscalls({
__NR_sysinfo,
})
#ifdef __NR_open
.BlockSyscallWithErrno(__NR_open, ENOENT)
#endif
#ifdef __NR_openat
.BlockSyscallWithErrno(__NR_openat, ENOENT)
#endif
.BuildOrDie();
}
};
#endif // CONTRIB_ZOPFLI_SANDBOXED_

View File

@ -0,0 +1,28 @@
# Copyright 2022 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
#
# https://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(GoogleTest)
add_executable(sapi_zopfli_test
zopfli_test.cc
../utils/utils_zopfli.cc
)
target_link_libraries(sapi_zopfli_test PRIVATE
sapi_contrib::zopfli
sapi::temp_file
sapi::test_main
)
gtest_discover_tests(sapi_zopfli_test PROPERTIES
ENVIRONMENT "TEST_FILES_DIR=${PROJECT_SOURCE_DIR}/files"
)

View File

@ -0,0 +1,98 @@
// Copyright 2022 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
//
// https://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 <fstream>
#include "contrib/zopfli/sandboxed.h"
#include "contrib/zopfli/utils/utils_zopfli.h"
#include "sandboxed_api/util/path.h"
#include "sandboxed_api/util/status_matchers.h"
#include "sandboxed_api/util/temp_file.h"
namespace {
using ::sapi::IsOk;
using ::testing::IsEmpty;
using ::testing::Not;
std::string GetTestFilePath(const std::string& filename) {
return sapi::file::JoinPath(getenv("TEST_FILES_DIR"), filename);
}
std::string GetTemporaryFile(const std::string& filename) {
absl::StatusOr<std::string> tmp_file =
sapi::CreateNamedTempFileAndClose(filename);
if (!tmp_file.ok()) {
return "";
}
return sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), *tmp_file);
}
class TestText : public testing::TestWithParam<ZopfliFormat> {};
class TestBinary : public testing::TestWithParam<ZopfliFormat> {};
TEST_P(TestText, Compress) {
ZopfliSapiSandbox sandbox;
ASSERT_THAT(sandbox.Init(), IsOk()) << "Couldn't initialize Sandboxed API";
ZopfliApi api(&sandbox);
std::string infile_s = GetTestFilePath("text");
std::string outfile_s = GetTemporaryFile("text.out");
ASSERT_THAT(outfile_s, Not(IsEmpty()));
std::ifstream infile(infile_s, std::ios::binary);
ASSERT_TRUE(infile.is_open());
std::ofstream outfile(outfile_s, std::ios::binary);
ASSERT_TRUE(outfile.is_open());
absl::Status status = Compress(api, infile, outfile, GetParam());
ASSERT_THAT(status, IsOk()) << "Unable to compress file";
ASSERT_LT(outfile.tellp(), infile.tellg());
}
INSTANTIATE_TEST_SUITE_P(SandboxTest, TestText,
testing::Values(ZOPFLI_FORMAT_DEFLATE,
ZOPFLI_FORMAT_GZIP,
ZOPFLI_FORMAT_ZLIB));
TEST_P(TestBinary, Compress) {
ZopfliSapiSandbox sandbox;
ASSERT_THAT(sandbox.Init(), IsOk()) << "Couldn't initialize Sandboxed API";
ZopfliApi api(&sandbox);
std::string infile_s = GetTestFilePath("binary");
std::string outfile_s = GetTemporaryFile("binary.out");
ASSERT_THAT(outfile_s, Not(IsEmpty()));
std::ifstream infile(infile_s, std::ios::binary);
ASSERT_TRUE(infile.is_open());
std::ofstream outfile(outfile_s, std::ios::binary);
ASSERT_TRUE(outfile.is_open());
absl::Status status = Compress(api, infile, outfile, GetParam());
ASSERT_THAT(status, IsOk()) << "Unable to compress file";
ASSERT_LT(outfile.tellp(), infile.tellg());
}
INSTANTIATE_TEST_SUITE_P(SandboxTest, TestBinary,
testing::Values(ZOPFLI_FORMAT_DEFLATE,
ZOPFLI_FORMAT_GZIP,
ZOPFLI_FORMAT_ZLIB));
} // namespace

View File

@ -0,0 +1,56 @@
// Copyright 2022 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
//
// https://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 "contrib/zopfli/utils/utils_zopfli.h"
#include <unistd.h>
#include <fstream>
absl::Status Compress(ZopfliApi& api, std::ifstream& instream,
std::ofstream& outstream, ZopfliFormat format) {
// Get size of Stream
instream.seekg(0, std::ios_base::end);
std::streamsize ssize = instream.tellg();
instream.seekg(0, std::ios_base::beg);
// Read data
sapi::v::Array<uint8_t> inbuf(ssize);
instream.read(reinterpret_cast<char*>(inbuf.GetData()), ssize);
if (instream.gcount() != ssize) {
return absl::UnavailableError("Unable to read file");
}
// Compress
sapi::v::Struct<ZopfliOptions> options;
SAPI_RETURN_IF_ERROR(api.ZopfliInitOptions(options.PtrAfter()));
sapi::v::GenericPtr outptr;
sapi::v::IntBase<size_t> outsize(0);
SAPI_RETURN_IF_ERROR(
api.ZopfliCompress(options.PtrBefore(), format, inbuf.PtrBefore(), ssize,
outptr.PtrAfter(), outsize.PtrBoth()));
// Get and save data
sapi::v::Array<int8_t> outbuf(outsize.GetValue());
outbuf.SetRemote(reinterpret_cast<void*>(outptr.GetValue()));
SAPI_RETURN_IF_ERROR(api.GetSandbox()->TransferFromSandboxee(&outbuf));
outstream.write(reinterpret_cast<char*>(outbuf.GetData()), outbuf.GetSize());
if (!outstream.good()) {
return absl::UnavailableError("Unable to write file");
}
return absl::OkStatus();
}

View File

@ -0,0 +1,26 @@
// Copyright 2022 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
//
// https://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 CONTRIB_ZOPFLI_UTILS_UTILS_ZOPFLI_H_
#define CONTRIB_ZOPFLI_UTILS_UTILS_ZOPFLI_H_
#include <fstream>
#include "absl/status/status.h"
#include "contrib/zopfli/sandboxed.h"
absl::Status Compress(ZopfliApi& api, std::ifstream& instream,
std::ofstream& outstream, ZopfliFormat format);
#endif // CONTRIB_ZOPFLI_UTILS_UTILS_ZOPFLI_H_

View File

@ -34,6 +34,8 @@ FetchContent_Declare(libzstd
FetchContent_MakeAvailable(libzstd) FetchContent_MakeAvailable(libzstd)
set(libzstd_INCLUDE_DIR "${libzstd_SOURCE_DIR}/lib") set(libzstd_INCLUDE_DIR "${libzstd_SOURCE_DIR}/lib")
add_subdirectory(wrapper)
add_sapi_library( add_sapi_library(
sapi_zstd sapi_zstd
@ -70,10 +72,16 @@ add_sapi_library(
ZSTD_getFrameContentSize ZSTD_getFrameContentSize
ZSTD_compress_fd
ZSTD_compressStream_fd
ZSTD_decompress_fd
ZSTD_decompressStream_fd
INPUTS INPUTS
${libzstd_INCLUDE_DIR}/zstd.h ${libzstd_INCLUDE_DIR}/zstd.h
wrapper/wrapper_zstd.h
LIBRARY libzstd_static LIBRARY wrapper_zstd
LIBRARY_NAME Zstd LIBRARY_NAME Zstd
NAMESPACE "" NAMESPACE ""
) )

View File

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <cstdlib> #include <cstdlib>
@ -25,10 +26,56 @@
#include "contrib/zstd/sandboxed.h" #include "contrib/zstd/sandboxed.h"
#include "contrib/zstd/utils/utils_zstd.h" #include "contrib/zstd/utils/utils_zstd.h"
ABSL_FLAG(bool, stream, false, "stream data to sandbox");
ABSL_FLAG(bool, decompress, false, "decompress"); ABSL_FLAG(bool, decompress, false, "decompress");
ABSL_FLAG(bool, memory_mode, false, "in memory operations"); ABSL_FLAG(bool, memory_mode, false, "in memory operations");
ABSL_FLAG(uint32_t, level, 0, "compression level"); ABSL_FLAG(uint32_t, level, 0, "compression level");
absl::Status Stream(ZstdApi& api, std::string infile_s, std::string outfile_s) {
std::ifstream infile(infile_s, std::ios::binary);
if (!infile.is_open()) {
return absl::UnavailableError(absl::StrCat("Unable to open ", infile_s));
}
std::ofstream outfile(outfile_s, std::ios::binary);
if (!outfile.is_open()) {
return absl::UnavailableError(absl::StrCat("Unable to open ", outfile_s));
}
if (absl::GetFlag(FLAGS_memory_mode)) {
if (absl::GetFlag(FLAGS_decompress)) {
return DecompressInMemory(api, infile, outfile);
}
return CompressInMemory(api, infile, outfile, absl::GetFlag(FLAGS_level));
}
if (absl::GetFlag(FLAGS_decompress)) {
return DecompressStream(api, infile, outfile);
}
return CompressStream(api, infile, outfile, absl::GetFlag(FLAGS_level));
}
absl::Status FileDescriptor(ZstdApi& api, std::string infile_s,
std::string outfile_s) {
sapi::v::Fd infd(open(infile_s.c_str(), O_RDONLY));
if (infd.GetValue() < 0) {
return absl::UnavailableError(absl::StrCat("Unable to open ", infile_s));
}
sapi::v::Fd outfd(open(outfile_s.c_str(), O_WRONLY | O_CREAT));
if (outfd.GetValue() < 0) {
return absl::UnavailableError(absl::StrCat("Unable to open ", outfile_s));
}
if (absl::GetFlag(FLAGS_memory_mode)) {
if (absl::GetFlag(FLAGS_decompress)) {
return DecompressInMemoryFD(api, infd, outfd);
}
return CompressInMemoryFD(api, infd, outfd, absl::GetFlag(FLAGS_level));
}
if (absl::GetFlag(FLAGS_decompress)) {
return DecompressStreamFD(api, infd, outfd);
}
return CompressStreamFD(api, infd, outfd, absl::GetFlag(FLAGS_level));
}
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
std::string prog_name(argv[0]); std::string prog_name(argv[0]);
google::InitGoogleLogging(argv[0]); google::InitGoogleLogging(argv[0]);
@ -39,17 +86,6 @@ int main(int argc, char* argv[]) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
std::ifstream infile(args[1], std::ios::binary);
if (!infile.is_open()) {
std::cerr << "Unable to open " << args[1] << std::endl;
return EXIT_FAILURE;
}
std::ofstream outfile(args[2], std::ios::binary);
if (!outfile.is_open()) {
std::cerr << "Unable to open " << args[2] << std::endl;
return EXIT_FAILURE;
}
ZstdSapiSandbox sandbox; ZstdSapiSandbox sandbox;
if (!sandbox.Init().ok()) { if (!sandbox.Init().ok()) {
std::cerr << "Unable to start sandbox\n"; std::cerr << "Unable to start sandbox\n";
@ -59,16 +95,10 @@ int main(int argc, char* argv[]) {
ZstdApi api(&sandbox); ZstdApi api(&sandbox);
absl::Status status; absl::Status status;
if (absl::GetFlag(FLAGS_memory_mode) && absl::GetFlag(FLAGS_decompress)) { if (absl::GetFlag(FLAGS_stream)) {
status = DecompressInMemory(api, infile, outfile); status = Stream(api, argv[1], argv[2]);
} else if (absl::GetFlag(FLAGS_memory_mode) &&
!absl::GetFlag(FLAGS_decompress)) {
status = CompressInMemory(api, infile, outfile, absl::GetFlag(FLAGS_level));
} else if (!absl::GetFlag(FLAGS_memory_mode) &&
absl::GetFlag(FLAGS_decompress)) {
status = DecompressStream(api, infile, outfile);
} else { } else {
status = CompressStream(api, infile, outfile, absl::GetFlag(FLAGS_level)); status = FileDescriptor(api, argv[1], argv[2]);
} }
if (!status.ok()) { if (!status.ok()) {

View File

@ -27,10 +27,12 @@ class ZstdSapiSandbox : public ZstdSandbox {
std::unique_ptr<sandbox2::Policy> ModifyPolicy( std::unique_ptr<sandbox2::Policy> ModifyPolicy(
sandbox2::PolicyBuilder*) override { sandbox2::PolicyBuilder*) override {
return sandbox2::PolicyBuilder() return sandbox2::PolicyBuilder()
.AllowDynamicStartup()
.AllowRead() .AllowRead()
.AllowWrite() .AllowWrite()
.AllowSystemMalloc() .AllowSystemMalloc()
.AllowExit() .AllowExit()
.AllowSyscalls({__NR_recvmsg})
.BuildOrDie(); .BuildOrDie();
} }
}; };

View File

@ -12,6 +12,9 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#include <fcntl.h>
#include <unistd.h>
#include <fstream> #include <fstream>
#include <string> #include <string>
@ -101,11 +104,10 @@ TEST(SandboxTest, CheckCompressInMemory) {
std::string infile_s = GetTestFilePath("text"); std::string infile_s = GetTestFilePath("text");
absl::StatusOr<std::string> path = SAPI_ASSERT_OK_AND_ASSIGN(std::string path,
sapi::CreateNamedTempFileAndClose("out.zstd"); sapi::CreateNamedTempFileAndClose("out.zstd"));
ASSERT_THAT(path, IsOk()) << "Could not create temp output file";
std::string outfile_s = std::string outfile_s =
sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), *path); sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), path);
std::ifstream infile(infile_s, std::ios::binary); std::ifstream infile(infile_s, std::ios::binary);
ASSERT_TRUE(infile.is_open()); ASSERT_TRUE(infile.is_open());
@ -126,10 +128,10 @@ TEST(SandboxTest, CheckDecompressInMemory) {
std::string infile_s = GetTestFilePath("text.blob.zstd"); std::string infile_s = GetTestFilePath("text.blob.zstd");
absl::StatusOr<std::string> path = sapi::CreateNamedTempFileAndClose("out"); SAPI_ASSERT_OK_AND_ASSIGN(std::string path,
ASSERT_THAT(path, IsOk()) << "Could not create temp output file"; sapi::CreateNamedTempFileAndClose("out"));
std::string outfile_s = std::string outfile_s =
sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), *path); sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), path);
std::ifstream infile(infile_s, std::ios::binary); std::ifstream infile(infile_s, std::ios::binary);
ASSERT_TRUE(infile.is_open()); ASSERT_TRUE(infile.is_open());
@ -153,16 +155,15 @@ TEST(SandboxTest, CheckCompressAndDecompressInMemory) {
std::string infile_s = GetTestFilePath("text"); std::string infile_s = GetTestFilePath("text");
absl::StatusOr<std::string> path_middle = SAPI_ASSERT_OK_AND_ASSIGN(std::string path_middle,
sapi::CreateNamedTempFileAndClose("middle.zstd"); sapi::CreateNamedTempFileAndClose("middle.zstd"));
ASSERT_THAT(path_middle, IsOk()) << "Could not create temp output file";
std::string middle_s = std::string middle_s =
sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), *path_middle); sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), path_middle);
absl::StatusOr<std::string> path = sapi::CreateNamedTempFileAndClose("out"); SAPI_ASSERT_OK_AND_ASSIGN(std::string path,
ASSERT_THAT(path, IsOk()) << "Could not create temp output file"; sapi::CreateNamedTempFileAndClose("out"));
std::string outfile_s = std::string outfile_s =
sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), *path); sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), path);
std::ifstream infile(infile_s, std::ios::binary); std::ifstream infile(infile_s, std::ios::binary);
ASSERT_TRUE(infile.is_open()); ASSERT_TRUE(infile.is_open());
@ -193,12 +194,10 @@ TEST(SandboxTest, CheckCompressStream) {
ZstdApi api = ZstdApi(&sandbox); ZstdApi api = ZstdApi(&sandbox);
std::string infile_s = GetTestFilePath("text"); std::string infile_s = GetTestFilePath("text");
SAPI_ASSERT_OK_AND_ASSIGN(std::string path,
absl::StatusOr<std::string> path = sapi::CreateNamedTempFileAndClose("out.zstd"));
sapi::CreateNamedTempFileAndClose("out.zstd");
ASSERT_THAT(path, IsOk()) << "Could not create temp output file";
std::string outfile_s = std::string outfile_s =
sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), *path); sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), path);
std::ifstream infile(infile_s, std::ios::binary); std::ifstream infile(infile_s, std::ios::binary);
ASSERT_TRUE(infile.is_open()); ASSERT_TRUE(infile.is_open());
@ -220,11 +219,10 @@ TEST(SandboxTest, CheckDecompressStream) {
ZstdApi api = ZstdApi(&sandbox); ZstdApi api = ZstdApi(&sandbox);
std::string infile_s = GetTestFilePath("text.stream.zstd"); std::string infile_s = GetTestFilePath("text.stream.zstd");
SAPI_ASSERT_OK_AND_ASSIGN(std::string path,
absl::StatusOr<std::string> path = sapi::CreateNamedTempFileAndClose("out"); sapi::CreateNamedTempFileAndClose("out"));
ASSERT_THAT(path, IsOk()) << "Could not create temp output file";
std::string outfile_s = std::string outfile_s =
sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), *path); sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), path);
std::ifstream infile(infile_s, std::ios::binary); std::ifstream infile(infile_s, std::ios::binary);
ASSERT_TRUE(infile.is_open()); ASSERT_TRUE(infile.is_open());
@ -248,16 +246,15 @@ TEST(SandboxTest, CheckCompressAndDecompressStream) {
std::string infile_s = GetTestFilePath("text"); std::string infile_s = GetTestFilePath("text");
absl::StatusOr<std::string> path_middle = SAPI_ASSERT_OK_AND_ASSIGN(std::string path_middle,
sapi::CreateNamedTempFileAndClose("middle.zstd"); sapi::CreateNamedTempFileAndClose("middle.zstd"));
ASSERT_THAT(path_middle, IsOk()) << "Could not create temp output file";
std::string middle_s = std::string middle_s =
sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), *path_middle); sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), path_middle);
absl::StatusOr<std::string> path = sapi::CreateNamedTempFileAndClose("out"); SAPI_ASSERT_OK_AND_ASSIGN(std::string path,
ASSERT_THAT(path, IsOk()) << "Could not create temp output file"; sapi::CreateNamedTempFileAndClose("out"));
std::string outfile_s = std::string outfile_s =
sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), *path); sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), path);
std::ifstream infile(infile_s, std::ios::binary); std::ifstream infile(infile_s, std::ios::binary);
ASSERT_TRUE(infile.is_open()); ASSERT_TRUE(infile.is_open());
@ -278,8 +275,235 @@ TEST(SandboxTest, CheckCompressAndDecompressStream) {
ASSERT_TRUE(outfile.is_open()); ASSERT_TRUE(outfile.is_open());
status = DecompressStream(api, inmiddle, outfile); status = DecompressStream(api, inmiddle, outfile);
ASSERT_THAT(status, IsOk()) << "Unable to decompress";
ASSERT_TRUE(CompareFiles(infile_s, outfile_s));
}
TEST(SandboxTest, CheckCompressInMemoryFD) {
ZstdSapiSandbox sandbox;
ASSERT_THAT(sandbox.Init(), IsOk()) << "Couldn't initialize Sandboxed API";
ZstdApi api = ZstdApi(&sandbox);
std::string infile_s = GetTestFilePath("text");
SAPI_ASSERT_OK_AND_ASSIGN(std::string path,
sapi::CreateNamedTempFileAndClose("out.zstd"));
std::string outfile_s =
sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), path);
sapi::v::Fd infd(open(infile_s.c_str(), O_RDONLY));
ASSERT_GE(infd.GetValue(), 0);
sapi::v::Fd outfd(open(outfile_s.c_str(), O_WRONLY));
ASSERT_GE(outfd.GetValue(), 0);
absl::Status status = CompressInMemoryFD(api, infd, outfd, 0);
ASSERT_THAT(status, IsOk()) << "Unable to compress file in memory";
off_t inpos = lseek(infd.GetValue(), 0, SEEK_END);
EXPECT_GE(inpos, 0);
off_t outpos = lseek(outfd.GetValue(), 0, SEEK_END);
EXPECT_GE(outpos, 0);
EXPECT_LT(outpos, inpos);
}
TEST(SandboxTest, CheckDecompressInMemoryFD) {
ZstdSapiSandbox sandbox;
ASSERT_THAT(sandbox.Init(), IsOk()) << "Couldn't initialize Sandboxed API";
ZstdApi api = ZstdApi(&sandbox);
std::string infile_s = GetTestFilePath("text.blob.zstd");
sapi::v::Fd infd(open(infile_s.c_str(), O_RDONLY));
ASSERT_GE(infd.GetValue(), 0);
SAPI_ASSERT_OK_AND_ASSIGN(std::string path,
sapi::CreateNamedTempFileAndClose("out"));
std::string outfile_s =
sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), path);
sapi::v::Fd outfd(open(outfile_s.c_str(), O_WRONLY));
ASSERT_GE(outfd.GetValue(), 0);
absl::Status status = DecompressInMemoryFD(api, infd, outfd);
ASSERT_THAT(status, IsOk()) << "Unable to compress file in memory";
off_t inpos = lseek(infd.GetValue(), 0, SEEK_END);
EXPECT_GE(inpos, 0);
off_t outpos = lseek(outfd.GetValue(), 0, SEEK_END);
EXPECT_GE(outpos, 0);
EXPECT_GT(outpos, inpos);
ASSERT_TRUE(CompareFiles(GetTestFilePath("text"), outfile_s));
}
TEST(SandboxTest, CheckCompressAndDecompressInMemoryFD) {
ZstdSapiSandbox sandbox;
absl::Status status;
int ret;
ASSERT_THAT(sandbox.Init(), IsOk()) << "Couldn't initialize Sandboxed API";
ZstdApi api = ZstdApi(&sandbox);
std::string infile_s = GetTestFilePath("text");
SAPI_ASSERT_OK_AND_ASSIGN(std::string path_middle,
sapi::CreateNamedTempFileAndClose("middle.zstd"));
std::string middle_s =
sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), path_middle);
SAPI_ASSERT_OK_AND_ASSIGN(std::string path,
sapi::CreateNamedTempFileAndClose("out"));
std::string outfile_s =
sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), path);
sapi::v::Fd infd(open(infile_s.c_str(), O_RDONLY));
ASSERT_GE(infd.GetValue(), 0);
sapi::v::Fd outmiddlefd(open(middle_s.c_str(), O_WRONLY));
ASSERT_GE(outmiddlefd.GetValue(), 0);
status = CompressInMemoryFD(api, infd, outmiddlefd, 0);
ASSERT_THAT(status, IsOk()) << "Unable to compress file in memory";
off_t inpos = lseek(infd.GetValue(), 0, SEEK_END);
EXPECT_GE(inpos, 0);
off_t outpos = lseek(outmiddlefd.GetValue(), 0, SEEK_END);
EXPECT_GE(outpos, 0);
EXPECT_LT(outpos, inpos);
infd.CloseLocalFd();
outmiddlefd.CloseLocalFd();
sapi::v::Fd inmiddlefd(open(middle_s.c_str(), O_RDONLY));
ASSERT_GE(inmiddlefd.GetValue(), 0);
sapi::v::Fd outfd(open(outfile_s.c_str(), O_WRONLY));
ASSERT_GE(outfd.GetValue(), 0);
status = DecompressInMemoryFD(api, inmiddlefd, outfd);
ASSERT_THAT(status, IsOk()) << "Unable to decompress file in memory"; ASSERT_THAT(status, IsOk()) << "Unable to decompress file in memory";
outfd.CloseLocalFd();
inmiddlefd.CloseLocalFd();
ASSERT_TRUE(CompareFiles(infile_s, outfile_s));
}
TEST(SandboxTest, CheckCompressStreamFD) {
absl::Status status;
ZstdSapiSandbox sandbox;
ASSERT_THAT(sandbox.Init(), IsOk()) << "Couldn't initialize Sandboxed API";
ZstdApi api = ZstdApi(&sandbox);
std::string infile_s = GetTestFilePath("text");
SAPI_ASSERT_OK_AND_ASSIGN(std::string path,
sapi::CreateNamedTempFileAndClose("out.zstd"));
std::string outfile_s =
sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), path);
sapi::v::Fd infd(open(infile_s.c_str(), O_RDONLY));
ASSERT_GE(infd.GetValue(), 0);
sapi::v::Fd outfd(open(outfile_s.c_str(), O_WRONLY));
ASSERT_GE(outfd.GetValue(), 0);
status = CompressStreamFD(api, infd, outfd, 0);
ASSERT_THAT(status, IsOk()) << "Unable to compress stream";
off_t inpos = lseek(infd.GetValue(), 0, SEEK_END);
EXPECT_GE(inpos, 0);
off_t outpos = lseek(outfd.GetValue(), 0, SEEK_END);
EXPECT_GE(outpos, 0);
EXPECT_LT(outpos, inpos);
}
TEST(SandboxTest, CheckDecompressStreamFD) {
absl::Status status;
ZstdSapiSandbox sandbox;
ASSERT_THAT(sandbox.Init(), IsOk()) << "Couldn't initialize Sandboxed API";
ZstdApi api = ZstdApi(&sandbox);
std::string infile_s = GetTestFilePath("text.stream.zstd");
SAPI_ASSERT_OK_AND_ASSIGN(std::string path,
sapi::CreateNamedTempFileAndClose("out"));
std::string outfile_s =
sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), path);
sapi::v::Fd infd(open(infile_s.c_str(), O_RDONLY));
ASSERT_GE(infd.GetValue(), 0);
sapi::v::Fd outfd(open(outfile_s.c_str(), O_WRONLY));
ASSERT_GE(outfd.GetValue(), 0);
status = DecompressStreamFD(api, infd, outfd);
ASSERT_THAT(status, IsOk()) << "Unable to decompress stream";
off_t inpos = lseek(infd.GetValue(), 0, SEEK_END);
EXPECT_GE(inpos, 0);
off_t outpos = lseek(outfd.GetValue(), 0, SEEK_END);
EXPECT_GE(outpos, 0);
EXPECT_GT(outpos, inpos);
ASSERT_TRUE(CompareFiles(GetTestFilePath("text"), outfile_s));
}
TEST(SandboxTest, CheckCompressAndDecompressStreamFD) {
ZstdSapiSandbox sandbox;
absl::Status status;
int ret;
ASSERT_THAT(sandbox.Init(), IsOk()) << "Couldn't initialize Sandboxed API";
ZstdApi api = ZstdApi(&sandbox);
std::string infile_s = GetTestFilePath("text");
SAPI_ASSERT_OK_AND_ASSIGN(std::string path_middle,
sapi::CreateNamedTempFileAndClose("middle.zstd"));
std::string middle_s =
sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), path_middle);
SAPI_ASSERT_OK_AND_ASSIGN(std::string path,
sapi::CreateNamedTempFileAndClose("out"));
std::string outfile_s =
sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), path);
sapi::v::Fd infd(open(infile_s.c_str(), O_RDONLY));
ASSERT_GE(infd.GetValue(), 0);
sapi::v::Fd outmiddlefd(open(middle_s.c_str(), O_WRONLY));
ASSERT_GE(outmiddlefd.GetValue(), 0);
status = CompressStreamFD(api, infd, outmiddlefd, 0);
ASSERT_THAT(status, IsOk()) << "Unable to compress stream";
off_t inpos = lseek(infd.GetValue(), 0, SEEK_END);
EXPECT_GE(inpos, 0);
off_t outmiddlepos = lseek(outmiddlefd.GetValue(), 0, SEEK_END);
EXPECT_GE(outmiddlepos, 0);
EXPECT_LT(outmiddlepos, inpos);
infd.CloseLocalFd();
outmiddlefd.CloseLocalFd();
sapi::v::Fd inmiddlefd(open(middle_s.c_str(), O_RDONLY));
ASSERT_GE(inmiddlefd.GetValue(), 0);
sapi::v::Fd outfd(open(outfile_s.c_str(), O_WRONLY));
ASSERT_GE(outfd.GetValue(), 0);
status = DecompressStreamFD(api, inmiddlefd, outfd);
ASSERT_THAT(status, IsOk()) << "Unable to decompress stream";
ASSERT_TRUE(CompareFiles(infile_s, outfile_s)); ASSERT_TRUE(CompareFiles(infile_s, outfile_s));
} }

View File

@ -241,3 +241,95 @@ absl::Status DecompressStream(ZstdApi& api, std::ifstream& in_stream,
return absl::OkStatus(); return absl::OkStatus();
} }
absl::Status CompressInMemoryFD(ZstdApi& api, sapi::v::Fd& infd,
sapi::v::Fd& outfd, int level) {
SAPI_RETURN_IF_ERROR(api.GetSandbox()->TransferToSandboxee(&infd));
SAPI_RETURN_IF_ERROR(api.GetSandbox()->TransferToSandboxee(&outfd));
SAPI_ASSIGN_OR_RETURN(
int iserr,
api.ZSTD_compress_fd(infd.GetRemoteFd(), outfd.GetRemoteFd(), 0));
SAPI_ASSIGN_OR_RETURN(iserr, api.ZSTD_isError(iserr))
if (iserr) {
return absl::UnavailableError("Unable to compress file");
}
infd.CloseRemoteFd(api.GetSandbox()->rpc_channel()).IgnoreError();
outfd.CloseRemoteFd(api.GetSandbox()->rpc_channel()).IgnoreError();
return absl::OkStatus();
}
absl::Status DecompressInMemoryFD(ZstdApi& api, sapi::v::Fd& infd,
sapi::v::Fd& outfd) {
SAPI_RETURN_IF_ERROR(api.GetSandbox()->TransferToSandboxee(&infd));
SAPI_RETURN_IF_ERROR(api.GetSandbox()->TransferToSandboxee(&outfd));
SAPI_ASSIGN_OR_RETURN(int iserr, api.ZSTD_decompress_fd(infd.GetRemoteFd(),
outfd.GetRemoteFd()));
SAPI_ASSIGN_OR_RETURN(iserr, api.ZSTD_isError(iserr))
if (iserr) {
return absl::UnavailableError("Unable to compress file");
}
infd.CloseRemoteFd(api.GetSandbox()->rpc_channel()).IgnoreError();
outfd.CloseRemoteFd(api.GetSandbox()->rpc_channel()).IgnoreError();
return absl::OkStatus();
}
absl::Status CompressStreamFD(ZstdApi& api, sapi::v::Fd& infd,
sapi::v::Fd& outfd, int level) {
SAPI_ASSIGN_OR_RETURN(ZSTD_CCtx * cctx, api.ZSTD_createCCtx());
sapi::v::RemotePtr rcctx(cctx);
int iserr;
SAPI_ASSIGN_OR_RETURN(iserr, api.ZSTD_CCtx_setParameter(
&rcctx, ZSTD_c_compressionLevel, level));
SAPI_ASSIGN_OR_RETURN(iserr, api.ZSTD_isError(iserr));
if (iserr) {
return absl::UnavailableError("Unable to set parameter l");
}
SAPI_ASSIGN_OR_RETURN(
iserr, api.ZSTD_CCtx_setParameter(&rcctx, ZSTD_c_checksumFlag, 1));
SAPI_ASSIGN_OR_RETURN(iserr, api.ZSTD_isError(iserr));
if (iserr) {
return absl::UnavailableError("Unable to set parameter c");
}
SAPI_RETURN_IF_ERROR(api.GetSandbox()->TransferToSandboxee(&infd));
SAPI_RETURN_IF_ERROR(api.GetSandbox()->TransferToSandboxee(&outfd));
SAPI_ASSIGN_OR_RETURN(iserr,
api.ZSTD_compressStream_fd(&rcctx, infd.GetRemoteFd(),
outfd.GetRemoteFd()));
if (iserr) {
return absl::UnavailableError("Unable to compress");
}
infd.CloseRemoteFd(api.GetSandbox()->rpc_channel()).IgnoreError();
outfd.CloseRemoteFd(api.GetSandbox()->rpc_channel()).IgnoreError();
return absl::OkStatus();
}
absl::Status DecompressStreamFD(ZstdApi& api, sapi::v::Fd& infd,
sapi::v::Fd& outfd) {
SAPI_ASSIGN_OR_RETURN(ZSTD_DCtx * dctx, api.ZSTD_createDCtx());
sapi::v::RemotePtr rdctx(dctx);
SAPI_RETURN_IF_ERROR(api.GetSandbox()->TransferToSandboxee(&infd));
SAPI_RETURN_IF_ERROR(api.GetSandbox()->TransferToSandboxee(&outfd));
SAPI_ASSIGN_OR_RETURN(int iserr,
api.ZSTD_decompressStream_fd(&rdctx, infd.GetRemoteFd(),
outfd.GetRemoteFd()));
if (iserr) {
return absl::UnavailableError("Unable to decompress");
}
infd.CloseRemoteFd(api.GetSandbox()->rpc_channel()).IgnoreError();
outfd.CloseRemoteFd(api.GetSandbox()->rpc_channel()).IgnoreError();
return absl::OkStatus();
}

View File

@ -24,10 +24,18 @@ absl::Status CompressInMemory(ZstdApi& api, std::ifstream& in_stream,
std::ofstream& out_stream, int level); std::ofstream& out_stream, int level);
absl::Status DecompressInMemory(ZstdApi& api, std::ifstream& in_stream, absl::Status DecompressInMemory(ZstdApi& api, std::ifstream& in_stream,
std::ofstream& out_stream); std::ofstream& out_stream);
absl::Status CompressInMemoryFD(ZstdApi& api, sapi::v::Fd& infd,
sapi::v::Fd& outfd, int level);
absl::Status DecompressInMemoryFD(ZstdApi& api, sapi::v::Fd& infd,
sapi::v::Fd& outfd);
absl::Status CompressStream(ZstdApi& api, std::ifstream& in_stream, absl::Status CompressStream(ZstdApi& api, std::ifstream& in_stream,
std::ofstream& out_stream, int level); std::ofstream& out_stream, int level);
absl::Status DecompressStream(ZstdApi& api, std::ifstream& in_stream, absl::Status DecompressStream(ZstdApi& api, std::ifstream& in_stream,
std::ofstream& out_stream); std::ofstream& out_stream);
absl::Status CompressStreamFD(ZstdApi& api, sapi::v::Fd& infd,
sapi::v::Fd& outfd, int level);
absl::Status DecompressStreamFD(ZstdApi& api, sapi::v::Fd& infd,
sapi::v::Fd& outfd);
#endif // CONTRIB_ZSTD_UTILS_UTILS_ZSTD_H_ #endif // CONTRIB_ZSTD_UTILS_UTILS_ZSTD_H_

View File

@ -0,0 +1,24 @@
# Copyright 2022 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
#
# https://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.
add_library(wrapper_zstd STATIC
wrapper_zstd.cc
)
target_link_libraries(wrapper_zstd PUBLIC
libzstd_static
)
target_include_directories(wrapper_zstd PUBLIC
"${SAPI_SOURCE_DIR}"
"${libzstd_INCLUDE_DIR}"
)

View File

@ -0,0 +1,182 @@
// Copyright 2022 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
//
// https://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 "contrib/zstd/wrapper/wrapper_zstd.h"
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <memory>
constexpr size_t kFileMaxSize = 1024 * 1024 * 1024; // 1GB
off_t FDGetSize(int fd) {
off_t size = lseek(fd, 0, SEEK_END);
if (size < 0) {
return -1;
}
if (lseek(fd, 0, SEEK_SET) < 0) {
return -1;
}
return size;
}
int ZSTD_compress_fd(int fdin, int fdout, int level) {
off_t sizein = FDGetSize(fdin);
if (sizein <= 0) {
return -1;
}
size_t sizeout = ZSTD_compressBound(sizein);
auto bufin = std::make_unique<int8_t[]>(sizein);
auto bufout = std::make_unique<int8_t[]>(sizeout);
if (read(fdin, bufin.get(), sizein) != sizein) {
return -1;
}
int retsize =
ZSTD_compress(bufout.get(), sizeout, bufin.get(), sizein, level);
if (ZSTD_isError(retsize)) {
return -1;
}
if (write(fdout, bufout.get(), retsize) != retsize) {
return -1;
}
return 0;
}
int ZSTD_compressStream_fd(ZSTD_CCtx* cctx, int fdin, int fdout) {
size_t sizein = ZSTD_CStreamInSize();
size_t sizeout = ZSTD_CStreamOutSize();
auto bufin = std::make_unique<int8_t[]>(sizein);
auto bufout = std::make_unique<int8_t[]>(sizeout);
ssize_t size;
while ((size = read(fdin, bufin.get(), sizein)) > 0) {
ZSTD_inBuffer_s struct_in;
struct_in.src = bufin.get();
struct_in.pos = 0;
struct_in.size = size;
ZSTD_EndDirective mode = ZSTD_e_continue;
if (size < sizein) {
mode = ZSTD_e_end;
}
bool isdone = false;
while (!isdone) {
ZSTD_outBuffer_s struct_out;
struct_out.dst = bufout.get();
struct_out.pos = 0;
struct_out.size = sizeout;
size_t remaining =
ZSTD_compressStream2(cctx, &struct_out, &struct_in, mode);
if (ZSTD_isError(remaining)) {
return -1;
}
if (write(fdout, bufout.get(), struct_out.pos) != struct_out.pos) {
return -1;
}
if (mode == ZSTD_e_continue) {
isdone = (struct_in.pos == size);
} else {
isdone = (remaining == 0);
}
}
}
if (size != 0) {
return -1;
}
return 0;
}
int ZSTD_decompress_fd(int fdin, int fdout) {
off_t sizein = FDGetSize(fdin);
if (sizein <= 0) {
return -1;
}
auto bufin = std::make_unique<int8_t[]>(sizein);
if (read(fdin, bufin.get(), sizein) != sizein) {
return -1;
}
size_t sizeout = ZSTD_getFrameContentSize(bufin.get(), sizein);
if (ZSTD_isError(sizeout) || sizeout > kFileMaxSize) {
return -1;
}
auto bufout = std::make_unique<int8_t[]>(sizeout);
size_t desize = ZSTD_decompress(bufout.get(), sizeout, bufin.get(), sizein);
if (ZSTD_isError(desize) || desize != sizeout) {
return -1;
}
if (write(fdout, bufout.get(), sizeout) != sizeout) {
return -1;
}
return 0;
}
int ZSTD_decompressStream_fd(ZSTD_DCtx* dctx, int fdin, int fdout) {
size_t sizein = ZSTD_CStreamInSize();
size_t sizeout = ZSTD_CStreamOutSize();
auto bufin = std::make_unique<int8_t[]>(sizein);
auto bufout = std::make_unique<int8_t[]>(sizeout);
ssize_t size;
while ((size = read(fdin, bufin.get(), sizein)) > 0) {
ZSTD_inBuffer_s struct_in;
struct_in.src = bufin.get();
struct_in.pos = 0;
struct_in.size = size;
while (struct_in.pos < size) {
ZSTD_outBuffer_s struct_out;
struct_out.dst = bufout.get();
struct_out.pos = 0;
struct_out.size = sizeout;
size_t ret = ZSTD_decompressStream(dctx, &struct_out, &struct_in);
if (ZSTD_isError(ret)) {
return -1;
}
if (write(fdout, bufout.get(), struct_out.pos) != struct_out.pos) {
return -1;
}
}
}
if (size != 0) {
return -1;
}
return 0;
}

View File

@ -0,0 +1,28 @@
// Copyright 2022 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
//
// https://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 CONTRIB_ZSTD_WRAPPER_WRAPPER_ZSTD_H_
#define CONTRIB_ZSTD_WRAPPER_WRAPPER_ZSTD_H_
#include <zstd.h>
extern "C" {
int ZSTD_compress_fd(int fdin, int fdout, int level);
int ZSTD_compressStream_fd(ZSTD_CCtx* cctx, int fdin, int fdout);
int ZSTD_decompress_fd(int fdin, int fdout);
int ZSTD_decompressStream_fd(ZSTD_DCtx* dctx, int fdin, int fdout);
};
#endif // CONTRIB_ZSTD_WRAPPER_WRAPPER_ZSTD_H_

View File

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

View File

@ -36,7 +36,7 @@ sapi_library(
cc_binary( cc_binary(
name = "main_zlib", name = "main_zlib",
srcs = ["main_zlib.cc"], srcs = ["main_zlib.cc"],
copts = sapi_platform_copts(["-Wframe-larger-than=65536"]), copts = sapi_platform_copts(),
deps = [ deps = [
":zlib-sapi", ":zlib-sapi",
":zlib-sapi_embed", ":zlib-sapi_embed",

View File

@ -17,7 +17,7 @@ add_sapi_library(zlib-sapi
FUNCTIONS deflateInit_ FUNCTIONS deflateInit_
deflate deflate
deflateEnd deflateEnd
INPUTS ${ZLIB_INCLUDE_DIRS}/zlib.h INPUTS "${ZLIB_INCLUDE_DIRS}/zlib.h"
LIBRARY ZLIB::ZLIB LIBRARY ZLIB::ZLIB
LIBRARY_NAME Zlib LIBRARY_NAME Zlib
NAMESPACE "sapi::zlib" NAMESPACE "sapi::zlib"

View File

@ -555,9 +555,11 @@ bool Comms::Recv(void* data, size_t len) {
// Internal helper method (low level). // Internal helper method (low level).
bool Comms::RecvTL(uint32_t* tag, size_t* length) { bool Comms::RecvTL(uint32_t* tag, size_t* length) {
if (!Recv(reinterpret_cast<uint8_t*>(tag), sizeof(*tag))) { if (!Recv(reinterpret_cast<uint8_t*>(tag), sizeof(*tag))) {
SAPI_RAW_VLOG(2, "RecvTL: Can't read tag");
return false; return false;
} }
if (!Recv(reinterpret_cast<uint8_t*>(length), sizeof(*length))) { if (!Recv(reinterpret_cast<uint8_t*>(length), sizeof(*length))) {
SAPI_RAW_VLOG(2, "RecvTL: Can't read length for tag %u", *tag);
return false; return false;
} }
if (*length > GetMaxMsgSize()) { if (*length > GetMaxMsgSize()) {

View File

@ -57,4 +57,5 @@ sh_test(
name = "static_sandbox_test", name = "static_sandbox_test",
srcs = ["static_sandbox_test.sh"], srcs = ["static_sandbox_test.sh"],
data = [":static_sandbox"], data = [":static_sandbox"],
tags = ["no_qemu_user_mode"],
) )

View File

@ -37,9 +37,6 @@ cc_binary(
name = "zpipe", name = "zpipe",
srcs = ["zpipe.c"], srcs = ["zpipe.c"],
copts = sapi_platform_copts(), copts = sapi_platform_copts(),
features = [ features = ["fully_static_link"],
"fully_static_link", # link libc statically
],
linkstatic = 1,
deps = ["@net_zlib//:zlib"], deps = ["@net_zlib//:zlib"],
) )

View File

@ -24,7 +24,6 @@ target_link_libraries(sandbox2_zpipe_sandbox PRIVATE
absl::memory absl::memory
sandbox2::bpf_helper sandbox2::bpf_helper
sandbox2::comms sandbox2::comms
# sandbox2::ipc
sapi::runfiles sapi::runfiles
sandbox2::sandbox2 sandbox2::sandbox2
sapi::base sapi::base
@ -38,5 +37,6 @@ add_executable(sandbox2_zpipe
set_target_properties(sandbox2_zpipe PROPERTIES OUTPUT_NAME zpipe) set_target_properties(sandbox2_zpipe PROPERTIES OUTPUT_NAME zpipe)
add_executable(sandbox2::zpipe ALIAS sandbox2_zpipe) add_executable(sandbox2::zpipe ALIAS sandbox2_zpipe)
target_link_libraries(sandbox2_zpipe PRIVATE target_link_libraries(sandbox2_zpipe PRIVATE
-static
ZLIB::ZLIB ZLIB::ZLIB
) )

View File

@ -54,7 +54,7 @@ std::unique_ptr<sandbox2::Policy> GetPolicy() {
// Allow write on STDOUT / STDERR. // Allow write on STDOUT / STDERR.
.AddPolicyOnSyscall(__NR_write, .AddPolicyOnSyscall(__NR_write,
{ARG_32(0), JEQ32(1, ALLOW), JEQ32(2, ALLOW)}) {ARG_32(0), JEQ32(1, ALLOW), JEQ32(2, ALLOW)})
.AllowSyscall(__NR_fstat) .AllowStat()
.AllowStaticStartup() .AllowStaticStartup()
.AllowSystemMalloc() .AllowSystemMalloc()
.AllowExit() .AllowExit()

View File

@ -653,12 +653,10 @@ PolicyBuilder& PolicyBuilder::AllowStaticStartup() {
BlockSyscallWithErrno(__NR_readlink, ENOENT); BlockSyscallWithErrno(__NR_readlink, ENOENT);
#endif #endif
if constexpr (sapi::host_cpu::IsArm()) {
AddPolicyOnSyscall(__NR_mprotect, { AddPolicyOnSyscall(__NR_mprotect, {
ARG_32(2), ARG_32(2),
JEQ32(PROT_READ, ALLOW), JEQ32(PROT_READ, ALLOW),
}); });
}
return *this; return *this;
} }
@ -884,7 +882,7 @@ PolicyBuilder& PolicyBuilder::AddFile(absl::string_view path, bool is_ro) {
PolicyBuilder& PolicyBuilder::AddFileAt(absl::string_view outside, PolicyBuilder& PolicyBuilder::AddFileAt(absl::string_view outside,
absl::string_view inside, bool is_ro) { absl::string_view inside, bool is_ro) {
EnableNamespaces(); EnableNamespaces(); // NOLINT(clang-diagnostic-deprecated-declarations)
auto valid_outside = ValidateAbsolutePath(outside); auto valid_outside = ValidateAbsolutePath(outside);
if (!valid_outside.ok()) { if (!valid_outside.ok()) {
@ -912,7 +910,7 @@ PolicyBuilder& PolicyBuilder::AddFileAt(absl::string_view outside,
PolicyBuilder& PolicyBuilder::AddLibrariesForBinary( PolicyBuilder& PolicyBuilder::AddLibrariesForBinary(
absl::string_view path, absl::string_view ld_library_path) { absl::string_view path, absl::string_view ld_library_path) {
EnableNamespaces(); EnableNamespaces(); // NOLINT(clang-diagnostic-deprecated-declarations)
auto valid_path = ValidatePath(path); auto valid_path = ValidatePath(path);
if (!valid_path.ok()) { if (!valid_path.ok()) {
@ -941,7 +939,7 @@ PolicyBuilder& PolicyBuilder::AddDirectory(absl::string_view path, bool is_ro) {
PolicyBuilder& PolicyBuilder::AddDirectoryAt(absl::string_view outside, PolicyBuilder& PolicyBuilder::AddDirectoryAt(absl::string_view outside,
absl::string_view inside, absl::string_view inside,
bool is_ro) { bool is_ro) {
EnableNamespaces(); EnableNamespaces(); // NOLINT(clang-diagnostic-deprecated-declarations)
auto valid_outside = ValidateAbsolutePath(outside); auto valid_outside = ValidateAbsolutePath(outside);
if (!valid_outside.ok()) { if (!valid_outside.ok()) {
@ -969,7 +967,7 @@ PolicyBuilder& PolicyBuilder::AddDirectoryAt(absl::string_view outside,
} }
PolicyBuilder& PolicyBuilder::AddTmpfs(absl::string_view inside, size_t size) { PolicyBuilder& PolicyBuilder::AddTmpfs(absl::string_view inside, size_t size) {
EnableNamespaces(); EnableNamespaces(); // NOLINT(clang-diagnostic-deprecated-declarations)
if (auto status = mounts_.AddTmpfs(inside, size); !status.ok()) { if (auto status = mounts_.AddTmpfs(inside, size); !status.ok()) {
SetError(absl::InternalError(absl::StrCat("Could not mount tmpfs ", inside, SetError(absl::InternalError(absl::StrCat("Could not mount tmpfs ", inside,
@ -979,14 +977,14 @@ PolicyBuilder& PolicyBuilder::AddTmpfs(absl::string_view inside, size_t size) {
} }
PolicyBuilder& PolicyBuilder::AllowUnrestrictedNetworking() { PolicyBuilder& PolicyBuilder::AllowUnrestrictedNetworking() {
EnableNamespaces(); EnableNamespaces(); // NOLINT(clang-diagnostic-deprecated-declarations)
allow_unrestricted_networking_ = true; allow_unrestricted_networking_ = true;
return *this; return *this;
} }
PolicyBuilder& PolicyBuilder::SetHostname(absl::string_view hostname) { PolicyBuilder& PolicyBuilder::SetHostname(absl::string_view hostname) {
EnableNamespaces(); EnableNamespaces(); // NOLINT(clang-diagnostic-deprecated-declarations)
hostname_ = std::string(hostname); hostname_ = std::string(hostname);
return *this; return *this;
@ -1089,7 +1087,7 @@ PolicyBuilder& PolicyBuilder::AddNetworkProxyHandlerPolicy() {
} }
PolicyBuilder& PolicyBuilder::SetRootWritable() { PolicyBuilder& PolicyBuilder::SetRootWritable() {
EnableNamespaces(); EnableNamespaces(); // NOLINT(clang-diagnostic-deprecated-declarations)
mounts_.SetRootWritable(); mounts_.SetRootWritable();
return *this; return *this;

View File

@ -286,9 +286,6 @@ absl::StatusOr<UnwindResult> StackTracePeer::LaunchLibunwindSandbox(
absl::StatusOr<std::vector<std::string>> GetStackTrace(const Regs* regs, absl::StatusOr<std::vector<std::string>> GetStackTrace(const Regs* regs,
const Mounts& mounts) { const Mounts& mounts) {
if constexpr (sapi::host_cpu::IsArm64()) {
return absl::UnavailableError("Stack traces unavailable on Aarch64");
}
if (absl::GetFlag(FLAGS_sandbox_disable_all_stack_traces)) { if (absl::GetFlag(FLAGS_sandbox_disable_all_stack_traces)) {
return absl::UnavailableError("Stacktraces disabled"); return absl::UnavailableError("Stacktraces disabled");
} }

View File

@ -62,6 +62,7 @@ cc_library(
"//sandboxed_api/util:raw_logging", "//sandboxed_api/util:raw_logging",
"//sandboxed_api/util:status", "//sandboxed_api/util:status",
"//sandboxed_api/util:strerror", "//sandboxed_api/util:strerror",
"@com_google_absl//absl/cleanup",
"@com_google_absl//absl/status:statusor", "@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings", "@com_google_absl//absl/strings",
"@org_gnu_libunwind//:unwind-ptrace-wrapped", "@org_gnu_libunwind//:unwind-ptrace-wrapped",

View File

@ -30,6 +30,7 @@ add_library(sandbox2_unwind STATIC
) )
add_library(sandbox2::unwind ALIAS sandbox2_unwind) add_library(sandbox2::unwind ALIAS sandbox2_unwind)
target_link_libraries(sandbox2_unwind PRIVATE target_link_libraries(sandbox2_unwind PRIVATE
absl::cleanup
absl::statusor absl::statusor
absl::strings absl::strings
sandbox2::comms sandbox2::comms

View File

@ -19,11 +19,13 @@
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <cstdio> #include <cstdio>
#include <cstdlib>
#include <map> #include <map>
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
#include "absl/cleanup/cleanup.h"
#include "absl/status/statusor.h" #include "absl/status/statusor.h"
#include "absl/strings/match.h" #include "absl/strings/match.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
@ -55,21 +57,20 @@ std::string DemangleSymbol(const std::string& maybe_mangled) {
} }
absl::StatusOr<std::vector<uintptr_t>> RunLibUnwind(pid_t pid, int max_frames) { absl::StatusOr<std::vector<uintptr_t>> RunLibUnwind(pid_t pid, int max_frames) {
unw_cursor_t cursor;
static unw_addr_space_t as = static unw_addr_space_t as =
unw_create_addr_space(&_UPT_accessors, 0 /* byte order */); unw_create_addr_space(&_UPT_accessors, 0 /* byte order */);
if (as == nullptr) { if (as == nullptr) {
return absl::InternalError("unw_create_addr_space() failed"); return absl::InternalError("unw_create_addr_space() failed");
} }
std::unique_ptr<struct UPT_info, void (*)(void*)> ui( void* context = _UPT_create(pid);
reinterpret_cast<struct UPT_info*>(_UPT_create(pid)), _UPT_destroy); if (context == nullptr) {
if (ui == nullptr) {
return absl::InternalError("_UPT_create() failed"); return absl::InternalError("_UPT_create() failed");
} }
absl::Cleanup context_cleanup = [&context] { _UPT_destroy(context); };
int rc = unw_init_remote(&cursor, as, ui.get()); unw_cursor_t cursor;
if (rc < 0) { if (int rc = unw_init_remote(&cursor, as, context); rc < 0) {
// Could be UNW_EINVAL (8), UNW_EUNSPEC (1) or UNW_EBADREG (3). // Could be UNW_EINVAL (8), UNW_EUNSPEC (1) or UNW_EBADREG (3).
return absl::InternalError( return absl::InternalError(
absl::StrCat("unw_init_remote() failed with error ", rc)); absl::StrCat("unw_init_remote() failed with error ", rc));
@ -78,7 +79,7 @@ absl::StatusOr<std::vector<uintptr_t>> RunLibUnwind(pid_t pid, int max_frames) {
std::vector<uintptr_t> ips; std::vector<uintptr_t> ips;
for (int i = 0; i < max_frames; ++i) { for (int i = 0; i < max_frames; ++i) {
unw_word_t ip; unw_word_t ip;
rc = unw_get_reg(&cursor, UNW_REG_IP, &ip); int rc = unw_get_reg(&cursor, UNW_REG_IP, &ip);
if (rc < 0) { if (rc < 0) {
// Could be UNW_EUNSPEC or UNW_EBADREG. // Could be UNW_EUNSPEC or UNW_EBADREG.
SAPI_RAW_LOG(WARNING, "unw_get_reg() failed with error %d", rc); SAPI_RAW_LOG(WARNING, "unw_get_reg() failed with error %d", rc);
@ -176,8 +177,10 @@ absl::StatusOr<SymbolMap> LoadSymbolsMap(pid_t pid) {
for (const ElfFile::Symbol& symbol : elf->symbols()) { for (const ElfFile::Symbol& symbol : elf->symbols()) {
if (elf->position_independent()) { if (elf->position_independent()) {
if (symbol.address < entry.end - entry.start) { if (symbol.address >= entry.pgoff &&
addr_to_symbol[symbol.address + entry.start] = symbol.name; symbol.address - entry.pgoff < entry.end - entry.start) {
addr_to_symbol[symbol.address + entry.start - entry.pgoff] =
symbol.name;
} }
} else { } else {
if (symbol.address >= entry.start && symbol.address < entry.end) { if (symbol.address >= entry.start && symbol.address < entry.end) {

View File

@ -26,13 +26,14 @@
#include "sandboxed_api/util/file_helpers.h" #include "sandboxed_api/util/file_helpers.h"
#include "sandboxed_api/util/status_matchers.h" #include "sandboxed_api/util/status_matchers.h"
extern "C" void ExportedFunctionName() { extern "C" void ExportedFunction() {
// Don't do anything - used to generate a symbol. // Don't do anything - used to generate a symbol.
} }
namespace file = ::sapi::file; namespace file = ::sapi::file;
using ::sapi::GetTestSourcePath; using ::sapi::GetTestSourcePath;
using ::sapi::IsOk; using ::sapi::IsOk;
using ::testing::ElementsAre;
using ::testing::Eq; using ::testing::Eq;
using ::testing::IsTrue; using ::testing::IsTrue;
using ::testing::Ne; using ::testing::Ne;
@ -65,19 +66,20 @@ TEST(MinielfTest, SymbolResolutionWorks) {
ParseProcMaps(maps_buffer)); ParseProcMaps(maps_buffer));
// Find maps entry that covers this entry. // Find maps entry that covers this entry.
uint64_t function_address = reinterpret_cast<uint64_t>(ExportedFunctionName); uint64_t function_address = reinterpret_cast<uint64_t>(&ExportedFunction);
auto function_entry = auto entry =
absl::c_find_if(maps, [function_address](const MapsEntry& entry) { absl::c_find_if(maps, [function_address](const MapsEntry& entry) {
return entry.start <= function_address && entry.end > function_address; return entry.start <= function_address && entry.end > function_address;
}); });
ASSERT_THAT(function_entry, Ne(maps.end())); ASSERT_THAT(entry, Ne(maps.end()));
function_address -= function_entry->start;
auto function_symbol = auto function_symbol =
absl::c_find_if(elf.symbols(), [](const ElfFile::Symbol& symbol) { absl::c_find_if(elf.symbols(), [](const ElfFile::Symbol& symbol) {
return symbol.name == "ExportedFunctionName"; return symbol.name == "ExportedFunction";
}); });
ASSERT_THAT(function_symbol, Ne(elf.symbols().end())); ASSERT_THAT(function_symbol, Ne(elf.symbols().end()));
function_address -= entry->start - entry->pgoff;
EXPECT_THAT(function_symbol->address, Eq(function_address)); EXPECT_THAT(function_symbol->address, Eq(function_address));
} }
@ -86,8 +88,7 @@ TEST(MinielfTest, ImportedLibraries) {
ElfFile elf, ElfFile::ParseFromFile( ElfFile elf, ElfFile::ParseFromFile(
GetTestSourcePath("sandbox2/util/testdata/hello_world"), GetTestSourcePath("sandbox2/util/testdata/hello_world"),
ElfFile::kLoadImportedLibraries)); ElfFile::kLoadImportedLibraries));
std::vector<std::string> imported_libraries = {"libc.so.6"}; EXPECT_THAT(elf.imported_libraries(), ElementsAre("libc.so.6"));
EXPECT_THAT(elf.imported_libraries(), Eq(imported_libraries));
} }
} // namespace } // namespace

View File

@ -31,8 +31,11 @@ void SaveStatusToProto(const absl::Status& status, StatusProto* out) {
absl::Status MakeStatusFromProto(const StatusProto& proto) { absl::Status MakeStatusFromProto(const StatusProto& proto) {
absl::Status status(static_cast<absl::StatusCode>(proto.code()), absl::Status status(static_cast<absl::StatusCode>(proto.code()),
proto.message()); proto.message());
for (const auto& [type_key, payload] : proto.payloads()) { // Note: Using C++17 structured bindings instead of `entry` crashes Clang 6.0
status.SetPayload(type_key, absl::Cord(payload)); // on Ubuntu 18.04 (bionic).
for (const auto& entry : proto.payloads()) {
status.SetPayload(/*type_url=*/entry.first,
/*payload=*/absl::Cord(entry.second));
} }
return status; return status;
} }