Sandbox zip

This commit is contained in:
Mariusz Zaborski 2022-02-09 07:56:47 -05:00
parent 4024694eb6
commit e49318571b
17 changed files with 1584 additions and 0 deletions

View File

@ -18,6 +18,7 @@ set(SAPI_CONTRIB_SANDBOXES
hunspell
jsonnet
libidn2
libzip
pffft
turbojpeg
zopfli

View File

@ -10,6 +10,7 @@ Directory | Project
`c-blosc/` | c-blosc - A blocking, shuffling and loss-less compression library | [github.com/Blosc/c-blosc](https://github.com/Blosc/c-blosc) | 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
`libzip/` | libzip - operations on zip archives | [github.com/nih-at/libzip](https://github.com/nih-at/libzip) | 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

View File

@ -0,0 +1,95 @@
# 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)
project(sapi_zip 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()
set(BUILD_SHARED_LIBS off)
FetchContent_Declare(libzip
GIT_REPOSITORY https://github.com/nih-at/libzip/
GIT_TAG 34b13ca4e887a5aba050015e3a179069643f4e76
)
FetchContent_MakeAvailable(libzip)
include_directories("${libzip_BINARY_DIR}")
add_subdirectory(wrapper)
add_sapi_library(
sapi_zip
FUNCTIONS
zip_open_from_source
zip_close
zip_get_name
zip_get_num_entries
zip_stat
zip_stat_index
zip_fopen
zip_fopen_index
zip_fclose
zip_fread
zip_fseek
zip_ftell
zip_source_buffer
zip_read_fd_to_source
zip_source_to_fd
zip_source_filefd
zip_source_filefd_create
zip_source_keep
zip_source_free
zip_file_add
zip_file_replace
zip_delete
zip_strerror
INPUTS
"${libzip_BINARY_DIR}/zipconf.h"
"${libzip_SOURCE_DIR}/lib/zip.h"
"wrapper/wrapper_zip.h"
LIBRARY wrapper_zip
LIBRARY_NAME Zip
NAMESPACE ""
)
add_library(sapi_contrib::libzip ALIAS sapi_zip)
target_include_directories(sapi_zip 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,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.
add_executable(
sapi_minizip
main.cc
../utils/utils_zip.cc
)
target_link_libraries(
sapi_minizip PRIVATE
sapi_zip
sapi::sapi
absl::flags_parse
)

View File

@ -0,0 +1,158 @@
// 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 <fcntl.h>
#include <unistd.h>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include "absl/flags/flag.h"
#include "absl/flags/parse.h"
#include "contrib/libzip/sandboxed.h"
#include "contrib/libzip/utils/utils_zip.h"
ABSL_FLAG(bool, list, false, "list files");
ABSL_FLAG(std::string, unzip, "", "unzip");
ABSL_FLAG(std::string, add_file, "", "add file");
ABSL_FLAG(std::string, delete, "", "delete");
absl::Status ListFiles(LibZip& zip) {
SAPI_ASSIGN_OR_RETURN(int64_t num, zip.GetNumberEntries());
for (uint64_t i = 0; i < num; i++) {
SAPI_ASSIGN_OR_RETURN(std::string name, zip.GetName(i));
std::cout << name << "\n";
}
return absl::OkStatus();
}
absl::Status UnzipToStdout(LibZip& zip, const std::string& filename) {
SAPI_ASSIGN_OR_RETURN(std::vector<uint8_t> buf, zip.ReadFile(filename));
std::cout << buf.data();
return absl::OkStatus();
}
absl::Status AddFile(LibZip& zip, const std::string& filename) {
int fd = open(filename.c_str(), O_RDONLY);
if (fd < 0) {
return absl::UnavailableError(
absl::StrCat("Unable to open file ", filename));
}
// The fd will be consumed
SAPI_ASSIGN_OR_RETURN(uint64_t index, zip.AddFile(filename, fd));
return absl::OkStatus();
}
absl::Status DeleteFile(LibZip& zip, const std::string& filename) {
int64_t index = -1;
SAPI_ASSIGN_OR_RETURN(int64_t num, zip.GetNumberEntries());
for (uint64_t i = 0; i < num; i++) {
SAPI_ASSIGN_OR_RETURN(std::string name, zip.GetName(i));
if (name == filename) {
index = i;
break;
}
}
if (index == -1) {
return absl::UnavailableError(
absl::StrCat("Unable to remove file ", filename));
}
return zip.DeleteFile(index);
}
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() < 2 || args.size() > 3) {
std::cerr << "Usage:\n " << prog_name << " ZIPFILE [OUTFILE]\n";
return EXIT_FAILURE;
}
std::string filename(args[1]);
ZipSapiSandbox sandbox;
if (!sandbox.Init().ok()) {
std::cerr << "Unable to start sandbox\n";
return EXIT_FAILURE;
}
LibZip zip(&sandbox, filename, 0);
if (!zip.IsOpen()) {
std::cerr << "Unable to open file " << filename << "\n";
return EXIT_FAILURE;
}
int outfd = -1;
if (args.size() == 3) {
outfd = open(args[2], O_WRONLY | O_CREAT);
if (outfd < 0) {
std::cerr << "Unable to open file " << args[2] << "\n";
return EXIT_FAILURE;
}
}
bool needs_saving = false;
absl::Status status;
if (absl::GetFlag(FLAGS_list)) {
status = ListFiles(zip);
}
if (!absl::GetFlag(FLAGS_unzip).empty()) {
status = UnzipToStdout(zip, absl::GetFlag(FLAGS_unzip));
}
if (!absl::GetFlag(FLAGS_add_file).empty()) {
status = AddFile(zip, absl::GetFlag(FLAGS_add_file));
needs_saving = true;
}
if (!absl::GetFlag(FLAGS_delete).empty()) {
status = DeleteFile(zip, absl::GetFlag(FLAGS_delete));
needs_saving = true;
}
if (!status.ok()) {
std::cerr << status << "\n";
return EXIT_FAILURE;
}
status = zip.Finish();
if (!status.ok()) {
std::cerr << status << "\n";
return EXIT_FAILURE;
}
if (needs_saving) {
if (outfd == -1) {
status = zip.Save();
} else {
status = zip.Save(outfd);
}
if (!status.ok()) {
std::cerr << status << "\n";
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}

BIN
contrib/libzip/files/binary Normal file

Binary file not shown.

View File

@ -0,0 +1,180 @@
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

59
contrib/libzip/files/text Normal file
View File

@ -0,0 +1,59 @@
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam id ultricies neque, id blandit nisl. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas pharetra urna purus, a finibus erat sodales ac. Donec sed convallis felis, ac rutrum velit. Suspendisse dapibus ultrices euismod. Donec non erat scelerisque, pretium dui id, dignissim dolor. Vivamus id orci maximus, maximus sapien sed, tincidunt nunc.
Praesent fringilla lectus lobortis dui posuere, ac mollis neque ultrices. Fusce nec quam eget neque feugiat mollis quis sit amet ipsum. Suspendisse hendrerit elit tincidunt neque tincidunt mattis. Nulla vitae neque sit amet metus consequat ultrices a ac augue. Nunc viverra lacinia ultrices. Vivamus in cursus ex, a sollicitudin purus. Curabitur et consectetur enim. Duis euismod magna eget velit tristique, at varius lorem posuere. Quisque non erat at diam blandit sollicitudin sit amet ac lectus. Maecenas nec consectetur augue, vel dignissim orci. Etiam rutrum ac massa at accumsan.
Nullam congue lacus et eros ornare, et malesuada nunc varius. Mauris facilisis suscipit nisl non tristique. Proin lobortis diam vel mi tempus, sit amet iaculis eros iaculis. Phasellus a metus ac purus pellentesque fermentum. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Suspendisse venenatis quam vel sapien scelerisque commodo. Donec nec urna feugiat, semper ipsum non, dapibus neque. Aenean egestas tortor sit amet interdum convallis.
Cras sed enim scelerisque orci hendrerit porta. Duis egestas erat sollicitudin vestibulum convallis. Proin eget eros in neque ultricies posuere. Quisque sodales nisi nulla, non sollicitudin ipsum sodales in. Phasellus feugiat sollicitudin enim, in faucibus massa cursus nec. Donec arcu erat, ultricies eget nisi scelerisque, pharetra fringilla nisl. Maecenas et consectetur neque. Duis vel rhoncus lacus. Nulla nec lorem iaculis, consequat sapien a, semper leo.
Praesent vehicula sem in tempor pulvinar. Sed porttitor volutpat nulla eget tempor. Phasellus sit amet quam justo. Donec sit amet lacus dolor. Ut finibus sollicitudin dui vitae tincidunt. Mauris commodo nec orci convallis accumsan. In dapibus urna ex, in convallis purus ornare vel.
Suspendisse potenti. Nulla mi lorem, dictum accumsan mollis vitae, commodo vitae purus. Nullam accumsan lectus elit, vel volutpat lectus varius eget. Sed in condimentum neque. Mauris nibh arcu, dignissim sed ipsum a, imperdiet mattis neque. Nam eu pretium orci, a semper mauris. Proin dui lacus, auctor nec nibh sed, eleifend interdum libero. Vestibulum venenatis gravida risus in pulvinar. Sed sit amet leo vehicula, lacinia nisi et, dignissim ex. Fusce consectetur sollicitudin nisi. Pellentesque nec mauris vitae arcu iaculis semper eu eu odio. Ut facilisis erat a hendrerit egestas. Nullam tristique augue nunc, et ornare risus efficitur et. Quisque placerat risus metus, eu rutrum dui egestas et. Donec elementum sapien leo, vitae porttitor metus pharetra luctus.
Ut non neque vel nibh accumsan luctus at eu ipsum. Ut vitae lacus vestibulum, sodales purus quis, elementum neque. Pellentesque a justo non massa finibus iaculis in sit amet mi. Nunc vel justo libero. Proin mollis ex quis nulla sollicitudin, quis porttitor justo imperdiet. Aenean vulputate semper consectetur. Aenean nibh tortor, viverra commodo magna sed, condimentum efficitur tellus. Maecenas eros mauris, tempor at porta ut, laoreet quis est. Proin eu purus a dolor aliquet bibendum nec ac velit. Phasellus quis tortor risus. Aliquam non felis quis massa scelerisque ullamcorper. Nulla tristique nunc ligula, quis semper lacus tincidunt ut. Maecenas in aliquet magna. Phasellus sed dolor id felis blandit efficitur a at nulla.
Curabitur condimentum est non felis luctus, in tempus tellus tempus. Curabitur at quam nec mi vulputate sollicitudin quis a arcu. Phasellus lectus lorem, feugiat sit amet accumsan in, pretium ut leo. Integer vulputate ante ac nunc elementum varius. Nunc interdum tellus auctor, rutrum urna ut, imperdiet quam. Maecenas non accumsan lorem. Donec sem augue, tincidunt vel aliquam in, viverra et tellus. Duis lobortis, arcu quis scelerisque rhoncus, velit enim lacinia sem, sed commodo lorem ex cursus ligula. Integer nec auctor erat. Proin feugiat vel odio a fringilla. Nam dignissim augue elit. Nam sed lectus consequat, lacinia est vel, maximus eros. Aenean egestas ultricies odio. Mauris ut cursus ipsum. Fusce porttitor, eros sed sollicitudin porttitor, quam ipsum blandit nunc, ut sagittis metus diam tristique tortor. In sagittis odio odio, et ullamcorper augue gravida vel.
Nam vulputate nulla ut faucibus pulvinar. Praesent in purus non orci semper imperdiet. Vivamus vel diam ornare, eleifend tellus sit amet, viverra orci. Proin porttitor ipsum et odio laoreet, quis efficitur nisl dictum. Vestibulum mollis, arcu ut semper iaculis, nulla sapien vehicula enim, quis vulputate dolor leo hendrerit felis. Vestibulum mi purus, tristique vel vulputate et, efficitur ac turpis. Aenean facilisis sed nisl ac iaculis. Proin scelerisque justo a diam commodo, ac volutpat nisi sodales. Aliquam hendrerit blandit sapien, eu pretium risus dictum nec. Aliquam ultrices tincidunt magna nec bibendum. Vivamus dapibus et lectus at suscipit. Phasellus maximus, nibh sed tempor convallis, arcu erat condimentum ex, id laoreet ex leo nec mi. Aenean ultricies eget quam non ultrices. Donec sollicitudin ex non elit mattis rutrum.
Aliquam feugiat, elit a lobortis aliquam, orci augue rhoncus urna, et condimentum nibh est at est. Morbi eu diam quis nisi tristique tempus id ac tortor. Praesent a aliquet sem. Donec a mollis tellus, in dapibus ligula. Nullam quis dictum leo. Nam turpis diam, imperdiet id felis non, rutrum vehicula dui. Donec eleifend augue eu mauris tristique, non condimentum sapien dapibus. Fusce congue scelerisque suscipit. In in vulputate enim, malesuada mollis augue. Vestibulum tristique tempus ipsum vel venenatis. Quisque mauris urna, congue in lorem sed, dapibus convallis lorem. In eget arcu varius, tempor nisi quis, fermentum ipsum. Cras faucibus lacus sed massa pulvinar, vel viverra felis rhoncus.
Nulla in nisi fringilla, molestie nisi at, dapibus arcu. Aenean ut justo eget neque tincidunt elementum. Ut varius, neque eu tempor pellentesque, magna turpis fermentum neque, eget pulvinar diam purus sit amet augue. Curabitur suscipit pharetra nisi egestas convallis. Aliquam et ex pulvinar eros malesuada viverra sed in libero. Quisque molestie dictum arcu at ultricies. Nulla id metus non lacus posuere vestibulum vel ut sem. Proin pulvinar nisl nisl, a imperdiet enim ultrices vel. Etiam malesuada posuere dignissim. Donec mollis nulla ut enim sollicitudin, nec commodo ante malesuada. Quisque sit amet augue eu quam malesuada mollis sed at ipsum.
Aliquam quam est, maximus sed porta ut, placerat eu nunc. Vivamus ultrices ultricies tristique. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. In et mi eu lacus rhoncus condimentum ultrices non velit. Suspendisse imperdiet, ipsum eu commodo euismod, est dolor sollicitudin augue, eu blandit risus tortor sit amet eros. Aliquam rutrum feugiat magna, sit amet aliquam tortor rutrum non. Fusce tempor rhoncus lectus vitae molestie. Sed ut tellus sagittis, congue enim mollis, malesuada ligula. Sed id tellus vel dolor commodo posuere malesuada et felis.
Morbi quis risus nec lectus maximus tristique vehicula a lectus. Suspendisse ipsum urna, accumsan sit amet dui id, malesuada pellentesque diam. Sed sit amet tellus rutrum, placerat urna nec, tristique libero. Etiam luctus sit amet dui in rutrum. Etiam iaculis, tortor ut vulputate blandit, enim ligula euismod tortor, a porttitor leo ex sit amet lorem. Proin fermentum, est et fermentum laoreet, ante risus aliquam odio, nec consectetur dui leo in est. Etiam dapibus risus sit amet quam viverra gravida. Aenean at libero quis dolor consectetur ultricies. Maecenas rutrum mattis dui, ut auctor elit fringilla vitae. Nulla consequat tincidunt ligula ac dapibus. Vestibulum nisl erat, pharetra ac cursus sed, molestie sit amet justo. Vestibulum lobortis id ligula in elementum. Mauris non purus a magna feugiat tempus et at erat. In tincidunt diam vitae rutrum molestie. Pellentesque ut nisi laoreet, semper mi aliquet, rhoncus dolor.
Pellentesque lacinia quis felis ac fringilla. Cras ante enim, efficitur non erat in, gravida mollis diam. Aliquam accumsan nulla nec eros aliquam fringilla. Mauris scelerisque aliquam fringilla. Aliquam lacinia mi orci, sit amet dignissim lorem lacinia at. Duis elit arcu, iaculis id risus at, porta sollicitudin sapien. Duis ante eros, consequat vitae massa at, auctor interdum nisi. Vivamus sit amet dui neque. Mauris tincidunt vestibulum arcu, consequat condimentum urna tincidunt vel. Sed a urna magna. Nullam in pharetra nulla.
Nunc id purus at ipsum blandit consectetur sagittis non lorem. In sit amet aliquam ante. Integer convallis lectus eu lorem finibus vulputate. Morbi feugiat turpis id neque posuere, non elementum turpis volutpat. Nullam gravida, turpis vitae varius placerat, neque nisl bibendum velit, at suscipit eros ipsum et lorem. Integer arcu eros, gravida eu mauris condimentum, tincidunt euismod mi. Sed id elit vitae nulla aliquet laoreet. Sed pulvinar sollicitudin fermentum. Fusce semper ullamcorper mollis. Aenean laoreet, sem non cursus volutpat, metus elit scelerisque nisi, eget maximus neque enim non orci.
Curabitur lacinia suscipit rutrum. Curabitur convallis eu lorem nec accumsan. Morbi et turpis sit amet erat mollis vehicula et eu risus. Nulla vel urna mollis, laoreet risus vel, auctor risus. Cras rutrum tempor ligula, sed fringilla justo tempor gravida. Nam tincidunt elementum dolor in sollicitudin. Donec pretium diam sed libero varius efficitur. Vivamus non nunc vulputate, accumsan ipsum sit amet, facilisis urna. Suspendisse suscipit, diam et ultrices maximus, enim sapien facilisis ligula, ut lacinia metus nisl eget felis. Proin egestas sollicitudin est ac auctor. Cras sapien turpis, interdum vitae laoreet sed, aliquam sed ex. Sed ullamcorper mi eu nisi varius facilisis. Nam fringilla at augue sit amet finibus. Mauris vitae facilisis purus.
Suspendisse hendrerit lacus eget nisi bibendum sodales. In scelerisque sem eget est suscipit, in sollicitudin urna ultricies. Aenean ac mi non mauris congue viverra. Nam fermentum, purus ut consectetur volutpat, augue arcu luctus eros, quis efficitur felis mi nec ligula. Nullam eget feugiat ante. Donec rutrum, ex sit amet sodales venenatis, leo nibh euismod lacus, nec auctor purus urna in enim. Aliquam erat volutpat. Ut a ante rhoncus, cursus massa quis, porttitor mi. Nullam non lectus et mauris mollis lacinia. Curabitur euismod euismod nisi vitae malesuada. Donec vel finibus justo. Suspendisse lobortis efficitur ligula sed bibendum.
Integer mauris nulla, auctor vel imperdiet vitae, commodo vel arcu. Nulla sit amet tempor ante, ac elementum dolor. Nam fermentum euismod est nec pulvinar. Etiam eleifend blandit nisl non mollis. Vestibulum porta sed nunc at aliquet. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Interdum et malesuada fames ac ante ipsum primis in faucibus. Donec id sem eu eros lobortis malesuada. Maecenas cursus neque a purus rhoncus, fermentum sagittis enim viverra. Proin blandit laoreet est eget feugiat.
Nulla nec nulla pellentesque, ullamcorper felis eget, bibendum augue. Sed lectus felis, tempor ac est non, commodo viverra augue. Ut bibendum arcu eget dapibus consectetur. Morbi id lectus vulputate, maximus leo sed, tincidunt leo. Nunc id nibh a lacus sagittis tristique at ac dolor. Nunc sed iaculis dolor. Cras maximus vulputate metus, a finibus magna sagittis non. Morbi porta fringilla enim, non pellentesque elit pellentesque eu. Vivamus pharetra dictum fermentum. Etiam consequat iaculis consequat. Morbi pharetra ante quam, quis efficitur purus finibus quis. Nulla at volutpat arcu. Curabitur augue lorem, lacinia eget augue vel, dignissim fringilla augue. Duis facilisis nulla turpis, ut fringilla quam efficitur ut. Cras tincidunt, tellus et dignissim ultricies, ligula ex pulvinar enim, vitae convallis erat ex ac neque.
Mauris sed auctor lorem. Vestibulum non ligula viverra, rhoncus quam at, pulvinar tellus. Phasellus dictum tellus eu nisl dignissim, id vulputate odio tincidunt. Mauris ornare ipsum nec maximus maximus. Nulla non sagittis turpis, in blandit magna. Donec at leo gravida, cursus diam ac, ornare velit. Praesent ipsum lorem, fermentum id lacinia ac, ultrices ac lectus. Vestibulum efficitur eget ipsum vitae vulputate. Aenean placerat magna sed ligula efficitur, ut consequat eros vestibulum. Proin placerat sapien sed arcu pharetra volutpat. Nunc diam lectus, tincidunt id eleifend vel, lobortis a lectus. In id orci sed purus venenatis pulvinar quis eget odio. Praesent quis nisi porta, blandit nisi a, hendrerit lacus. Morbi mollis libero non commodo consequat. Nullam id erat mi.
Vestibulum sit amet ante turpis. Duis in cursus eros. Praesent luctus eget augue tristique porttitor. Sed scelerisque facilisis sem sed interdum. Donec tristique augue ex, sit amet auctor ex elementum id. Sed lacinia ultrices dui, vitae scelerisque leo fringilla quis. Proin condimentum facilisis justo. Integer nulla mi, laoreet vel magna elementum, dignissim volutpat turpis. Aliquam erat volutpat.
Ut at quam nulla. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam maximus felis quis tincidunt fringilla. Fusce hendrerit pharetra pharetra. Nullam venenatis augue eget neque venenatis varius. Aenean posuere posuere nibh, sed vulputate purus tristique a. Sed nec lacus egestas, rhoncus nunc varius, euismod metus.
Aliquam pellentesque vel turpis ut aliquam. Fusce aliquam fermentum eros, gravida finibus arcu lacinia ut. Morbi vehicula nulla vitae viverra imperdiet. Curabitur eu euismod dui. Nullam congue congue odio, vel varius libero volutpat ut. Curabitur ante urna, vehicula nec sodales vel, lacinia eget arcu. Ut mollis rhoncus orci et facilisis. Aenean feugiat, purus a porttitor feugiat, ex nunc convallis leo, vel semper metus dolor id neque. Proin placerat orci ut purus cursus vehicula. Praesent molestie gravida ipsum, ac sagittis augue viverra vitae. Donec mi purus, congue vitae blandit ut, sollicitudin eu lorem. Vivamus dapibus nibh sed placerat mollis. Fusce egestas nunc lorem, sed interdum turpis gravida eget. Pellentesque enim ante, accumsan pulvinar dignissim ut, faucibus ac orci.
Fusce tempor fringilla bibendum. Nulla eu suscipit dui. In hac habitasse platea dictumst. Vivamus at lobortis orci, sit amet aliquet nunc. Nunc lacus mauris, sagittis in ornare sit amet, venenatis et dolor. Donec pellentesque nisl blandit, facilisis urna ac, dapibus nisl. Integer sollicitudin commodo euismod. Maecenas vulputate consequat ligula a accumsan. Nunc id risus magna. Nullam pulvinar blandit ante quis elementum.
Aliquam cursus lectus dui, facilisis tincidunt libero euismod id. Integer id placerat ligula, sit amet mattis mi. Nullam sed nunc orci. Etiam ac dolor sit amet purus consectetur hendrerit. Sed facilisis venenatis ullamcorper. Maecenas tincidunt nunc scelerisque vehicula eleifend. Nullam tincidunt tristique felis sed tempus. Donec nec fermentum dui, in tempus libero. Nam viverra mauris ornare mi finibus, sit amet convallis dui aliquam. Cras ut ultrices tellus. Pellentesque scelerisque placerat vehicula. Quisque cursus malesuada nunc, ut ultricies metus imperdiet eget.
Proin tristique gravida justo eget hendrerit. Donec id tincidunt sapien. Fusce elementum metus eget risus fermentum, eget venenatis purus rutrum. Maecenas rhoncus pharetra eros a iaculis. Aliquam vestibulum ipsum sed vehicula tempor. Sed convallis tellus sed augue pellentesque, eget suscipit ex iaculis. Integer nisl sapien, vulputate vel congue eget, viverra id ante. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nunc blandit aliquet ex nec vehicula. Sed tristique gravida tellus eget egestas. Quisque bibendum ligula velit, sed egestas diam rutrum in. Maecenas hendrerit augue nec elit lacinia mattis.
Phasellus ultrices ex augue, vel venenatis turpis laoreet in. Suspendisse a imperdiet lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nulla quis nisl finibus, dictum urna eget, fermentum purus. Nam fermentum magna id nisi semper, nec tempor lorem blandit. Sed dignissim fringilla dui id lacinia. Phasellus vitae viverra erat. Interdum et malesuada fames ac ante ipsum primis in faucibus. Pellentesque vel malesuada lorem, pharetra consequat diam. Quisque tempor dui eu quam aliquam porta. Donec tortor tortor, tristique vitae sem eget, euismod viverra justo. Morbi id mollis ex. Suspendisse potenti. Donec rutrum, orci id molestie malesuada, massa ex fermentum nisi, vitae facilisis nisi turpis eget enim. Sed eu mi at augue maximus rhoncus. Cras vehicula tellus non gravida efficitur.
Mauris eros justo, finibus lacinia sodales ut, tempus a ligula. Nulla sit amet sagittis mauris, non fermentum magna. Quisque tristique sagittis porta. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In ultricies, lectus in rutrum lobortis, elit nisi bibendum turpis, a gravida ligula mi id dolor. In rhoncus suscipit lectus ac maximus. Nunc vulputate aliquam laoreet. Morbi eget purus sit amet odio suscipit rutrum. Suspendisse id enim eget justo fringilla fringilla. Maecenas et nulla consectetur, feugiat orci ac, scelerisque est. Pellentesque iaculis justo dui, nec volutpat elit tincidunt eget. Curabitur finibus est a nisl interdum, ut rutrum lorem luctus.
Nam dolor ipsum, egestas eget luctus nec, congue vitae eros. Donec libero massa, molestie nec augue lacinia, auctor iaculis tortor. Proin tellus mi, vestibulum in lacus at, fringilla commodo nulla. Ut ullamcorper, quam at blandit congue, mauris purus volutpat nisl, quis fermentum justo ipsum id mi. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Etiam vestibulum augue eget sagittis porta. Curabitur eget purus placerat, fringilla lorem non, pretium mauris. Suspendisse potenti. Ut cursus erat augue, quis laoreet felis posuere sit amet. Suspendisse potenti. Sed aliquet semper quam quis ultrices. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Donec placerat massa et ipsum malesuada, in fringilla mi mollis. Curabitur vel condimentum enim. Donec luctus libero eget dapibus sagittis. Cras vulputate nibh non mauris accumsan, vel lobortis elit hendrerit. Praesent hendrerit ligula purus, non consequat libero accumsan sed. Suspendisse fringilla, tortor in fermentum congue, arcu tellus mollis sem, ut tempus enim dui non leo. Sed in augue diam. Maecenas vel neque eget mi lacinia ornare. Maecenas pharetra consectetur erat non feugiat. Aliquam lacinia augue eget elit maximus fringilla. Suspendisse risus lorem, porta eget nunc a, porta lobortis sapien.

Binary file not shown.

View File

@ -0,0 +1,51 @@
// 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_LIBZIP_SANDBOXED_H_
#define CONTRIB_LIBZIP_SANDBOXED_H_
#include <libgen.h>
#include <syscall.h>
#include <memory>
// XXX: This header is required because of the bug in generator.
// The generator for some reason doesn't catch the types
// defined by zip (for example zip_uint32_t).
#include <zipconf.h>
#include "sapi_zip.sapi.h" // NOLINT(build/include)
class ZipSapiSandbox : public ZipSandbox {
public:
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
sandbox2::PolicyBuilder*) override {
return sandbox2::PolicyBuilder()
.AllowDynamicStartup()
.AllowRead()
.AllowWrite()
.AllowSystemMalloc()
.AllowExit()
.AllowSafeFcntl()
.AllowSyscalls({
__NR_dup,
__NR_recvmsg,
__NR_ftruncate,
})
.BlockSyscallWithErrno(__NR_openat, ENOENT)
.BuildOrDie();
}
};
#endif // CONTRIB_LIBZIP_SANDBOXED_H_

View File

@ -0,0 +1,33 @@
# 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_zip_test
test_zip.cc
../utils/utils_zip.cc
)
target_link_libraries(
sapi_zip_test PRIVATE
sapi_zip
sapi::temp_file
sapi::test_main
)
gtest_discover_tests(sapi_zip_test PROPERTIES ENVIRONMENT "TEST_FILES_DIR=${PROJECT_SOURCE_DIR}/files")

View File

@ -0,0 +1,392 @@
// 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/libzip/sandboxed.h"
#include "contrib/libzip/utils/utils_zip.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;
class ZipBase : public testing::Test {
protected:
std::string GetTestFilePath(const std::string& filename);
std::string GetTemporaryFile(const std::string& filename);
std::streamsize GetStreamSize(std::ifstream& stream);
absl::StatusOr<std::vector<uint8_t>> ReadFile(const std::string& filename);
void SetUp() override;
const char* test_files_dir_;
std::string test_path_zip_;
std::unique_ptr<ZipSapiSandbox> sandbox_;
};
class ZipMultiFiles
: public ZipBase,
public testing::WithParamInterface<std::pair<uint64_t, std::string>> {};
void ZipBase::SetUp() {
test_files_dir_ = getenv("TEST_FILES_DIR");
ASSERT_NE(test_files_dir_, nullptr);
test_path_zip_ = GetTestFilePath("zip.zip");
sandbox_ = std::make_unique<ZipSapiSandbox>();
ASSERT_THAT(sandbox_->Init(), IsOk());
}
absl::StatusOr<std::vector<uint8_t>> ZipBase::ReadFile(
const std::string& filename) {
std::ifstream file(filename, std::ios::binary);
if (!file.is_open()) {
return absl::UnavailableError("Unable to open file");
}
std::streamsize size = GetStreamSize(file);
std::vector<uint8_t> buf(size);
file.read(reinterpret_cast<char*>(buf.data()), size);
if (file.gcount() != size) {
return absl::UnavailableError("Unable to read data");
}
return buf;
}
std::string ZipBase::GetTestFilePath(const std::string& filename) {
return sapi::file::JoinPath(test_files_dir_, filename);
}
std::string ZipBase::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);
}
std::streamsize ZipBase::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;
}
TEST_F(ZipBase, CheckInit) {
LibZip zip(sandbox_.get(), test_path_zip_, 0);
ASSERT_THAT(zip.IsOpen(), true);
}
TEST_F(ZipBase, CheckFileCount) {
LibZip zip(sandbox_.get(), test_path_zip_, 0);
ASSERT_THAT(zip.IsOpen(), true);
SAPI_ASSERT_OK_AND_ASSIGN(uint64_t count, zip.GetNumberEntries());
ASSERT_EQ(count, 2);
}
TEST_F(ZipBase, AddFileBuf) {
LibZip zip(sandbox_.get(), test_path_zip_, 0);
ASSERT_THAT(zip.IsOpen(), true);
SAPI_ASSERT_OK_AND_ASSIGN(auto newdata,
ReadFile(GetTestFilePath("notinzip")));
SAPI_ASSERT_OK_AND_ASSIGN(uint64_t index, zip.AddFile("test", newdata));
SAPI_ASSERT_OK_AND_ASSIGN(uint64_t count, zip.GetNumberEntries());
ASSERT_EQ(count, 3);
SAPI_ASSERT_OK_AND_ASSIGN(std::string newname, zip.GetName(index));
ASSERT_EQ(newname, "test");
}
TEST_F(ZipBase, AddFileFd) {
LibZip zip(sandbox_.get(), test_path_zip_, 0);
ASSERT_THAT(zip.IsOpen(), true);
int fd = open(GetTestFilePath("notinzip").c_str(), O_RDONLY);
ASSERT_GE(fd, 0);
SAPI_ASSERT_OK_AND_ASSIGN(uint64_t index, zip.AddFile("test", fd));
SAPI_ASSERT_OK_AND_ASSIGN(uint64_t count, zip.GetNumberEntries());
ASSERT_EQ(count, 3);
SAPI_ASSERT_OK_AND_ASSIGN(std::string newname, zip.GetName(index));
ASSERT_EQ(newname, "test");
}
TEST_F(ZipMultiFiles, AddFileBufInplaceStore) {
std::string new_path_zip = GetTemporaryFile("newzip.zip");
ASSERT_TRUE(
sapi::file_util::fileops::CopyFile(test_path_zip_, new_path_zip, 0644));
LibZip zip(sandbox_.get(), new_path_zip, 0);
ASSERT_THAT(zip.IsOpen(), true);
SAPI_ASSERT_OK_AND_ASSIGN(auto newdata,
ReadFile(GetTestFilePath("notinzip")));
SAPI_ASSERT_OK_AND_ASSIGN(uint64_t index, zip.AddFile("test", newdata));
ASSERT_THAT(zip.Finish(), IsOk());
ASSERT_THAT(zip.Save(), IsOk());
LibZip newzip(sandbox_.get(), new_path_zip, 0);
ASSERT_THAT(newzip.IsOpen(), true);
SAPI_ASSERT_OK_AND_ASSIGN(auto nameddata, newzip.ReadFile("test"));
ASSERT_EQ(newdata, newdata);
SAPI_ASSERT_OK_AND_ASSIGN(auto indexeddata, newzip.ReadFile(index));
ASSERT_EQ(indexeddata, newdata);
}
TEST_P(ZipMultiFiles, CheckFileNames) {
LibZip zip(sandbox_.get(), test_path_zip_, 0);
ASSERT_THAT(zip.IsOpen(), true);
uint64_t index = GetParam().first;
std::string origname = GetParam().second;
SAPI_ASSERT_OK_AND_ASSIGN(std::string name, zip.GetName(index));
ASSERT_EQ(name, origname);
}
TEST_P(ZipMultiFiles, DeleteFile) {
LibZip zip(sandbox_.get(), test_path_zip_, 0);
ASSERT_THAT(zip.IsOpen(), true);
uint64_t index = GetParam().first;
std::string origname = GetParam().second;
SAPI_ASSERT_OK_AND_ASSIGN(uint64_t count, zip.GetNumberEntries());
ASSERT_THAT(zip.DeleteFile(index), IsOk());
for (uint64_t i = 0; i < count; i++) {
absl::StatusOr<std::string> name = zip.GetName(i);
if (i == index) {
ASSERT_FALSE(name.ok());
} else {
ASSERT_THAT(name, IsOk());
ASSERT_NE(*name, origname);
}
}
}
TEST_P(ZipMultiFiles, ReadFileName) {
LibZip zip(sandbox_.get(), test_path_zip_, 0);
ASSERT_THAT(zip.IsOpen(), true);
std::string name = GetParam().second;
SAPI_ASSERT_OK_AND_ASSIGN(auto zipdata, zip.ReadFile(name));
SAPI_ASSERT_OK_AND_ASSIGN(auto origdata, ReadFile(GetTestFilePath(name)));
ASSERT_EQ(zipdata, origdata);
}
TEST_P(ZipMultiFiles, ReadFileIndex) {
LibZip zip(sandbox_.get(), test_path_zip_, 0);
ASSERT_THAT(zip.IsOpen(), true);
uint64_t index = GetParam().first;
std::string name = GetParam().second;
SAPI_ASSERT_OK_AND_ASSIGN(auto zipdata, zip.ReadFile(index));
SAPI_ASSERT_OK_AND_ASSIGN(auto origdata, ReadFile(GetTestFilePath(name)));
ASSERT_EQ(zipdata, origdata);
}
TEST_P(ZipMultiFiles, AddFileBufNewStore) {
LibZip zip(sandbox_.get(), test_path_zip_, 0);
ASSERT_THAT(zip.IsOpen(), true);
SAPI_ASSERT_OK_AND_ASSIGN(auto newdata,
ReadFile(GetTestFilePath("notinzip")));
SAPI_ASSERT_OK_AND_ASSIGN(uint64_t index, zip.AddFile("test", newdata));
std::string new_zip_file_name = GetTemporaryFile("newzip.zip");
int newfdzip = open(new_zip_file_name.c_str(), O_WRONLY);
ASSERT_GE(newfdzip, 0);
ASSERT_THAT(zip.Finish(), IsOk());
ASSERT_THAT(zip.Save(newfdzip), IsOk());
close(newfdzip);
LibZip newzip(sandbox_.get(), new_zip_file_name, 0);
ASSERT_THAT(newzip.IsOpen(), true);
SAPI_ASSERT_OK_AND_ASSIGN(auto nameddata, newzip.ReadFile("test"));
ASSERT_EQ(newdata, newdata);
SAPI_ASSERT_OK_AND_ASSIGN(auto indexeddata, newzip.ReadFile(index));
ASSERT_EQ(indexeddata, newdata);
// We also check if non other data was corrupted
uint64_t oldindex = GetParam().first;
std::string name = GetParam().second;
SAPI_ASSERT_OK_AND_ASSIGN(auto zipdata, newzip.ReadFile(oldindex));
SAPI_ASSERT_OK_AND_ASSIGN(auto origdata, ReadFile(GetTestFilePath(name)));
ASSERT_EQ(zipdata, origdata);
}
TEST_P(ZipMultiFiles, AddFileFdStore) {
LibZip zip(sandbox_.get(), test_path_zip_, 0);
ASSERT_THAT(zip.IsOpen(), true);
SAPI_ASSERT_OK_AND_ASSIGN(auto newdata,
ReadFile(GetTestFilePath("notinzip")));
int fd = open(GetTestFilePath("notinzip").c_str(), O_RDONLY);
ASSERT_GE(fd, 0);
SAPI_ASSERT_OK_AND_ASSIGN(uint64_t index, zip.AddFile("test", fd));
std::string new_zip_file_name = GetTemporaryFile("newzip.zip");
int newfdzip = open(new_zip_file_name.c_str(), O_WRONLY);
ASSERT_GE(newfdzip, 0);
ASSERT_THAT(zip.Finish(), IsOk());
ASSERT_THAT(zip.Save(newfdzip), IsOk());
close(newfdzip);
LibZip newzip(sandbox_.get(), new_zip_file_name, 0);
ASSERT_THAT(newzip.IsOpen(), true);
SAPI_ASSERT_OK_AND_ASSIGN(auto nameddata, newzip.ReadFile("test"));
ASSERT_EQ(nameddata, newdata);
SAPI_ASSERT_OK_AND_ASSIGN(auto indexeddata, newzip.ReadFile(index));
ASSERT_EQ(indexeddata, newdata);
// We also check if non other data was corrupted
uint64_t oldindex = GetParam().first;
std::string name = GetParam().second;
SAPI_ASSERT_OK_AND_ASSIGN(auto zipdata, newzip.ReadFile(oldindex));
SAPI_ASSERT_OK_AND_ASSIGN(auto origdata, ReadFile(GetTestFilePath(name)));
ASSERT_EQ(zipdata, origdata);
}
TEST_P(ZipMultiFiles, ReplaceFileBufStore) {
LibZip zip(sandbox_.get(), test_path_zip_, 0);
ASSERT_THAT(zip.IsOpen(), true);
uint64_t index = GetParam().first;
std::string name = GetParam().second;
SAPI_ASSERT_OK_AND_ASSIGN(auto newdata,
ReadFile(GetTestFilePath("notinzip")));
SAPI_ASSERT_OK_AND_ASSIGN(auto zipdata, zip.ReadFile(index));
ASSERT_NE(zipdata, newdata);
ASSERT_THAT(zip.ReplaceFile(index, newdata), IsOk());
std::string new_zip_file_name = GetTemporaryFile("newzip.zip");
int newfdzip = open(new_zip_file_name.c_str(), O_WRONLY);
ASSERT_GE(newfdzip, 0);
ASSERT_THAT(zip.Finish(), IsOk());
ASSERT_THAT(zip.Save(newfdzip), IsOk());
close(newfdzip);
LibZip newzip(sandbox_.get(), new_zip_file_name, 0);
ASSERT_THAT(newzip.IsOpen(), true);
SAPI_ASSERT_OK_AND_ASSIGN(auto nameddata, newzip.ReadFile(name));
ASSERT_EQ(nameddata, newdata);
SAPI_ASSERT_OK_AND_ASSIGN(auto indexeddata, newzip.ReadFile(index));
ASSERT_EQ(indexeddata, newdata);
}
TEST_P(ZipMultiFiles, ReplaceFileFdStore) {
LibZip zip(sandbox_.get(), test_path_zip_, 0);
ASSERT_THAT(zip.IsOpen(), true);
uint64_t index = GetParam().first;
std::string name = GetParam().second;
SAPI_ASSERT_OK_AND_ASSIGN(auto newdata,
ReadFile(GetTestFilePath("notinzip")));
SAPI_ASSERT_OK_AND_ASSIGN(auto zipdata, zip.ReadFile(index));
ASSERT_NE(zipdata, newdata);
int fd = open(GetTestFilePath("notinzip").c_str(), O_RDONLY);
ASSERT_GE(fd, 0);
ASSERT_THAT(zip.ReplaceFile(index, fd), IsOk());
std::string new_zip_file_name = GetTemporaryFile("newzip.zip");
int newfdzip = open(new_zip_file_name.c_str(), O_WRONLY);
ASSERT_GE(newfdzip, 0);
ASSERT_THAT(zip.Finish(), IsOk());
ASSERT_THAT(zip.Save(newfdzip), IsOk());
close(newfdzip);
LibZip newzip(sandbox_.get(), new_zip_file_name, 0);
ASSERT_THAT(newzip.IsOpen(), true);
SAPI_ASSERT_OK_AND_ASSIGN(auto nameddata, newzip.ReadFile(name));
ASSERT_EQ(nameddata, newdata);
SAPI_ASSERT_OK_AND_ASSIGN(auto indexeddata, newzip.ReadFile(index));
ASSERT_EQ(indexeddata, newdata);
}
TEST_P(ZipMultiFiles, DeleteFileStore) {
LibZip zip(sandbox_.get(), test_path_zip_, 0);
ASSERT_THAT(zip.IsOpen(), true);
uint64_t index = GetParam().first;
std::string origname = GetParam().second;
SAPI_ASSERT_OK_AND_ASSIGN(uint64_t oldcount, zip.GetNumberEntries());
ASSERT_THAT(zip.DeleteFile(index), IsOk());
std::string new_zip_file_name = GetTemporaryFile("newzip.zip");
int newfdzip = open(new_zip_file_name.c_str(), O_WRONLY);
ASSERT_GE(newfdzip, 0);
ASSERT_THAT(zip.Finish(), IsOk());
ASSERT_THAT(zip.Save(newfdzip), IsOk());
close(newfdzip);
LibZip newzip(sandbox_.get(), new_zip_file_name, 0);
ASSERT_THAT(newzip.IsOpen(), true);
SAPI_ASSERT_OK_AND_ASSIGN(uint64_t newcount, newzip.GetNumberEntries());
ASSERT_LT(newcount, oldcount);
for (uint64_t i = 0; i < newcount; i++) {
absl::StatusOr<std::string> name = newzip.GetName(i);
ASSERT_THAT(name, IsOk());
ASSERT_NE(*name, origname);
}
}
INSTANTIATE_TEST_SUITE_P(ZipBase, ZipMultiFiles,
testing::Values(std::make_pair(0, "binary"),
std::make_pair(1, "text")));
} // namespace

View File

@ -0,0 +1,324 @@
// 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/libzip/utils/utils_zip.h"
#include <fstream>
#include <iostream>
#include <string>
#include "absl/cleanup/cleanup.h"
#include "contrib/libzip/sandboxed.h"
constexpr uint64_t kFileMaxSize = 1024 * 1024 * 1024; // 1GB
#define ZIP_FL_ENC_GUESS 0
#define ZIP_FL_OVERWRITE 8192u
LibZip::~LibZip() {
if (IsOpen()) {
api_.zip_close(zip_.get()).IgnoreError();
}
api_.zip_source_free(&(*zipsource_)).IgnoreError();
}
bool LibZip::IsOpen() { return zip_ != nullptr; }
bool LibZip::IsOpenLocal() { return rfd_.GetValue() >= 0; }
absl::Status LibZip::CheckOpen() {
if (!IsOpen()) {
return absl::UnavailableError("Modification stage finished");
}
return absl::OkStatus();
}
absl::Status LibZip::CheckFinished() {
if (IsOpen()) {
return absl::UnavailableError("Still in modification stage");
}
return absl::OkStatus();
}
absl::Status LibZip::OpenRemote() {
if (!IsOpenLocal()) {
return absl::UnavailableError("Zip file is not open");
}
SAPI_RETURN_IF_ERROR(sandbox_->TransferToSandboxee(&rfd_));
SAPI_ASSIGN_OR_RETURN(void* zipsource, CreateSourceFromFd(rfd_));
zipsource_ = absl::make_unique<sapi::v::RemotePtr>(zipsource);
sapi::v::NullPtr null_ptr;
absl::StatusOr<zip_t*> status_or_zip =
api_.zip_open_from_source(&(*zipsource_), flags_, &null_ptr);
if (!status_or_zip.ok() || *status_or_zip == nullptr) {
api_.zip_source_free(&(*zipsource_)).IgnoreError();
zipsource_ = nullptr;
return absl::UnavailableError("Unable to open remote");
}
SAPI_RETURN_IF_ERROR(api_.zip_source_keep(&(*zipsource_)));
zip_ = absl::make_unique<sapi::v::RemotePtr>(*status_or_zip);
return absl::OkStatus();
}
absl::Status LibZip::Finish() {
SAPI_ASSIGN_OR_RETURN(int ret, api_.zip_close(zip_.get()));
if (ret < 0) {
return absl::UnavailableError("Unable to close remote");
}
zip_ = nullptr;
return absl::OkStatus();
}
absl::Status LibZip::Save(int fd) {
SAPI_RETURN_IF_ERROR(CheckFinished());
sapi::v::Fd rfd(fd);
SAPI_RETURN_IF_ERROR(sandbox_->TransferToSandboxee(&rfd));
return Save(rfd);
}
absl::Status LibZip::Save() {
SAPI_RETURN_IF_ERROR(CheckFinished());
return Save(rfd_);
}
absl::Status LibZip::Save(sapi::v::Fd& rfd) {
SAPI_RETURN_IF_ERROR(CheckFinished());
SAPI_ASSIGN_OR_RETURN(
bool ret, api_.zip_source_to_fd(&(*zipsource_), rfd.GetRemoteFd()));
if (!ret) {
return absl::UnavailableError("Unable to store data");
}
return absl::OkStatus();
}
absl::StatusOr<std::string> LibZip::GetName(uint64_t index) {
SAPI_RETURN_IF_ERROR(CheckOpen());
SAPI_ASSIGN_OR_RETURN(const char* name,
api_.zip_get_name(zip_.get(), index, ZIP_FL_ENC_GUESS));
if (name == nullptr) {
return absl::UnavailableError("Unable to find name under index");
}
return sandbox_->GetCString(sapi::v::RemotePtr(const_cast<char*>(name)));
}
absl::StatusOr<uint64_t> LibZip::GetNumberEntries() {
SAPI_RETURN_IF_ERROR(CheckOpen());
SAPI_ASSIGN_OR_RETURN(int64_t num, api_.zip_get_num_entries(zip_.get(), 0));
if (num < 0) {
/* Imposible as zip != nullptr */
return absl::UnavailableError("Internal error");
}
return num;
}
absl::StatusOr<std::vector<uint8_t>> LibZip::ReadFile(
sapi::v::RemotePtr& rzipfile, uint32_t size) {
SAPI_RETURN_IF_ERROR(CheckOpen());
if (size > kFileMaxSize) {
return absl::UnavailableError("File is to large");
}
std::vector<uint8_t> buf(size);
sapi::v::Array<uint8_t> arr(buf.data(), size);
SAPI_ASSIGN_OR_RETURN(uint64_t ret,
api_.zip_fread(&rzipfile, arr.PtrAfter(), size));
if (ret != size) {
return absl::UnavailableError("Unable to read file");
}
return buf;
}
absl::StatusOr<std::vector<uint8_t>> LibZip::ReadFile(
const std::string& filename) {
SAPI_RETURN_IF_ERROR(CheckOpen());
sapi::v::Struct<zip_stat_t> zipstat;
sapi::v::ConstCStr cfilename(filename.c_str());
SAPI_ASSIGN_OR_RETURN(
int err,
api_.zip_stat(zip_.get(), cfilename.PtrBefore(), 0, zipstat.PtrAfter()));
if (err < 0) {
return absl::UnavailableError("Unable to get file stat");
}
SAPI_ASSIGN_OR_RETURN(zip_file_t * zipfile,
api_.zip_fopen(zip_.get(), cfilename.PtrBefore(), 0));
if (zipfile == nullptr) {
return absl::UnavailableError("Unable to open file in archaive");
}
sapi::v::RemotePtr rzipfile(zipfile);
absl::Cleanup rzipfile_cleanup = [this, &rzipfile] {
api_.zip_fclose(&rzipfile).IgnoreError();
};
return ReadFile(rzipfile, zipstat.mutable_data()->size);
}
absl::StatusOr<std::vector<uint8_t>> LibZip::ReadFile(uint64_t index) {
SAPI_RETURN_IF_ERROR(CheckOpen());
sapi::v::Struct<zip_stat_t> zipstat;
SAPI_ASSIGN_OR_RETURN(
int err, api_.zip_stat_index(zip_.get(), index, 0, zipstat.PtrAfter()));
if (err < 0) {
return absl::UnavailableError("Unable to get file stat");
}
SAPI_ASSIGN_OR_RETURN(zip_file_t * zipfile,
api_.zip_fopen_index(zip_.get(), index, 0));
if (zipfile == nullptr) {
return absl::UnavailableError("Unable to open file in archaive");
}
sapi::v::RemotePtr rzipfile(zipfile);
absl::Cleanup rzipfile_cleanup = [this, &rzipfile] {
api_.zip_fclose(&rzipfile).IgnoreError();
};
return ReadFile(rzipfile, zipstat.mutable_data()->size);
}
absl::StatusOr<uint64_t> LibZip::AddFile(const std::string& filename,
sapi::v::RemotePtr& rzipsource) {
SAPI_RETURN_IF_ERROR(CheckOpen());
sapi::v::ConstCStr cfilename(filename.c_str());
SAPI_ASSIGN_OR_RETURN(int64_t index,
api_.zip_file_add(zip_.get(), cfilename.PtrBefore(),
&rzipsource, ZIP_FL_OVERWRITE));
if (index < 0) {
SAPI_ASSIGN_OR_RETURN(std::string errs, GetError());
api_.zip_source_free(&rzipsource).IgnoreError();
return absl::UnavailableError("Unable to add file");
}
return index;
}
absl::StatusOr<void*> LibZip::CreateSourceFromFd(sapi::v::Fd& rfd) {
sapi::v::NullPtr null_ptr;
SAPI_ASSIGN_OR_RETURN(void* zipsource, api_.zip_read_fd_to_source(
rfd.GetRemoteFd(), &null_ptr));
if (zipsource == nullptr) {
return absl::UnavailableError("Unable to create buffer");
}
return zipsource;
}
absl::StatusOr<void*> LibZip::GetSource(std::vector<uint8_t>& buf) {
sapi::v::Array<uint8_t> arr(buf.data(), buf.size());
SAPI_ASSIGN_OR_RETURN(
zip_source_t * zipsource,
api_.zip_source_buffer(zip_.get(), arr.PtrBefore(), arr.GetSize(),
1 /* autofree */));
if (zipsource == nullptr) {
return absl::UnavailableError("Unable to create buffer");
}
arr.SetRemote(nullptr); // We don't want to free automaticlt buffer
// leave memory menagment to the zip process
return zipsource;
}
absl::StatusOr<void*> LibZip::GetSource(int fd, const std::string& mode) {
sapi::v::Fd rfd(fd);
SAPI_RETURN_IF_ERROR(sandbox_->TransferToSandboxee(&rfd));
sapi::v::ConstCStr cmode(mode.c_str());
SAPI_ASSIGN_OR_RETURN(void* zipsource,
api_.zip_source_filefd(zip_.get(), rfd.GetRemoteFd(),
cmode.PtrBefore(), 0, 0));
if (zipsource == nullptr) {
return absl::UnavailableError("Unable to create buffer");
}
rfd.OwnRemoteFd(false);
return zipsource;
}
absl::StatusOr<uint64_t> LibZip::AddFile(const std::string& filename,
std::vector<uint8_t>& buf) {
SAPI_RETURN_IF_ERROR(CheckOpen());
SAPI_ASSIGN_OR_RETURN(void* zipsource, GetSource(buf));
sapi::v::RemotePtr rzipsource(zipsource);
return AddFile(filename, rzipsource);
}
absl::StatusOr<uint64_t> LibZip::AddFile(const std::string& filename, int fd) {
SAPI_RETURN_IF_ERROR(CheckOpen());
SAPI_ASSIGN_OR_RETURN(void* zipsource, GetSource(fd, "rb"));
sapi::v::RemotePtr rzipsource(zipsource);
return AddFile(filename, rzipsource);
}
absl::Status LibZip::ReplaceFile(uint64_t index,
sapi::v::RemotePtr& rzipsource) {
SAPI_RETURN_IF_ERROR(CheckOpen());
SAPI_ASSIGN_OR_RETURN(
int64_t ret, api_.zip_file_replace(zip_.get(), index, &rzipsource, 0));
if (ret < 0) {
api_.zip_source_free(&rzipsource).IgnoreError();
return absl::UnavailableError("Unable to replace file");
}
return absl::OkStatus();
}
absl::Status LibZip::ReplaceFile(uint64_t index, int fd) {
SAPI_RETURN_IF_ERROR(CheckOpen());
SAPI_ASSIGN_OR_RETURN(void* zipsource, GetSource(fd, "rb"));
sapi::v::RemotePtr rzipsource(zipsource);
return ReplaceFile(index, rzipsource);
}
absl::Status LibZip::ReplaceFile(uint64_t index, std::vector<uint8_t>& buf) {
SAPI_RETURN_IF_ERROR(CheckOpen());
SAPI_ASSIGN_OR_RETURN(void* zipsource, GetSource(buf));
sapi::v::RemotePtr rzipsource(zipsource);
return ReplaceFile(index, rzipsource);
}
absl::Status LibZip::DeleteFile(uint64_t index) {
SAPI_RETURN_IF_ERROR(CheckOpen());
SAPI_ASSIGN_OR_RETURN(int ret, api_.zip_delete(zip_.get(), index));
if (ret < 0) {
return absl::UnavailableError("Unable to delete file");
}
return absl::OkStatus();
}
absl::StatusOr<std::string> LibZip::GetError() {
SAPI_RETURN_IF_ERROR(CheckOpen());
SAPI_ASSIGN_OR_RETURN(const char* err, api_.zip_strerror(zip_.get()));
if (err == nullptr) {
return absl::UnavailableError("No error");
}
return sandbox_->GetCString(sapi::v::RemotePtr(const_cast<char*>(err)));
}

View File

@ -0,0 +1,84 @@
// 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_LIBZIP_UTILS_UTILS_ZIP_H_
#define CONTRIB_LIBZIP_UTILS_UTILS_ZIP_H_
#include <fcntl.h>
#include "contrib/libzip/sandboxed.h"
#include "sandboxed_api/util/status_macros.h"
class LibZip {
public:
explicit LibZip(ZipSandbox* sandbox, std::string filename, int flags)
: sandbox_(CHECK_NOTNULL(sandbox)),
api_(sandbox_),
filename_(std::move(filename)),
flags_(flags),
rfd_(open(filename.c_str(), O_RDWR | O_CREAT)) {
OpenRemote().IgnoreError();
};
~LibZip();
bool IsOpen();
absl::StatusOr<std::string> GetName(uint64_t index);
absl::StatusOr<uint64_t> GetNumberEntries();
absl::StatusOr<std::vector<uint8_t>> ReadFile(uint64_t index);
absl::StatusOr<std::vector<uint8_t>> ReadFile(const std::string& filename);
absl::StatusOr<uint64_t> AddFile(const std::string& filename,
std::vector<uint8_t>& buf);
absl::StatusOr<uint64_t> AddFile(const std::string& filename, int fd);
absl::Status ReplaceFile(uint64_t index, std::vector<uint8_t>& buf);
absl::Status ReplaceFile(uint64_t index, int fd);
absl::Status DeleteFile(uint64_t index);
absl::StatusOr<std::string> GetError();
absl::Status Finish();
// Save a copy of file to another fd.
absl::Status Save(int fd);
// Save a copy to the same fd.
absl::Status Save();
protected:
bool IsOpenLocal();
absl::Status OpenRemote();
absl::StatusOr<std::vector<uint8_t>> ReadFile(sapi::v::RemotePtr& zipfile,
uint32_t size);
absl::StatusOr<uint64_t> AddFile(const std::string& filename,
sapi::v::RemotePtr& rzipsource);
absl::Status ReplaceFile(uint64_t index, sapi::v::RemotePtr& rzipsource);
absl::StatusOr<void*> GetSource(std::vector<uint8_t>& buf);
absl::StatusOr<void*> GetSource(int fd, const std::string& mode);
absl::StatusOr<void*> CreateSourceFromFd(sapi::v::Fd& rfd);
absl::Status Save(sapi::v::Fd& fd);
absl::Status CheckOpen();
absl::Status CheckFinished();
private:
ZipSandbox* sandbox_;
ZipApi api_;
int flags_;
std::unique_ptr<sapi::v::RemotePtr> zip_;
std::unique_ptr<sapi::v::RemotePtr> zipsource_;
sapi::v::Fd rfd_;
std::string filename_;
};
#endif // CONTRIB_LIBZIP_UTILS_UTILS_ZIP_H_

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.
add_library(wrapper_zip STATIC
wrapper_zip.cc
)
target_link_libraries(wrapper_zip PUBLIC
libzip::zip
sapi::sapi
)
target_include_directories(wrapper_zip PUBLIC
"${SAPI_SOURCE_DIR}"
"${libzip_SOURCE_DIR}/lib/"
)

View File

@ -0,0 +1,120 @@
// 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/libzip/wrapper/wrapper_zip.h"
#include <fcntl.h>
#include <unistd.h>
#include <iostream>
#include "absl/cleanup/cleanup.h"
constexpr size_t kFileMaxSize = 1024 * 1024 * 1024; // 1GB
void* zip_source_filefd(zip_t* archive, int fd, const char* mode,
zip_uint64_t start, zip_int64_t len) {
FILE* pfile;
// The file stream is closed when the source is being freed,
// usually by zip_close(3).
pfile = fdopen(fd, mode);
if (pfile == nullptr) {
return nullptr;
}
return zip_source_filep(archive, pfile, start, len);
}
void* zip_source_filefd_create(int fd, const char* mode, zip_uint64_t start,
zip_int64_t len, zip_error_t* ze) {
FILE* pfile;
pfile = fdopen(fd, mode);
if (pfile == nullptr) {
return nullptr;
}
return zip_source_filep_create(pfile, start, len, ze);
}
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;
}
void* zip_read_fd_to_source(int fd, zip_error_t* ze) {
off_t sizein = FDGetSize(fd);
if (sizein > kFileMaxSize) {
return nullptr;
}
int8_t* buf = reinterpret_cast<int8_t*>(malloc(sizein));
if (buf == nullptr) {
return nullptr;
}
if (read(fd, buf, sizein) != sizein) {
free(buf);
return nullptr;
}
zip_source_t* src = zip_source_buffer_create(buf, sizein, 1, ze);
if (src == nullptr) {
free(buf);
return nullptr;
}
return src;
}
// This function is not atomic. Maybe it should be?
bool zip_source_to_fd(zip_source_t* src, int fd) {
if (lseek(fd, 0, SEEK_SET) < 0) {
return false;
}
if (ftruncate(fd, 0) < 0) {
return false;
}
if (zip_source_open(src) < 0) {
return false;
}
absl::Cleanup src_cleanup = [&src] { zip_source_close(src); };
if (zip_source_seek(src, 0, SEEK_SET) < 0) {
return false;
}
int8_t buf[4096];
size_t size;
while (true) {
size = zip_source_read(src, &buf, sizeof(buf));
if (size <= 0) {
break;
}
if (write(fd, &buf, size) != size) {
return false;
}
}
return size == 0;
}

View File

@ -0,0 +1,32 @@
// 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_LIBZIP_WRAPPER_WRAPPER_ZIP_H_
#define CONTRIB_LIBZIP_WRAPPER_WRAPPER_ZIP_H_
#include <zip.h>
extern "C" {
// XXX: it seems like a bug in sapi,
// if we use zip_source_t as return value it is converted to
// int.
void* zip_source_filefd(zip_t* archive, int fd, const char* flags,
zip_uint64_t start, zip_int64_t len);
void* zip_source_filefd_create(int fd, const char* flags, zip_uint64_t start,
zip_int64_t len, zip_error_t* ze);
void* zip_read_fd_to_source(int fd, zip_error_t* ze);
bool zip_source_to_fd(zip_source_t* src, int fd);
}
#endif // CONTRIB_ZIP_WRAPPER_WRAPPER_ZIP_H_