1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <cassert>
16 #include <cstdio>
17 #include <cstdlib>
18
19 #include "absl/base/log_severity.h"
20 #include "absl/base/macros.h"
21 #include "absl/flags/parse.h"
22 #include "absl/log/globals.h"
23 #include "absl/log/initialize.h"
24 #include "absl/log/log.h"
25 #include "absl/status/status.h"
26 #include "absl/status/statusor.h"
27 #include "sandboxed_api/examples/zlib/zlib-sapi.sapi.h"
28 #include "sandboxed_api/vars.h"
29
30 // Need to define these manually, as zlib.h cannot be directly included. The
31 // interface generator makes all functions available that were requested in
32 // sapi_library(), but does not know which macro constants are needed by the
33 // sandboxee.
34 #define Z_NO_FLUSH 0
35 #define Z_FINISH 4
36 #define Z_OK 0
37 #define Z_DEFAULT_COMPRESSION (-1)
38 #define Z_ERRNO (-1)
39 #define Z_STREAM_ERROR (-2)
40 #define Z_STREAM_END 1
41
main(int argc,char * argv[])42 int main(int argc, char* argv[]) {
43 absl::SetStderrThreshold(absl::LogSeverityAtLeast::kInfo);
44 absl::ParseCommandLine(argc, argv);
45 absl::InitializeLog();
46
47 sapi::Sandbox sandbox(sapi::zlib::zlib_sapi_embed_create());
48 sapi::zlib::ZlibApi api(&sandbox);
49 if (auto status = sandbox.Init(); !status.ok()) {
50 LOG(FATAL) << "Couldn't initialize Sandboxed API for zlib: "
51 << status.message();
52 }
53
54 absl::StatusOr<int> ret;
55 int flush;
56 unsigned have;
57 sapi::v::Struct<sapi::zlib::z_stream> strm;
58
59 constexpr int kChunk = 16384;
60 unsigned char in_[kChunk] = {0};
61 unsigned char out_[kChunk] = {0};
62 sapi::v::Array<unsigned char> input(in_, kChunk);
63 sapi::v::Array<unsigned char> output(out_, kChunk);
64 if (!sandbox.Allocate(&input).ok() || !sandbox.Allocate(&output).ok()) {
65 LOG(FATAL) << "Allocate memory failed";
66 }
67
68 constexpr char kZlibVersion[] = "1.2.11";
69 sapi::v::Array<const char> version(kZlibVersion,
70 ABSL_ARRAYSIZE(kZlibVersion));
71
72 // Allocate deflate state.
73 *strm.mutable_data() = sapi::zlib::z_stream{};
74
75 if (ret = api.deflateInit_(strm.PtrBoth(), Z_DEFAULT_COMPRESSION,
76 version.PtrBefore(), sizeof(sapi::zlib::z_stream));
77 *ret != Z_OK) {
78 return *ret;
79 }
80
81 LOG(INFO) << "Starting compression";
82
83 // Compress until end of file.
84 do {
85 strm.mutable_data()->avail_in = fread(input.GetLocal(), 1, kChunk, stdin);
86 if (!sandbox.TransferToSandboxee(&input).ok()) {
87 LOG(FATAL) << "TransferToSandboxee failed";
88 }
89 if (ferror(stdin)) {
90 LOG(INFO) << "Error reading from stdin";
91 api.deflateEnd(strm.PtrBoth()).IgnoreError();
92 return Z_ERRNO;
93 }
94 flush = feof(stdin) ? Z_FINISH : Z_NO_FLUSH;
95 strm.mutable_data()->next_in =
96 reinterpret_cast<unsigned char*>(input.GetRemote());
97
98 // Run deflate() on input until output buffer not full, finish compression
99 // if all of source has been read in.
100 do {
101 strm.mutable_data()->avail_out = kChunk;
102 strm.mutable_data()->next_out =
103 reinterpret_cast<unsigned char*>(output.GetRemote());
104
105 ret = api.deflate(strm.PtrBoth(), flush); // no bad return value.
106 assert(*ret != Z_STREAM_ERROR); // state not clobbered.
107 have = kChunk - strm.data().avail_out;
108
109 if (!sandbox.TransferFromSandboxee(&output).ok()) {
110 LOG(FATAL) << "TransferFromSandboxee failed";
111 }
112 if (fwrite(output.GetLocal(), 1, have, stdout) != have ||
113 ferror(stdout)) {
114 // Not really necessary as strm did not change from last transfer.
115 api.deflateEnd(strm.PtrBoth()).IgnoreError();
116 return Z_ERRNO;
117 }
118 } while (strm.data().avail_out == 0);
119 assert(strm.data().avail_in == 0); // all input will be used.
120
121 // done when last data in file processed.
122 } while (flush != Z_FINISH);
123 assert(*ret == Z_STREAM_END); // stream will be complete.
124
125 // clean up and return.
126 api.deflateEnd(strm.PtrBoth()).IgnoreError();
127
128 return EXIT_SUCCESS;
129 }
130