1 /*
2  * Copyright (c) 2024 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 "gotonextfile_fuzzer.h"
17 
18 #include <cstdio>
19 
20 #include "assembler/assembly-emitter.h"
21 #include "assembler/assembly-parser.h"
22 #include "libziparchive/zip_archive.h"
23 #include "libpandafile/file.h"
24 
25 constexpr size_t MAX_BUFFER_SIZE = 2048;
26 constexpr size_t MAX_DIR_SIZE = 64;
27 
28 namespace OHOS {
GenerateZipfile(const char* data, const char* archive_name, int n, char* buf, char* archive_filename, int& i, int& ret, std::vector<uint8_t>& pf_data, int level = Z_BEST_COMPRESSION)29     void GenerateZipfile(const char* data, const char* archive_name, int n, char* buf, char* archive_filename, int& i,
30                          int& ret, std::vector<uint8_t>& pf_data, int level = Z_BEST_COMPRESSION)
31     {
32         // Delete the test archive, so it doesn't keep growing as we run this test
33         (void)remove(archive_name);
34         // Create and append a directory entry for testing
35         ret = panda::CreateOrAddFileIntoZip(archive_name, "directory/", NULL, 0, APPEND_STATUS_CREATE, level);
36         if (ret != 0) {
37             return;
38         }
39         int err = 0;
40         // Append a bunch of text files to the test archive
41         for (i = (n - 1); i >= 0; --i) {
42             err = sprintf_s(archive_filename, MAX_DIR_SIZE, "%d.txt", i);
43             if (err != 0) {
44                 return;
45             }
46             err = sprintf_s(buf, MAX_BUFFER_SIZE, "%d %s %d", (n - 1) - i, data, i);
47             if (err != 0) {
48                 return;
49             }
50             ret = panda::CreateOrAddFileIntoZip(archive_name, archive_filename, buf, strlen(buf) + 1,
51                                                 APPEND_STATUS_ADDINZIP, level);
52             if (ret != 0) {
53                 return;
54             }
55         }
56     }
57 
MakePfData(std::vector<uint8_t>& pf_data)58     int MakePfData(std::vector<uint8_t>& pf_data)
59     {
60         panda::pandasm::Parser p;
61         auto source = R"()";
62         std::string src_filename = "src.pa";
63         auto res = p.Parse(source, src_filename);
64         if (p.ShowError().err != panda::pandasm::Error::ErrorType::ERR_NONE) {
65             return 1;
66         }
67         auto pf = panda::pandasm::AsmEmitter::Emit(res.Value());
68         if (pf == nullptr) {
69             return 1;
70         }
71         const auto header_ptr = reinterpret_cast<const uint8_t *>(pf->GetHeader());
72         pf_data.assign(header_ptr, header_ptr + sizeof(panda::panda_file::File::Header));
73         return 0;
74     }
75 
GoToNextFileFuzzTest(const uint8_t* data, [[maybe_unused]] size_t size)76     void GoToNextFileFuzzTest(const uint8_t* data, [[maybe_unused]] size_t size)
77     {
78         {
79             // handle is nullptr
80             panda::ZipArchiveHandle handle = nullptr;
81             panda::GoToNextFile(handle);
82         }
83 
84         {
85             // handle is not nullptr
86             // creating an empty pandafile
87             const char* s = reinterpret_cast<char*>(const_cast<uint8_t*>(data));
88             std::vector<uint8_t> pf_data {};
89             int err = MakePfData(pf_data);
90             if (err != 0) {
91                 return;
92             }
93             static const char* archive_name = "__LIBZIPARCHIVE__ZipFile__.zip";
94             const int n = 3;
95             char buf[MAX_BUFFER_SIZE];
96             char archive_filename[MAX_DIR_SIZE];
97             int i = 0;
98             int ret = 0;
99             GenerateZipfile(s, archive_name, n, buf, archive_filename, i, ret, pf_data);
100 
101             // Quick Check
102             panda::ZipArchiveHandle zipfile = nullptr;
103             if (panda::OpenArchive(zipfile, archive_name) != 0) {
104                 return;
105             }
106             panda::GlobalStat gi = panda::GlobalStat();
107             if (panda::GetGlobalFileInfo(zipfile, &gi) != 0) {
108                 return;
109             }
110             int entrynum = static_cast<int>(gi.GetNumberOfEntry());
111             for (i = 0; i < entrynum; ++i) {
112                 panda::EntryFileStat file_stat;
113                 if (panda::GetCurrentFileInfo(zipfile, &file_stat) != 0) {
114                     panda::CloseArchive(zipfile);
115                     return;
116                 }
117                 if ((i + 1) < entrynum) {
118                     if (panda::GoToNextFile(zipfile) != 0) {
119                         panda::CloseArchive(zipfile);
120                         return;
121                     }
122                 }
123             }
124             panda::CloseArchive(zipfile);
125             (void)remove(archive_name);
126         }
127     }
128 }
129 
130 /* Fuzzer entry point */
LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)131 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
132 {
133     /* Run your code on data */
134     OHOS::GoToNextFileFuzzTest(data, size);
135     return 0;
136 }