1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *    http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // Read-only stream access to Zip Archive entries.
18 #include <errno.h>
19 #include <inttypes.h>
20 #include <string.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 
24 #include <memory>
25 #include <vector>
26 
27 #define LOG_TAG "ZIPARCHIVE"
28 #include <android-base/file.h>
29 #include <log/log.h>
30 #include <ziparchive/zip_archive.h>
31 #include <ziparchive/zip_archive_stream_entry.h>
32 #include <zlib.h>
33 
34 #include "zip_archive_private.h"
35 
36 static constexpr size_t kBufSize = 65535;
37 
Init(const ZipEntry & entry)38 bool ZipArchiveStreamEntry::Init(const ZipEntry& entry) {
39   ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
40   off64_t data_offset = entry.offset;
41   if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
42     ALOGW("lseek to data at %" PRId64 " failed: %s", data_offset, strerror(errno));
43     return false;
44   }
45   crc32_ = entry.crc32;
46   return true;
47 }
48 
49 class ZipArchiveStreamEntryUncompressed : public ZipArchiveStreamEntry {
50  public:
ZipArchiveStreamEntryUncompressed(ZipArchiveHandle handle)51   ZipArchiveStreamEntryUncompressed(ZipArchiveHandle handle) : ZipArchiveStreamEntry(handle) {}
~ZipArchiveStreamEntryUncompressed()52   virtual ~ZipArchiveStreamEntryUncompressed() {}
53 
54   const std::vector<uint8_t>* Read() override;
55 
56   bool Verify() override;
57 
58  protected:
59   bool Init(const ZipEntry& entry) override;
60 
61   uint32_t length_;
62 
63  private:
64   std::vector<uint8_t> data_;
65   uint32_t computed_crc32_;
66 };
67 
Init(const ZipEntry & entry)68 bool ZipArchiveStreamEntryUncompressed::Init(const ZipEntry& entry) {
69   if (!ZipArchiveStreamEntry::Init(entry)) {
70     return false;
71   }
72 
73   length_ = entry.uncompressed_length;
74 
75   data_.resize(kBufSize);
76   computed_crc32_ = 0;
77 
78   return true;
79 }
80 
Read()81 const std::vector<uint8_t>* ZipArchiveStreamEntryUncompressed::Read() {
82   if (length_ == 0) {
83     return nullptr;
84   }
85 
86   size_t bytes = (length_ > data_.size()) ? data_.size() : length_;
87   ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
88   errno = 0;
89   if (!android::base::ReadFully(archive->fd, data_.data(), bytes)) {
90     if (errno != 0) {
91       ALOGE("Error reading from archive fd: %s", strerror(errno));
92     } else {
93       ALOGE("Short read of zip file, possibly corrupted zip?");
94     }
95     length_ = 0;
96     return nullptr;
97   }
98 
99   if (bytes < data_.size()) {
100     data_.resize(bytes);
101   }
102   computed_crc32_ = crc32(computed_crc32_, data_.data(), data_.size());
103   length_ -= bytes;
104   return &data_;
105 }
106 
Verify()107 bool ZipArchiveStreamEntryUncompressed::Verify() {
108   return length_ == 0 && crc32_ == computed_crc32_;
109 }
110 
111 class ZipArchiveStreamEntryCompressed : public ZipArchiveStreamEntry {
112  public:
ZipArchiveStreamEntryCompressed(ZipArchiveHandle handle)113   ZipArchiveStreamEntryCompressed(ZipArchiveHandle handle) : ZipArchiveStreamEntry(handle) {}
114   virtual ~ZipArchiveStreamEntryCompressed();
115 
116   const std::vector<uint8_t>* Read() override;
117 
118   bool Verify() override;
119 
120  protected:
121   bool Init(const ZipEntry& entry) override;
122 
123  private:
124   bool z_stream_init_ = false;
125   z_stream z_stream_;
126   std::vector<uint8_t> in_;
127   std::vector<uint8_t> out_;
128   uint32_t uncompressed_length_;
129   uint32_t compressed_length_;
130   uint32_t computed_crc32_;
131 };
132 
133 // This method is using libz macros with old-style-casts
134 #pragma GCC diagnostic push
135 #pragma GCC diagnostic ignored "-Wold-style-cast"
zlib_inflateInit2(z_stream * stream,int window_bits)136 static inline int zlib_inflateInit2(z_stream* stream, int window_bits) {
137   return inflateInit2(stream, window_bits);
138 }
139 #pragma GCC diagnostic pop
140 
Init(const ZipEntry & entry)141 bool ZipArchiveStreamEntryCompressed::Init(const ZipEntry& entry) {
142   if (!ZipArchiveStreamEntry::Init(entry)) {
143     return false;
144   }
145 
146   // Initialize the zlib stream struct.
147   memset(&z_stream_, 0, sizeof(z_stream_));
148   z_stream_.zalloc = Z_NULL;
149   z_stream_.zfree = Z_NULL;
150   z_stream_.opaque = Z_NULL;
151   z_stream_.next_in = nullptr;
152   z_stream_.avail_in = 0;
153   z_stream_.avail_out = 0;
154   z_stream_.data_type = Z_UNKNOWN;
155 
156   // Use the undocumented "negative window bits" feature to tell zlib
157   // that there's no zlib header waiting for it.
158   int zerr = zlib_inflateInit2(&z_stream_, -MAX_WBITS);
159   if (zerr != Z_OK) {
160     if (zerr == Z_VERSION_ERROR) {
161       ALOGE("Installed zlib is not compatible with linked version (%s)",
162         ZLIB_VERSION);
163     } else {
164       ALOGE("Call to inflateInit2 failed (zerr=%d)", zerr);
165     }
166 
167     return false;
168   }
169 
170   z_stream_init_ = true;
171 
172   uncompressed_length_ = entry.uncompressed_length;
173   compressed_length_ = entry.compressed_length;
174 
175   out_.resize(kBufSize);
176   in_.resize(kBufSize);
177 
178   computed_crc32_ = 0;
179 
180   return true;
181 }
182 
~ZipArchiveStreamEntryCompressed()183 ZipArchiveStreamEntryCompressed::~ZipArchiveStreamEntryCompressed() {
184   if (z_stream_init_) {
185     inflateEnd(&z_stream_);
186     z_stream_init_ = false;
187   }
188 }
189 
Verify()190 bool ZipArchiveStreamEntryCompressed::Verify() {
191   return z_stream_init_ && uncompressed_length_ == 0 && compressed_length_ == 0 &&
192       crc32_ == computed_crc32_;
193 }
194 
Read()195 const std::vector<uint8_t>* ZipArchiveStreamEntryCompressed::Read() {
196   if (z_stream_.avail_out == 0) {
197     z_stream_.next_out = out_.data();
198     z_stream_.avail_out = out_.size();;
199   }
200 
201   while (true) {
202     if (z_stream_.avail_in == 0) {
203       if (compressed_length_ == 0) {
204         return nullptr;
205       }
206       size_t bytes = (compressed_length_ > in_.size()) ? in_.size() : compressed_length_;
207       ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
208       errno = 0;
209       if (!android::base::ReadFully(archive->fd, in_.data(), bytes)) {
210         if (errno != 0) {
211           ALOGE("Error reading from archive fd: %s", strerror(errno));
212         } else {
213           ALOGE("Short read of zip file, possibly corrupted zip?");
214         }
215         return nullptr;
216       }
217 
218       compressed_length_ -= bytes;
219       z_stream_.next_in = in_.data();
220       z_stream_.avail_in = bytes;
221     }
222 
223     int zerr = inflate(&z_stream_, Z_NO_FLUSH);
224     if (zerr != Z_OK && zerr != Z_STREAM_END) {
225       ALOGE("inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)",
226           zerr, z_stream_.next_in, z_stream_.avail_in,
227           z_stream_.next_out, z_stream_.avail_out);
228       return nullptr;
229     }
230 
231     if (z_stream_.avail_out == 0) {
232       uncompressed_length_ -= out_.size();
233       computed_crc32_ = crc32(computed_crc32_, out_.data(), out_.size());
234       return &out_;
235     }
236     if (zerr == Z_STREAM_END) {
237       if (z_stream_.avail_out != 0) {
238         // Resize the vector down to the actual size of the data.
239         out_.resize(out_.size() - z_stream_.avail_out);
240         computed_crc32_ = crc32(computed_crc32_, out_.data(), out_.size());
241         uncompressed_length_ -= out_.size();
242         return &out_;
243       }
244       return nullptr;
245     }
246   }
247   return nullptr;
248 }
249 
250 class ZipArchiveStreamEntryRawCompressed : public ZipArchiveStreamEntryUncompressed {
251  public:
ZipArchiveStreamEntryRawCompressed(ZipArchiveHandle handle)252   ZipArchiveStreamEntryRawCompressed(ZipArchiveHandle handle)
253       : ZipArchiveStreamEntryUncompressed(handle) {}
~ZipArchiveStreamEntryRawCompressed()254   virtual ~ZipArchiveStreamEntryRawCompressed() {}
255 
256   bool Verify() override;
257 
258  protected:
259   bool Init(const ZipEntry& entry) override;
260 };
261 
Init(const ZipEntry & entry)262 bool ZipArchiveStreamEntryRawCompressed::Init(const ZipEntry& entry) {
263   if (!ZipArchiveStreamEntryUncompressed::Init(entry)) {
264     return false;
265   }
266   length_ = entry.compressed_length;
267 
268   return true;
269 }
270 
Verify()271 bool ZipArchiveStreamEntryRawCompressed::Verify() {
272   return length_ == 0;
273 }
274 
Create(ZipArchiveHandle handle,const ZipEntry & entry)275 ZipArchiveStreamEntry* ZipArchiveStreamEntry::Create(
276     ZipArchiveHandle handle, const ZipEntry& entry) {
277   ZipArchiveStreamEntry* stream = nullptr;
278   if (entry.method != kCompressStored) {
279     stream = new ZipArchiveStreamEntryCompressed(handle);
280   } else {
281     stream = new ZipArchiveStreamEntryUncompressed(handle);
282   }
283   if (stream && !stream->Init(entry)) {
284     delete stream;
285     stream = nullptr;
286   }
287 
288   return stream;
289 }
290 
CreateRaw(ZipArchiveHandle handle,const ZipEntry & entry)291 ZipArchiveStreamEntry* ZipArchiveStreamEntry::CreateRaw(
292     ZipArchiveHandle handle, const ZipEntry& entry) {
293   ZipArchiveStreamEntry* stream = nullptr;
294   if (entry.method == kCompressStored) {
295     // Not compressed, don't need to do anything special.
296     stream = new ZipArchiveStreamEntryUncompressed(handle);
297   } else {
298     stream = new ZipArchiveStreamEntryRawCompressed(handle);
299   }
300   if (stream && !stream->Init(entry)) {
301     delete stream;
302     stream = nullptr;
303   }
304   return stream;
305 }
306