From 3abadcd5071ea1acbc5748deb57f21b03c7c5536 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 30 May 2026 11:26:26 +0200 Subject: [PATCH 1/2] Rework NANDImporter::GetPath slash handling GetPath has two special cases where it doesn't add a slash. The first is for the root entry's special name "/". The next commit will be neater if we can skip calling GetPath for the root entry, because '/' is one of the characters that Common::EscapeFileName replaces with an escape sequence. Let's check for entry number 0 instead. The second is for parent paths that already end in a slash. There's no actual need to check for this - double slashes are harmless, and for comparison, NANDImporter::ExtractCertificates already appends slashes without checking if there already is one. Let's remove this check. --- Source/Core/DiscIO/NANDImporter.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Source/Core/DiscIO/NANDImporter.cpp b/Source/Core/DiscIO/NANDImporter.cpp index f4c94bbb2c..77492fd0f0 100644 --- a/Source/Core/DiscIO/NANDImporter.cpp +++ b/Source/Core/DiscIO/NANDImporter.cpp @@ -134,10 +134,6 @@ bool NANDImporter::ExtractFiles() std::string NANDImporter::GetPath(const NANDFSTEntry& entry, const std::string& parent_path) { std::string name(entry.name, strnlen(entry.name, sizeof(NANDFSTEntry::name))); - - if (name.front() == '/' || parent_path.back() == '/') - return parent_path + name; - return parent_path + '/' + name; } @@ -153,7 +149,7 @@ bool NANDImporter::ProcessEntry(u16 entry_number, const std::string& parent_path const NANDFSTEntry entry = m_superblock->fst[entry_number]; - const std::string path = GetPath(entry, parent_path); + const std::string path = entry_number == 0 ? parent_path : GetPath(entry, parent_path); INFO_LOG_FMT(DISCIO, "Entry: {} Path: {}", entry, path); Type type = static_cast(entry.mode & 3); From 2faa9760d3e689ceb5b92f71e29a4a869b9f50f9 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sat, 30 May 2026 11:28:03 +0200 Subject: [PATCH 2/2] Prevent path traversal in NANDImporter::ProcessEntry Reported by MrSynAckster. A specifically crafted NAND dump could use path traversal to overwrite files on the host file system. This is also an accuracy fix for importing NAND dumps that contain file names that Dolphin is supposed to escape. Some games' save files are affected. --- Source/Core/DiscIO/NANDImporter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/Core/DiscIO/NANDImporter.cpp b/Source/Core/DiscIO/NANDImporter.cpp index 77492fd0f0..4477621984 100644 --- a/Source/Core/DiscIO/NANDImporter.cpp +++ b/Source/Core/DiscIO/NANDImporter.cpp @@ -11,6 +11,7 @@ #include "Common/IOFile.h" #include "Common/Logging/Log.h" #include "Common/MsgHandler.h" +#include "Common/NandPaths.h" #include "Core/IOS/ES/Formats.h" namespace DiscIO @@ -134,7 +135,7 @@ bool NANDImporter::ExtractFiles() std::string NANDImporter::GetPath(const NANDFSTEntry& entry, const std::string& parent_path) { std::string name(entry.name, strnlen(entry.name, sizeof(NANDFSTEntry::name))); - return parent_path + '/' + name; + return parent_path + '/' + Common::EscapeFileName(name); } bool NANDImporter::ProcessEntry(u16 entry_number, const std::string& parent_path)