1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
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  *     http://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 
16 #include "dlp_zip.h"
17 
18 #include <cstdlib>
19 #include <cstdio>
20 #include <fcntl.h>
21 #include <memory>
22 #include <set>
23 #include <string>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 #include "dlp_permission_log.h"
28 
29 #include "securec.h"
30 
31 namespace OHOS {
32 namespace Security {
33 namespace DlpPermission {
34 using Defer = std::shared_ptr<void>;
35 namespace {
36 static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, SECURITY_DOMAIN_DLP_PERMISSION, "DlpFileZip"};
37 const uint32_t ZIP_BUFF_SIZE = 1024;
38 const int32_t DLP_ZIP_FAIL = -1;
39 const int32_t DLP_ZIP_OK = 0;
40 const int32_t FILE_COUNT = 3;
41 const int32_t MAX_PATH = 30;
42 const std::string DLP_GENERAL_INFO = "dlp_general_info";
43 const std::set<std::string> FILE_NAME_SET = {"dlp_cert", "dlp_general_info", "encrypted_data"};
44 }
45 
AddBuffToZip(const void * buf,uint32_t size,const char * nameInZip,const char * zipName)46 int32_t AddBuffToZip(const void *buf, uint32_t size, const char *nameInZip, const char *zipName)
47 {
48     if (buf == nullptr || zipName == nullptr) {
49         DLP_LOG_ERROR(LABEL, "Buff or zipName is nullptr.");
50         return DLP_ZIP_FAIL;
51     }
52     zipFile zf = zipOpen64(zipName, APPEND_STATUS_ADDINZIP);
53     if (zf == nullptr) {
54         DLP_LOG_ERROR(LABEL, "AddBuffToZip fail err %{public}d, zipName %{public}s",
55             errno, zipName);
56         return DLP_ZIP_FAIL;
57     }
58     int compressLevel = 0;
59     zip_fileinfo zi = {};
60 
61     int32_t err = zipOpenNewFileInZip3_64(zf, nameInZip, &zi,
62         NULL, 0, NULL, 0, NULL /* comment */,
63         (compressLevel != 0) ? Z_DEFLATED : 0,
64         compressLevel, 0,
65         /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */
66         -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
67         NULL, 0, 0);
68     if (err != ZIP_OK) {
69         DLP_LOG_ERROR(LABEL, "AddBuffToZip fail err %{public}d, nameInZip %{public}s", err, nameInZip);
70         (void)zipClose(zf, NULL);
71         return DLP_ZIP_FAIL;
72     }
73     int32_t res = DLP_ZIP_OK;
74     err = zipWriteInFileInZip (zf, buf, (unsigned)size);
75     if (err != ZIP_OK) {
76         DLP_LOG_ERROR(LABEL, "zipWriteInFileInZip fail err %{public}d, %{public}s", err, nameInZip);
77         res = DLP_ZIP_FAIL;
78     }
79 
80     if (zipCloseFileInZip(zf) != ZIP_OK) {
81         DLP_LOG_ERROR(LABEL, "zipCloseFileInZip fail nameInZip %{public}s", nameInZip);
82         res = DLP_ZIP_FAIL;
83     }
84 
85     if (zipClose(zf, NULL) != ZIP_OK) {
86         DLP_LOG_ERROR(LABEL, "zipClose fail nameInZip %{public}s", nameInZip);
87         return DLP_ZIP_FAIL;
88     }
89 
90     return res;
91 }
92 
AddFileContextToZip(int32_t fd,const char * nameInZip,const char * zipName)93 int32_t AddFileContextToZip(int32_t fd, const char *nameInZip, const char *zipName)
94 {
95     zipFile zf = zipOpen64(zipName, APPEND_STATUS_ADDINZIP);
96     if (zf == nullptr) {
97         DLP_LOG_ERROR(LABEL, "AddFileContextToZip fail err %{public}d, zipName %{public}s",
98             errno, zipName);
99         return DLP_ZIP_FAIL;
100     }
101     int32_t compressLevel = 0;
102     zip_fileinfo zi = {};
103 
104     int32_t err = zipOpenNewFileInZip3_64(zf, nameInZip, &zi,
105         NULL, 0, NULL, 0, NULL /* comment */,
106         (compressLevel != 0) ? Z_DEFLATED : 0,
107         compressLevel, 0,
108         /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */
109         -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
110         NULL, 0, 0);
111     if (err != ZIP_OK) {
112         DLP_LOG_ERROR(LABEL, "create zip file fail err %{public}d, nameInZip %{public}s", err, nameInZip);
113         zipClose(zf, NULL);
114         return DLP_ZIP_FAIL;
115     }
116     int32_t readLen;
117     int32_t res = DLP_ZIP_OK;
118     auto buf = std::make_unique<char[]>(ZIP_BUFF_SIZE);
119     while ((readLen = read(fd, buf.get(), ZIP_BUFF_SIZE)) > 0) {
120         err = zipWriteInFileInZip (zf, buf.get(), (unsigned)readLen);
121         if (err != ZIP_OK) {
122             DLP_LOG_ERROR(LABEL, "zipWriteInFileInZip fail err %{public}d, %{public}s", err, nameInZip);
123             res = DLP_ZIP_FAIL;
124             break;
125         }
126     }
127 
128     if (readLen == -1) {
129         DLP_LOG_ERROR(LABEL, "read errno %{public}s", strerror(errno));
130         res = DLP_ZIP_FAIL;
131     }
132 
133     if (zipCloseFileInZip(zf) != ZIP_OK) {
134         DLP_LOG_ERROR(LABEL, "zipCloseFileInZip fail nameInZip %{public}s", nameInZip);
135         res = DLP_ZIP_FAIL;
136     }
137 
138     if (zipClose(zf, NULL) != ZIP_OK) {
139         DLP_LOG_ERROR(LABEL, "zipClose fail nameInZip %{public}s", nameInZip);
140         return DLP_ZIP_FAIL;
141     }
142 
143     return res;
144 }
145 
FdOpenFileFunc(void * opaque,const char * filename,int mode)146 static void *FdOpenFileFunc(void *opaque, const char *filename, int mode)
147 {
148     if ((opaque == nullptr) || (filename == nullptr)) {
149         return nullptr;
150     }
151     FILE *file = nullptr;
152     const char *modeFopen = nullptr;
153     uint32_t modeInner = static_cast<uint32_t>(mode);
154     if ((modeInner & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) {
155         modeFopen = "rb";
156     } else if (modeInner & ZLIB_FILEFUNC_MODE_EXISTING) {
157         modeFopen = "r+b";
158     } else if (modeInner & ZLIB_FILEFUNC_MODE_CREATE) {
159         modeFopen = "wb";
160     }
161     if (modeFopen != nullptr) {
162         int fd = dup(*static_cast<int *>(opaque));
163         if (fd != -1) {
164             file = fdopen(fd, modeFopen);
165         }
166     }
167 
168     return file;
169 }
170 
FdCloseFileFunc(void * opaque,void * stream)171 static int FdCloseFileFunc(void *opaque, void *stream)
172 {
173     if (fclose(static_cast<FILE *>(stream)) != 0) {
174         DLP_LOG_ERROR(LABEL, "fclose fail errno %{public}d", errno);
175     }
176     free(opaque);  // malloc'ed in FillFdOpenFileFunc()
177     return 0;
178 }
179 
FillFdOpenFileFunc(zlib_filefunc_def * pzlibFilefuncDef,int fd)180 static void FillFdOpenFileFunc(zlib_filefunc_def *pzlibFilefuncDef, int fd)
181 {
182     if (pzlibFilefuncDef == nullptr) {
183         return;
184     }
185     fill_fopen_filefunc(pzlibFilefuncDef);
186     pzlibFilefuncDef->zopen_file = FdOpenFileFunc;
187     pzlibFilefuncDef->zclose_file = FdCloseFileFunc;
188     int *ptrFd = static_cast<int *>(malloc(sizeof(fd)));
189     if (ptrFd == nullptr) {
190         return;
191     }
192     *ptrFd = fd;
193     pzlibFilefuncDef->opaque = ptrFd;
194 }
195 
OpenFdForUnzipping(int zipFD)196 static unzFile OpenFdForUnzipping(int zipFD)
197 {
198     zlib_filefunc_def zipFuncs;
199     FillFdOpenFileFunc(&zipFuncs, zipFD);
200     return unzOpen2("fd", &zipFuncs);
201 }
202 
OpenZipFile(int fd)203 static zipFile OpenZipFile(int fd)
204 {
205     zipFile uf = OpenFdForUnzipping(fd);
206     if (uf == nullptr) {
207         DLP_LOG_ERROR(LABEL, "unzOpenFile fail errno %{public}d", errno);
208         return nullptr;
209     }
210     return uf;
211 }
212 
CheckUnzipFileInfo(int32_t fd)213 bool CheckUnzipFileInfo(int32_t fd)
214 {
215     zipFile uf = OpenZipFile(fd);
216     if (uf == nullptr) {
217         DLP_LOG_ERROR(LABEL, "OpenZipFile fail errno %{public}d", errno);
218         return false;
219     }
220     unz_global_info64 globalnfo;
221     int res = unzGetGlobalInfo64(uf, &globalnfo);
222     if (res != UNZ_OK) {
223         DLP_LOG_ERROR(LABEL, "Call unzGetGloabalInfo64 fail res=%{public}d errno=%{public}d", res, errno);
224         (void)unzClose(uf);
225         return false;
226     }
227     //The number of files is equal to 3
228     if (globalnfo.number_entry != FILE_COUNT) {
229         DLP_LOG_ERROR(LABEL, "File count=%{public}llu", globalnfo.number_entry);
230         (void)unzClose(uf);
231         return false;
232     }
233     unz_file_info64 fileInfo;
234     char fileName[MAX_PATH + 1] = {0};
235     for (int32_t i = 0; i < FILE_COUNT; i++) {
236         res = unzGetCurrentFileInfo64(uf, &fileInfo, fileName, MAX_PATH, nullptr, 0, nullptr, 0);
237         if (res != UNZ_OK) {
238             DLP_LOG_ERROR(LABEL, "Call unzGetCurrentFileInfo64 fail res=%{public}d errno=%{public}d", res, errno);
239             (void)unzClose(uf);
240             return false;
241         }
242         fileName[MAX_PATH] = '\0';
243         //The file name has not been changed
244         auto it = FILE_NAME_SET.find(fileName);
245         if (it == FILE_NAME_SET.end()) {
246             DLP_LOG_ERROR(LABEL, "FileName=%{public}s do not found", fileName);
247             (void)unzClose(uf);
248             return false;
249         }
250         //The file has not been compressed
251         if (fileInfo.compressed_size < fileInfo.uncompressed_size) {
252             DLP_LOG_ERROR(LABEL, "Compressed_size=%{public}llu is less uncompress_size=%{public}llu",
253                 fileInfo.compressed_size, fileInfo.uncompressed_size);
254             (void)unzClose(uf);
255             return false;
256         }
257         unzGoToNextFile(uf);
258     }
259     (void)unzClose(uf);
260     return true;
261 }
262 
UnzipSpecificFile(int32_t fd,const char * nameInZip,const char * unZipName)263 int32_t UnzipSpecificFile(int32_t fd, const char*nameInZip, const char *unZipName)
264 {
265     zipFile uf;
266     int32_t outFd = open(unZipName, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
267     if (outFd == -1) {
268         DLP_LOG_ERROR(LABEL, "open fail %{public}s errno %{public}d", unZipName, errno);
269         return DLP_ZIP_FAIL;
270     }
271     Defer p(nullptr, [&](...) {
272         close(outFd);
273     });
274 
275     uf = OpenZipFile(fd);
276     if (uf == nullptr) {
277         return DLP_ZIP_FAIL;
278     }
279 
280     if (unzLocateFile(uf, nameInZip, 0) != UNZ_OK) {
281         DLP_LOG_ERROR(LABEL, "unzLocateFile fail %{public}s errno %{public}d", nameInZip, errno);
282         (void)unzClose(uf);
283         return DLP_ZIP_FAIL;
284     }
285 
286     int32_t err = unzOpenCurrentFile(uf);
287     if (err != UNZ_OK) {
288         DLP_LOG_ERROR(LABEL, "unzOpenCurrentFile fail %{public}s errno %{public}d", nameInZip, err);
289         (void)unzClose(uf);
290         return DLP_ZIP_FAIL;
291     }
292 
293     int32_t readSize = 0;
294     auto buf = std::make_unique<char[]>(ZIP_BUFF_SIZE);
295     do {
296         readSize = unzReadCurrentFile(uf, buf.get(), ZIP_BUFF_SIZE);
297         int32_t writeSize = write(outFd, buf.get(), readSize);
298         if (writeSize != readSize) {
299             err = DLP_ZIP_FAIL;
300             DLP_LOG_ERROR(LABEL, "write zip fail %{public}s errno %{public}d write %{public}d read %{public}d",
301                 nameInZip, errno, writeSize, readSize);
302             break;
303         }
304     } while (readSize > 0);
305 
306     if (readSize < 0) {
307         DLP_LOG_ERROR(LABEL, "unzReadCurrentFile fail %{public}s errno %{public}d", nameInZip, errno);
308     }
309 
310     if (unzCloseCurrentFile(uf) != ZIP_OK) {
311         DLP_LOG_ERROR(LABEL, "unzCloseCurrentFile fail nameInZip %{public}s", nameInZip);
312     }
313 
314     if (unzClose(uf) != ZIP_OK) {
315         DLP_LOG_ERROR(LABEL, "zipClose fail nameInZip %{public}s", nameInZip);
316         return DLP_ZIP_FAIL;
317     }
318 
319     return err;
320 }
321 
IsZipFile(int32_t fd)322 bool IsZipFile(int32_t fd)
323 {
324     unzFile uz = OpenFdForUnzipping(fd);
325     if (uz == nullptr) {
326         DLP_LOG_ERROR(LABEL, "unzOpenFile fail, %{public}d", errno);
327         return false;
328     }
329 
330     if (unzLocateFile(uz, DLP_GENERAL_INFO.c_str(), 0) != UNZ_OK) {
331         DLP_LOG_ERROR(LABEL, "unzLocateFile fail %{public}s errno %{public}d", DLP_GENERAL_INFO.c_str(), errno);
332         (void)unzClose(uz);
333         return false;
334     }
335 
336     (void)unzClose(uz);
337     return true;
338 }
339 }  // namespace DlpPermission
340 }  // namespace Security
341 }  // namespace OHOS
342