// Copyright 2019 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include #include #include "absl/base/macros.h" #include "sandboxed_api/util/flag.h" #include "sandboxed_api/examples/zlib/zlib-sapi.sapi.h" #include "sandboxed_api/examples/zlib/zlib-sapi_embed.h" #include "sandboxed_api/vars.h" // Need to define these manually, as zlib.h cannot be directly included. The // interface generator makes all functions available that were requested in // sapi_library(), but does not know which macro constants are needed by the // sandboxee. #define Z_NO_FLUSH 0 #define Z_FINISH 4 #define Z_OK 0 #define Z_DEFAULT_COMPRESSION (-1) #define Z_ERRNO (-1) #define Z_STREAM_ERROR (-2) #define Z_STREAM_END 1 int main(int argc, char** argv) { gflags::ParseCommandLineFlags(&argc, &argv, true); google::InitGoogleLogging(argv[0]); sapi::Sandbox sandbox(sapi::zlib::zlib_sapi_embed_create()); sapi::zlib::ZlibApi api(&sandbox); if (auto status = sandbox.Init(); !status.ok()) { LOG(FATAL) << "Couldn't initialize Sandboxed API for zlib: " << status.message(); } sapi::StatusOr ret; int flush; unsigned have; sapi::v::Struct strm; constexpr int kChunk = 16384; unsigned char in_[kChunk] = {0}; unsigned char out_[kChunk] = {0}; sapi::v::Array input(in_, kChunk); sapi::v::Array output(out_, kChunk); if (!sandbox.Allocate(&input).ok() || !sandbox.Allocate(&output).ok()) { LOG(FATAL) << "Allocate memory failed"; } constexpr char kZlibVersion[] = "1.2.11"; sapi::v::Array version(kZlibVersion, ABSL_ARRAYSIZE(kZlibVersion)); // Allocate deflate state. *strm.mutable_data() = sapi::zlib::z_stream{}; if (ret = api.deflateInit_(strm.PtrBoth(), Z_DEFAULT_COMPRESSION, version.PtrBefore(), sizeof(sapi::zlib::z_stream)); *ret != Z_OK) { return *ret; } LOG(INFO) << "Starting decompression"; // Compress until end of file. do { strm.mutable_data()->avail_in = fread(input.GetLocal(), 1, kChunk, stdin); if (!sandbox.TransferToSandboxee(&input).ok()) { LOG(FATAL) << "TransferToSandboxee failed"; } if (ferror(stdin)) { LOG(INFO) << "Error reading from stdin"; api.deflateEnd(strm.PtrBoth()).IgnoreError(); return Z_ERRNO; } flush = feof(stdin) ? Z_FINISH : Z_NO_FLUSH; strm.mutable_data()->next_in = reinterpret_cast(input.GetRemote()); // Run deflate() on input until output buffer not full, finish compression // if all of source has been read in. do { strm.mutable_data()->avail_out = kChunk; strm.mutable_data()->next_out = reinterpret_cast(output.GetRemote()); ret = api.deflate(strm.PtrBoth(), flush); // no bad return value. assert(*ret != Z_STREAM_ERROR); // state not clobbered. have = kChunk - strm.data().avail_out; if (!sandbox.TransferFromSandboxee(&output).ok()) { LOG(FATAL) << "TransferFromSandboxee failed"; } if (fwrite(output.GetLocal(), 1, have, stdout) != have || ferror(stdout)) { // Not really necessary as strm did not change from last transfer. api.deflateEnd(strm.PtrBoth()).IgnoreError(); return Z_ERRNO; } } while (strm.data().avail_out == 0); assert(strm.data().avail_in == 0); // all input will be used. // done when last data in file processed. } while (flush != Z_FINISH); assert(*ret == Z_STREAM_END); // stream will be complete. // clean up and return. api.deflateEnd(strm.PtrBoth()).IgnoreError(); return EXIT_SUCCESS; }