1 // Copyright 2020 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 "sapi_minitar.h"  // NOLINT(build/include)
16 
17 #include <dlfcn.h>
18 
19 #include <iostream>
20 #include <memory>
21 
22 #include "libarchive_sapi.sapi.h"  // NOLINT(build/include)
23 #include "sandbox.h"               // NOLINT(build/include)
24 #include "sandboxed_api/var_array.h"
25 #include "sandboxed_api/var_ptr.h"
26 
27 SapiLibarchiveSandboxExtract* sandbox_extract;
28 LibarchiveApi* api;
29 char* c_str_tmp = nullptr;
30 
31 typedef void (*real_extract)(const char*, int, int, int);
32 
extract(const char * filename,int do_extract,int flags,int verbose)33 void extract(const char* filename, int do_extract, int flags, int verbose) {
34   // Here we initialize the sandbox and other objects.
35   std::string tmp_dir;
36   if (do_extract) {
37     tmp_dir = CreateTempDirAtCWD().value();
38   }
39 
40   std::string filename_absolute = MakeAbsolutePathAtCWD(filename);
41 
42   // Initialize sandbox and api objects.
43   sandbox_extract =
44       new SapiLibarchiveSandboxExtract(filename_absolute, do_extract, tmp_dir);
45   CHECK(sandbox_extract->Init().ok()) << "Error during sandbox initialization";
46   api = new LibarchiveApi(sandbox_extract);
47 
48   // After everything is set up, call the original function (next symbol).
49 
50   // TODO getting the mangled name of the function at runtime does not work
51   // as intended. At the moment just use the symbol directly.
52   const char* y = "_Z7extractPKciii";
53   void* x = dlsym(RTLD_NEXT, y);
54 
55   CHECK(x != nullptr) << "dlsym call could not find function symbol";
56   ((real_extract)x)(filename_absolute.c_str(), do_extract, flags, verbose);
57 
58   // clean up
59   if (c_str_tmp != nullptr) {
60     delete[] c_str_tmp;
61   }
62 
63   // This is the last function called so we can delete the temporary directory
64   // here
65   if (do_extract) {
66     sandbox2::file_util::fileops::DeleteRecursively(tmp_dir);
67   }
68 
69   delete api;
70   delete sandbox_extract;
71 }
72 
archive_read_new()73 archive* archive_read_new() {
74   archive* ret = api->archive_read_new().value();
75   CHECK(ret != nullptr) << "Failed to create archive";
76   return ret;
77 }
78 
archive_write_disk_new()79 archive* archive_write_disk_new() {
80   archive* ret = api->archive_write_disk_new().value();
81   CHECK(ret != nullptr) << "Failed to create archive";
82   return ret;
83 }
84 
archive_write_disk_set_options(archive * ext,int flags)85 int archive_write_disk_set_options(archive* ext, int flags) {
86   sapi::v::RemotePtr ext_ptr(ext);
87 
88   return api->archive_write_disk_set_options(&ext_ptr, flags).value();
89 }
90 
archive_read_support_filter_bzip2(archive * a)91 int archive_read_support_filter_bzip2(archive* a) {
92   sapi::v::RemotePtr a_ptr(a);
93   return api->archive_read_support_filter_bzip2(&a_ptr).value();
94 }
95 
archive_read_support_filter_gzip(archive * a)96 int archive_read_support_filter_gzip(archive* a) {
97   sapi::v::RemotePtr a_ptr(a);
98   return api->archive_read_support_filter_gzip(&a_ptr).value();
99 }
100 
archive_read_support_filter_compress(archive * a)101 int archive_read_support_filter_compress(archive* a) {
102   sapi::v::RemotePtr a_ptr(a);
103   return api->archive_read_support_filter_compress(&a_ptr).value();
104 }
archive_read_support_format_tar(archive * a)105 int archive_read_support_format_tar(archive* a) {
106   sapi::v::RemotePtr a_ptr(a);
107   return api->archive_read_support_format_tar(&a_ptr).value();
108 }
109 
archive_read_support_format_cpio(archive * a)110 int archive_read_support_format_cpio(archive* a) {
111   sapi::v::RemotePtr a_ptr(a);
112   return api->archive_read_support_format_cpio(&a_ptr).value();
113 }
114 
archive_write_disk_set_standard_lookup(archive * ext)115 int archive_write_disk_set_standard_lookup(archive* ext) {
116   sapi::v::RemotePtr ext_ptr(ext);
117 
118   return api->archive_write_disk_set_standard_lookup(&ext_ptr).value();
119 }
120 
archive_read_open_filename(archive * a,const char * _filename,size_t _block_size)121 int archive_read_open_filename(archive* a, const char* _filename,
122                                size_t _block_size) {
123   sapi::v::RemotePtr a_ptr(a);
124 
125   return api
126       ->archive_read_open_filename(
127           &a_ptr, sapi::v::ConstCStr(_filename).PtrBefore(), _block_size)
128       .value();
129 }
130 
archive_read_next_header(archive * a,archive_entry ** entry)131 int archive_read_next_header(archive* a, archive_entry** entry) {
132   sapi::v::IntBase<archive_entry*> entry_ptr_tmp(0);
133   sapi::v::RemotePtr a_ptr(a);
134   int rc =
135       api->archive_read_next_header(&a_ptr, entry_ptr_tmp.PtrAfter()).value();
136   *entry = entry_ptr_tmp.GetValue();
137   return rc;
138 }
139 
140 // In the following two functions we need to transfer a string from the
141 // sandboxed process to the client process. However, this string would
142 // go out of scope after this function so we use a global char * to make
143 // sure it does not get automatically deleted before it is used.
archive_error_string(archive * a)144 const char* archive_error_string(archive* a) {
145   sapi::v::RemotePtr a_ptr(a);
146   char* str = api->archive_error_string(&a_ptr).value();
147   CHECK(str != nullptr) << "Could not get error message";
148 
149   std::string str_tmp =
150       sandbox_extract->GetCString(sapi::v::RemotePtr(str)).value();
151 
152   if (c_str_tmp != nullptr) {
153     delete[] c_str_tmp;
154   }
155 
156   c_str_tmp = new char[str_tmp.length() + 1];
157   strcpy(c_str_tmp, str_tmp.c_str());  // NOLINT(runtime/printf)
158 
159   return c_str_tmp;
160 }
161 
archive_entry_pathname(archive_entry * entry)162 const char* archive_entry_pathname(archive_entry* entry) {
163   sapi::v::RemotePtr entry_ptr(entry);
164   char* str = api->archive_entry_pathname(&entry_ptr).value();
165   CHECK(str != nullptr) << "Could not get pathname";
166 
167   std::string str_tmp =
168       sandbox_extract->GetCString(sapi::v::RemotePtr(str)).value();
169 
170   if (c_str_tmp != nullptr) {
171     delete[] c_str_tmp;
172   }
173 
174   c_str_tmp = new char[str_tmp.length() + 1];
175   strcpy(c_str_tmp, str_tmp.c_str());  // NOLINT(runtime/printf)
176 
177   return c_str_tmp;
178 }
179 
archive_read_close(archive * a)180 int archive_read_close(archive* a) {
181   sapi::v::RemotePtr a_ptr(a);
182   return api->archive_read_close(&a_ptr).value();
183 }
184 
archive_read_free(archive * a)185 int archive_read_free(archive* a) {
186   sapi::v::RemotePtr a_ptr(a);
187   return api->archive_read_free(&a_ptr).value();
188 }
189 
archive_write_close(archive * a)190 int archive_write_close(archive* a) {
191   sapi::v::RemotePtr a_ptr(a);
192   return api->archive_write_close(&a_ptr).value();
193 }
194 
archive_write_free(archive * a)195 int archive_write_free(archive* a) {
196   sapi::v::RemotePtr a_ptr(a);
197   return api->archive_write_free(&a_ptr).value();
198 }
199 
archive_write_header(archive * a,archive_entry * entry)200 int archive_write_header(archive* a, archive_entry* entry) {
201   sapi::v::RemotePtr a_ptr(a), entry_ptr(entry);
202   return api->archive_write_header(&a_ptr, &entry_ptr).value();
203 }
204 
archive_read_data_block(archive * a,const void ** buff,size_t * size,la_int64_t * offset)205 int archive_read_data_block(archive* a, const void** buff, size_t* size,
206                             la_int64_t* offset) {
207   sapi::v::IntBase<archive_entry*> buff_ptr_tmp(0);
208   sapi::v::ULLong size_tmp;
209   sapi::v::SLLong offset_tmp;
210   sapi::v::RemotePtr a_ptr(a);
211 
212   int rv =
213       api->archive_read_data_block(&a_ptr, buff_ptr_tmp.PtrAfter(),
214                                    size_tmp.PtrAfter(), offset_tmp.PtrAfter())
215           .value();
216   *buff = buff_ptr_tmp.GetValue();
217   *size = size_tmp.GetValue();
218   *offset = offset_tmp.GetValue();
219 
220   return rv;
221 }
222 
archive_write_data_block(archive * a,const void * buff,size_t s,la_int64_t o)223 la_ssize_t archive_write_data_block(archive* a, const void* buff, size_t s,
224                                     la_int64_t o) {
225   sapi::v::RemotePtr buff_ptr((void*)(buff));
226   sapi::v::RemotePtr a_ptr(a);
227 
228   return api->archive_write_data_block(&a_ptr, &buff_ptr, s, o).value();
229 }
230