Move libtiff sandbox to `contrib/`, add to tests

PiperOrigin-RevId: 453410018
Change-Id: I7a9815d844e43fe4b6a1971104179c5b854b2f0a
pull/171/head
Christian Blichmann 2022-06-07 05:04:30 -07:00 committed by Copybara-Service
parent 9ac0400186
commit d805286343
22 changed files with 136 additions and 157 deletions

View File

@ -11,7 +11,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-20.04]
contrib: [jsonnet, pffft]
contrib: [jsonnet, libtiff, pffft]
ignore-errors: [true]
include:
- compiler: clang

View File

@ -18,6 +18,7 @@ set(SAPI_CONTRIB_SANDBOXES
hunspell
jsonnet
libidn2
libtiff
libxls
libzip
pffft

View File

@ -12,36 +12,30 @@
# See the License for the specific language governing permissions and
# limitations under the License.
cmake_minimum_required(VERSION 3.10)
cmake_minimum_required(VERSION 3.13..3.22)
project(sandboxed_libtiff CXX)
include(CTest)
include(GoogleTest)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# Set this on the command-line
set(SAPI_ROOT "" CACHE PATH "Path to the Sandboxed API source tree")
# To obtain a full SAPI_ROOT check out its source separately:
# git clone https://github.com/google/sandboxed-api.git $HOME/sapi_root
# Then configure:
# mkdir -p build && cd build
# cmake .. -G Ninja -DSAPI_ROOT=$HOME/sapi_root
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()
option(TIFF_SAPI_BUILD_EXAMPLES "" ON)
option(TIFF_SAPI_BUILD_TESTING "" ON)
set(SAPI_BUILD_EXAMPLES ${TIFF_SAPI_BUILD_EXAMPLES} CACHE BOOL "" FORCE)
set(SAPI_BUILD_TESTING ${TIFF_SAPI_BUILD_TESTING} CACHE BOOL "" FORCE)
FetchContent_Declare(libtiff
GIT_REPOSITORY https://gitlab.com/libtiff/libtiff
GIT_TAG v4.4.0 # 2022-05-20
)
FetchContent_MakeAvailable(libtiff)
add_subdirectory(wrapper)
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(tiff_sapi
# List of functions that we want to include in the
# generated sandboxed API class
@ -84,6 +78,7 @@ add_sapi_library(tiff_sapi
TIFFSetFieldDouble3
TIFFReadRGBATile
TIFFReadRGBATileExt
TIFFReadEncodedTile
TIFFReadEncodedStrip
TIFFReadFromUserBuffer
@ -108,7 +103,7 @@ add_sapi_library(tiff_sapi
TIFFCreateEXIFDirectory
TIFFWriteCustomDirectory
INPUTS wrapper/libtiff/libtiff/tiffio.h
INPUTS "${libtiff_SOURCE_DIR}/libtiff/tiffio.h"
wrapper/func.h
# Header files or .cc files that should be parsed
LIBRARY wrapped_tiff # Library dependency from the add_library() above
@ -116,15 +111,15 @@ add_sapi_library(tiff_sapi
# suffixed with "Api" and "Sandbox" as needed.
NAMESPACE "" # Optional C++ namespace to wrap the generated code
)
add_library(sapi_contrib::libtiff ALIAS tiff_sapi)
target_include_directories(tiff_sapi INTERFACE
"${PROJECT_BINARY_DIR}" # To find the generated SAPI header
)
if (TIFF_SAPI_BUILD_EXAMPLES)
if (SAPI_BUILD_EXAMPLES)
add_subdirectory(example)
endif()
if (TIFF_SAPI_BUILD_TESTING)
if (BUILD_TESTING AND SAPI_BUILD_TESTING)
add_subdirectory(test)
endif()

28
contrib/libtiff/README.md Normal file
View File

@ -0,0 +1,28 @@
# sapi-libtiff
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)).
Copyright 2020 Google LLC.
## Usage
#### build:
```bash
mkdir -p build && cd build && cmake .. \
-DSAPI_ROOT=$HOME/sapi_root \
-DBUILD_SHARED_LIBS=OFF
make -j 8
```
#### to run the sandboxed example:
`./example/sandboxed absolute/path/to/project/dir`
#### to run tests:
`./test/tests`
you also can use sandbox flags `sandbox2_danger_danger_permit_all` and
`sandbox2_danger_danger_permit_all_and_log` for debugging.

View File

@ -21,6 +21,7 @@
#include "../sandboxed.h" // NOLINT(build/include)
#include "sandboxed_api/util/fileops.h"
#include "sandboxed_api/util/path.h"
#include "sandboxed_api/util/vars.h"
#include "tiffio.h" // NOLINT(build/include)
// sapi functions:
@ -38,8 +39,9 @@ constexpr std::array<uint8_t, 6> kCluster0 = {0, 0, 2, 0, 138, 139};
constexpr std::array<uint8_t, 6> kCluster64 = {0, 0, 9, 6, 134, 119};
constexpr std::array<uint8_t, 6> kCluster128 = {44, 40, 63, 59, 230, 95};
template <typename ArrayT>
int CheckCluster(int cluster, const sapi::v::Array<uint8_t>& buffer,
const std::vector<uint8_t>& expected_cluster) {
const ArrayT& expected_cluster) {
uint8_t* target = buffer.GetData() + cluster * 6;
if (!std::memcmp(target, expected_cluster.data(), 6)) {

View File

@ -12,20 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef LIBTIFF_SANDBOXED_H_
#define LIBTIFF_SANDBOXED_H_
#ifndef CONTRIB_LIBTIFF_SANDBOXED_H_
#define CONTRIB_LIBTIFF_SANDBOXED_H_
#include <linux/futex.h>
#include <syscall.h>
#include <string>
#include <memory>
#include <utility>
#include "sandboxed_api/util/flag.h"
#include "absl/flags/flag.h"
#include "tiff_sapi.sapi.h" // NOLINT(build/include)
ABSL_DECLARE_FLAG(string, sandbox2_danger_danger_permit_all);
ABSL_DECLARE_FLAG(string, sandbox2_danger_danger_permit_all_and_log);
class TiffSapiSandbox : public TiffSandbox {
public:
explicit TiffSapiSandbox(std::string dir = "", std::string file = "")
@ -67,4 +66,4 @@ class TiffSapiSandbox : public TiffSandbox {
std::string file_;
};
#endif // LIBTIFF_SANDBOXED_H_
#endif // CONTRIB_LIBTIFF_SANDBOXED_H_

View File

@ -12,8 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
include(GoogleTest)
add_executable(tests
check_tag.h
check_tag.cc
@ -24,14 +22,15 @@ add_executable(tests
helper.h
helper.cc
)
target_link_libraries(tests PRIVATE
tiff_sapi
sapi::sapi
sapi::temp_file
gtest
gmock
gtest_main
target_link_libraries(tests
PRIVATE sapi::base
sapi::sapi
sapi::temp_file
sapi_contrib::libtiff
gmock
gtest_main
)
gtest_discover_tests(tests)
gtest_discover_tests(tests PROPERTIES
ENVIRONMENT "TEST_SRCDIR=${PROJECT_SOURCE_DIR}"
)

View File

@ -22,8 +22,6 @@ using ::testing::IsTrue;
// sapi functions:
// TIFFGetField
namespace {
void CheckShortField(TiffApi& api, sapi::v::RemotePtr& tif, const ttag_t field,
const uint16_t value) {
sapi::v::UShort tmp(123);
@ -67,5 +65,3 @@ void CheckLongField(TiffApi& api, sapi::v::RemotePtr& tif, const ttag_t field,
EXPECT_THAT(tmp.GetValue(), Eq(value))
<< "Wrong LONG value fetched for tag " << field;
}
} // namespace

View File

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef LIBTIFF_TEST_CHECK_TAG_H_
#define LIBTIFF_TEST_CHECK_TAG_H_
#ifndef CONTRIB_LIBTIFF_TEST_CHECK_TAG_H_
#define CONTRIB_LIBTIFF_TEST_CHECK_TAG_H_
#include <cstdint>
@ -28,4 +28,4 @@ void CheckShortPairedField(TiffApi& api, sapi::v::RemotePtr& tif,
void CheckLongField(TiffApi&, sapi::v::RemotePtr& tif, const ttag_t field,
const uint32_t value);
#endif // LIBTIFF_TEST_CHECK_TAG_H_
#endif // CONTRIB_LIBTIFF_TEST_CHECK_TAG_H_

View File

@ -50,11 +50,11 @@ constexpr int kSamplePerPixel = 1;
void TestWriting(const char* mode, int tiled, int height) {
absl::StatusOr<std::string> status_or_path =
sandbox2::CreateNamedTempFileAndClose("defer_strile_writing.tif");
sapi::CreateNamedTempFileAndClose("defer_strile_writing.tif");
ASSERT_THAT(status_or_path, IsOk()) << "Could not create temp file";
std::string srcfile = sandbox2::file::JoinPath(
sandbox2::file_util::fileops::GetCWD(), status_or_path.value());
std::string srcfile = sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(),
status_or_path.value());
absl::StatusOr<int> status_or_int;
absl::StatusOr<int64_t> status_or_long;

View File

@ -16,30 +16,10 @@
#include <iostream>
auto* g_in_dir = new std::string();
std::string GetCWD() {
char cwd[PATH_MAX];
getcwd(cwd, sizeof(cwd));
return cwd;
}
std::string GetImagesDir() {
std::string cwd = GetCWD();
auto find = cwd.rfind("/build");
if (find == std::string::npos) {
std::cerr << "Something went wrong: CWD don't contain build dir. "
<< "Please run tests from build dir, path might be incorrect\n";
return cwd + "/test/images";
}
return cwd.substr(0, find) + "/test/images";
}
std::string GetFilePath(const std::string& filename) {
if (g_in_dir->empty()) {
*g_in_dir = GetImagesDir();
}
return sandbox2::file::JoinPath(*g_in_dir, filename);
const char* test_srcdir = std::getenv("TEST_SRCDIR");
return sapi::file::JoinPath(
test_srcdir == nullptr ? sapi::file_util::fileops::GetCWD() : test_srcdir,
filename);
}

View File

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef LIBTIFF_TEST_HELPER_H_
#define LIBTIFF_TEST_HELPER_H_
#ifndef CONTRIB_LIBTIFF_TEST_HELPER_H_
#define CONTRIB_LIBTIFF_TEST_HELPER_H_
#include <string>
@ -26,4 +26,4 @@
std::string GetFilePath(const std::string& filename);
#endif // LIBTIFF_TEST_HELPER_H_
#endif // CONTRIB_LIBTIFF_TEST_HELPER_H_

View File

@ -49,17 +49,17 @@ constexpr int kRowsPerStrip = 1;
TEST(SandboxTest, LongTag) {
absl::StatusOr<std::string> status_or_path =
sandbox2::CreateNamedTempFileAndClose("long_test.tif");
sapi::CreateNamedTempFileAndClose("long_test.tif");
ASSERT_THAT(status_or_path, IsOk()) << "Could not create temp file";
std::string srcfile = sandbox2::file::JoinPath(
sandbox2::file_util::fileops::GetCWD(), status_or_path.value());
std::string srcfile = sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(),
status_or_path.value());
TiffSapiSandbox sandbox("", srcfile);
ASSERT_THAT(sandbox.Init(), IsOk()) << "Couldn't initialize Sandboxed API";
std::array<uint8_t, SPP> buffer = {0, 127, 255};
sapi::v::Array<uint8_t> buffer_(buffer.data(), SPP);
std::array<uint8_t, kSamplesPerPixel> buffer = {0, 127, 255};
sapi::v::Array<uint8_t> buffer_(buffer.data(), kSamplesPerPixel);
absl::StatusOr<int> status_or_int;
absl::StatusOr<TIFF*> status_or_tif;
@ -87,7 +87,8 @@ TEST(SandboxTest, LongTag) {
ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error";
EXPECT_THAT(status_or_int.value(), IsTrue()) << "Can't set BitsPerSample tag";
status_or_int = api.TIFFSetFieldU1(&tif, TIFFTAG_SAMPLESPERPIXEL, SPP);
status_or_int =
api.TIFFSetFieldU1(&tif, TIFFTAG_SAMPLESPERPIXEL, kSamplesPerPixel);
ASSERT_THAT(status_or_int, IsOk()) << "TIFFSetFieldU1 fatal error";
EXPECT_THAT(status_or_int.value(), IsTrue())
<< "Can't set SamplesPerPixel tag";

View File

@ -41,9 +41,10 @@ constexpr std::array<uint8_t, 6> kCluster0 = {0, 0, 2, 0, 138, 139};
constexpr std::array<uint8_t, 6> kCluster64 = {0, 0, 9, 6, 134, 119};
constexpr std::array<uint8_t, 6> kCluster128 = {44, 40, 63, 59, 230, 95};
int CheckCluster(int cluster, const sapi::v::Array<uint8_t> &buffer,
const std::vector<uint8_t> &expected_cluster) {
uint8_t *target = buffer.GetData() + cluster * 6;
template <typename ArrayT>
int CheckCluster(int cluster, const sapi::v::Array<uint8_t>& buffer,
const ArrayT& expected_cluster) {
uint8_t* target = buffer.GetData() + cluster * 6;
bool comp = !(std::memcmp(target, expected_cluster.data(), 6) == 0);
@ -60,8 +61,8 @@ int CheckCluster(int cluster, const sapi::v::Array<uint8_t> &buffer,
int CheckRgbPixel(int pixel, int min_red, int max_red, int min_green,
int max_green, int min_blue, int max_blue,
const sapi::v::Array<uint8_t> &buffer) {
uint8_t *rgb = buffer.GetData() + 3 * pixel;
const sapi::v::Array<uint8_t>& buffer) {
uint8_t* rgb = buffer.GetData() + 3 * pixel;
bool comp =
!(rgb[0] >= min_red && rgb[0] <= max_red && rgb[1] >= min_green &&
@ -78,7 +79,7 @@ int CheckRgbPixel(int pixel, int min_red, int max_red, int min_green,
int CheckRgbaPixel(int pixel, int min_red, int max_red, int min_green,
int max_green, int min_blue, int max_blue, int min_alpha,
int max_alpha, const sapi::v::Array<uint32_t> &buffer) {
int max_alpha, const sapi::v::Array<uint32_t>& buffer) {
// RGBA images are upside down - adjust for normal ordering
int adjusted_pixel = pixel % 128 + (127 - (pixel / 128)) * 128;
unsigned rgba = buffer[adjusted_pixel];
@ -103,38 +104,37 @@ int CheckRgbaPixel(int pixel, int min_red, int max_red, int min_green,
}
TEST(SandboxTest, RawDecode) {
std::string srcfile = GetFilePath("quad-tile.jpg.tiff");
std::string srcfile = GetFilePath("test/images/quad-tile.jpg.tiff");
TiffSapiSandbox sandbox("", srcfile);
ASSERT_THAT(sandbox.Init(), IsOk()) << "Couldn't initialize Sandboxed API";
tsize_t sz;
unsigned int pixel_status = 0;
sapi::v::UShort h, v;
absl::StatusOr<TIFF> status_or_tif;
absl::StatusOr<int> status_or_int;
absl::StatusOr<tmsize_t> status_or_long;
sapi::v::UShort h;
sapi::v::UShort v;
TiffApi api(&sandbox);
sapi::v::ConstCStr srcfile_var(srcfile.c_str());
sapi::v::ConstCStr r_var("r");
status_or_tif = api.TIFFOpen(srcfile_var.PtrBefore(), r_var.PtrBefore());
absl::StatusOr<TIFF*> status_or_tif =
api.TIFFOpen(srcfile_var.PtrBefore(), r_var.PtrBefore());
ASSERT_THAT(status_or_tif, IsOk()) << "Could not open " << srcfile;
sapi::v::RemotePtr tif(status_or_tif.value());
ASSERT_THAT(tif.GetValue(), NotNull())
<< "Could not open " << srcfile << ", TIFFOpen return NULL";
status_or_int = api.TIFFGetField2(&tif, TIFFTAG_YCBCRSUBSAMPLING, h.PtrBoth(),
v.PtrBoth());
absl::StatusOr<int> status_or_int = api.TIFFGetField2(
&tif, TIFFTAG_YCBCRSUBSAMPLING, h.PtrBoth(), v.PtrBoth());
ASSERT_THAT(status_or_int, IsOk()) << "TIFFGetField2 fatal error";
EXPECT_THAT(
status_or_int.value() == 0 || h.GetValue() != 2 || v.GetValue() != 2,
IsFalse())
<< "Could not retrieve subsampling tag";
status_or_long = api.TIFFTileSize(&tif);
absl::StatusOr<tmsize_t> status_or_long = api.TIFFTileSize(&tif);
ASSERT_THAT(status_or_int, IsOk()) << "TIFFTileSize fatal error";
EXPECT_THAT(status_or_long.value(), Eq(24576))
<< "tiles are " << status_or_long.value() << " bytes";

View File

@ -23,6 +23,7 @@ using ::sapi::IsOk;
using ::testing::Eq;
using ::testing::IsFalse;
using ::testing::IsTrue;
using ::testing::Ne;
using ::testing::NotNull;
// sapi functions:
@ -47,35 +48,35 @@ struct SingleTag {
const uint16_t value;
};
constexpr std::array<SingleTag, 9> kShortSingleTags = {
SingleTag{TIFFTAG_COMPRESSION, COMPRESSION_NONE},
SingleTag{TIFFTAG_FILLORDER, FILLORDER_MSB2LSB},
SingleTag{TIFFTAG_ORIENTATION, ORIENTATION_BOTRIGHT},
SingleTag{TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH},
SingleTag{TIFFTAG_MINSAMPLEVALUE, 23},
SingleTag{TIFFTAG_MAXSAMPLEVALUE, 241},
SingleTag{TIFFTAG_INKSET, INKSET_MULTIINK},
SingleTag{TIFFTAG_NUMBEROFINKS, kSamplePerPixel},
SingleTag{TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT}};
struct PairedTag {
const ttag_t tag;
const std::array<uint16_t, 2> values;
};
constexpr std::array<SingleTag, 9> kShortSingleTags = {
{TIFFTAG_COMPRESSION, COMPRESSION_NONE},
{TIFFTAG_FILLORDER, FILLORDER_MSB2LSB},
{TIFFTAG_ORIENTATION, ORIENTATION_BOTRIGHT},
{TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH},
{TIFFTAG_MINSAMPLEVALUE, 23},
{TIFFTAG_MAXSAMPLEVALUE, 241},
{TIFFTAG_INKSET, INKSET_MULTIINK},
{TIFFTAG_NUMBEROFINKS, kSamplePerPixel},
{TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT}};
constexpr std::array<PairedTag, 4> kShortPairedTags = {
{TIFFTAG_PAGENUMBER, {1, 1}},
{TIFFTAG_HALFTONEHINTS, {0, 255}},
{TIFFTAG_DOTRANGE, {8, 16}},
{TIFFTAG_YCBCRSUBSAMPLING, {2, 1}}};
PairedTag{TIFFTAG_PAGENUMBER, {1, 1}},
PairedTag{TIFFTAG_HALFTONEHINTS, {0, 255}},
PairedTag{TIFFTAG_DOTRANGE, {8, 16}},
PairedTag{TIFFTAG_YCBCRSUBSAMPLING, {2, 1}}};
TEST(SandboxTest, ShortTag) {
absl::StatusOr<std::string> status_or_path =
sandbox2::CreateNamedTempFileAndClose("short_test.tif");
sapi::CreateNamedTempFileAndClose("short_test.tif");
ASSERT_THAT(status_or_path, IsOk()) << "Could not create temp file";
std::string srcfile = sandbox2::file::JoinPath(
sandbox2::file_util::fileops::GetCWD(), status_or_path.value());
std::string srcfile =
sapi::file::JoinPath(sapi::file_util::fileops::GetCWD(), *status_or_path);
TiffSapiSandbox sandbox("", srcfile);
ASSERT_THAT(sandbox.Init(), IsOk()) << "Couldn't initialize Sandboxed API";

View File

@ -12,17 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
add_library(wrapped_tiff OBJECT
add_library(wrapped_tiff STATIC
func.h
func.cc
)
set_target_properties(wrapped_tiff
PROPERTIES LINKER_LANGUAGE C
)
add_subdirectory(libtiff)
target_link_libraries(wrapped_tiff
target_link_libraries(wrapped_tiff PRIVATE
sapi::temp_file
sapi::sapi
tiff

View File

@ -12,7 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "func.h" // NOLINT(build/include)
#include "contrib/libtiff/wrapper/func.h"
#include <cstdint>
// Work around the linker not including this symbol in the final sandboxee
// binary.
static volatile auto unused_reference_function =
reinterpret_cast<uintptr_t>(&TIFFReadRGBATile);
int TIFFGetField1(TIFF* tif, uint32_t tag, void* param) {
return TIFFGetField(tif, tag, param);

View File

@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef LIBTIFF_WRAPPER_FUNC_H_
#define LIBTIFF_WRAPPER_FUNC_H_
#ifndef CONTRIB_LIBTIFF_WRAPPER_FUNC_H_
#define CONTRIB_LIBTIFF_WRAPPER_FUNC_H_
#include <cstdint>
@ -85,4 +85,4 @@ int TIFFSetFieldDouble3(TIFF* tif, uint32_t tag, double param1, double param2,
} // extern "C"
#endif // LIBTIFF_WRAPPER_FUNC_H_
#endif // CONTRIB_LIBTIFF_WRAPPER_FUNC_H_

View File

@ -1,2 +0,0 @@
build/
.vscode/

View File

@ -1,22 +0,0 @@
# sapi-libtiff
Copyright 2020 Google LLC.
## Start use
You should make sure the libtiff submodule is cloned.
`git clone --recursive https://github.com/alexelex/sapi-libtiff`
## Usage
#### build:
`mkdir -p build && cd build && cmake .. -DSAPI_ROOT=$HOME/sapi_root -DBUILD_SHARED_LIBS=OFF`
`make -j 8`
#### to run the sandboxed example:
`./example/sandboxed absolute/path/to/project/dir`
#### to run tests:
`./test/tests`
you also can use sandbox flags `sandbox2_danger_danger_permit_all` and `sandbox2_danger_danger_permit_all_and_log`