Skip to content

Commit 9275e14

Browse files
authored
Merge commit from fork
Check the total number of files, self-referential entries and excessively-deep directory structures. Signed-off-by: Tu Dinh <contact@tudinh.xyz>
1 parent e93c656 commit 9275e14

File tree

1 file changed

+70
-5
lines changed

1 file changed

+70
-5
lines changed

NanaZip.Codecs/NanaZip.Codecs.Archive.Romfs.cpp

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include "NanaZip.Codecs.SevenZipWrapper.h"
1414

1515
#include <map>
16+
#include <unordered_set>
17+
#include <deque>
1618

1719
#include "Mile.Helpers.Portable.Base.Unstaged.h"
1820

@@ -56,6 +58,11 @@ namespace
5658
// ROMFS cases.
5759
const std::size_t g_RomfsMaximumPathLength = MAX_PATH;
5860

61+
// Limit resource consumption.
62+
const std::size_t g_RomfsMaximumEntries = 10000;
63+
// Protect against excessively-deep directory structures.
64+
const std::size_t g_RomfsMaximumVisitDepth = 1000;
65+
5966
struct RomfsHeader
6067
{
6168
// The ASCII representation of those bytes (i.e. "-rom1fs-")
@@ -123,6 +130,12 @@ namespace NanaZip::Codecs::Archive
123130
IInStream* m_FileStream = nullptr;
124131
std::uint32_t m_FullSize = 0;
125132
std::string m_VolumeName;
133+
134+
// For GetAllPaths.
135+
std::deque<std::pair<std::uint32_t, std::string>> m_VisitQueue;
136+
// Protect against recursive structures.
137+
std::unordered_set<std::uint32_t> m_VisitedOffsets;
138+
126139
std::map<std::string, RomfsFilePathInformation> m_TemporaryFilePaths;
127140
std::vector<RomfsFilePathInformation> m_FilePaths;
128141
bool m_IsInitialized = false;
@@ -176,15 +189,28 @@ namespace NanaZip::Codecs::Archive
176189

177190
private:
178191

179-
void GetAllPaths(
192+
HRESULT GetOnePath(
180193
std::uint32_t Offset,
181-
std::string const& RootPath)
194+
std::string const& Path)
182195
{
183196
while (Offset)
184197
{
185198
RomfsFilePathInformation Information;
186199
Information.Inode = Offset;
187200

201+
if (m_VisitedOffsets.size() >= g_RomfsMaximumEntries)
202+
{
203+
// Too many files, softly bail out.
204+
return S_OK;
205+
}
206+
207+
auto [Iterator, Inserted] = m_VisitedOffsets.insert(Offset);
208+
if (!Inserted)
209+
{
210+
// We have visited recursively. Bail out.
211+
return HRESULT_FROM_WIN32(ERROR_FILE_CORRUPT);
212+
}
213+
188214
std::uint8_t FileHeaderBuffer[
189215
offsetof(RomfsFileHeader, FileName)] = {};
190216
if (FAILED(this->ReadFileStream(
@@ -225,11 +251,21 @@ namespace NanaZip::Codecs::Archive
225251
if ("." != FileName && ".." != FileName)
226252
{
227253
Information.Offset = Offset;
228-
Information.Path = RootPath + FileName;
254+
Information.Path = Path + FileName;
229255

230256
if (RomfsFileType::Directory == Information.Type)
231257
{
232-
this->GetAllPaths(Offset, Information.Path + "/");
258+
if (m_VisitQueue.size() < g_RomfsMaximumVisitDepth)
259+
{
260+
m_VisitQueue.emplace_back(
261+
Offset,
262+
Information.Path + "/");
263+
}
264+
else
265+
{
266+
// Exceeded our internal limit, bail out.
267+
return HRESULT_FROM_WIN32(ERROR_FILE_CORRUPT);
268+
}
233269
}
234270
else if (RomfsFileType::HardLink == Information.Type)
235271
{
@@ -244,6 +280,31 @@ namespace NanaZip::Codecs::Archive
244280

245281
Offset = NextOffset;
246282
}
283+
284+
return S_OK;
285+
}
286+
287+
HRESULT GetAllPaths(std::uint32_t RootOffset)
288+
{
289+
m_VisitQueue.clear();
290+
m_VisitedOffsets.clear();
291+
m_VisitQueue.emplace_back(RootOffset, "");
292+
293+
while (!m_VisitQueue.empty())
294+
{
295+
HRESULT Result;
296+
297+
// Get the entry out before visiting.
298+
auto [Offset, Path] = std::move(m_VisitQueue.front());
299+
m_VisitQueue.pop_front();
300+
Result = this->GetOnePath(Offset, Path);
301+
if (S_OK != Result)
302+
{
303+
return Result;
304+
}
305+
}
306+
307+
return S_OK;
247308
}
248309

249310
public:
@@ -342,7 +403,11 @@ namespace NanaZip::Codecs::Archive
342403
OpenCallback->SetTotal(&TotalFiles, &TotalBytes);
343404
}
344405

345-
this->GetAllPaths(Offset, "");
406+
hr = this->GetAllPaths(Offset);
407+
if (FAILED(hr))
408+
{
409+
break;
410+
}
346411

347412
TotalFiles = this->m_TemporaryFilePaths.size();
348413
if (OpenCallback)

0 commit comments

Comments
 (0)