mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-27 02:41:17 +00:00
Confine config import to the preset directory (#15608)
import_presets reduced each zip entry to a basename by stripping only '/', so on Windows an entry named with '\' separators kept its directory components and was extracted wherever they pointed. Strip both separators, and reject any entry whose name still escapes the extraction folder. The preset name from the JSON and the bundle id from bundle_structure.json were joined onto the preset directory unchecked as well, which let either of them write outside it on every platform. Both are now validated before anything is written. The check is the is_path_within_root helper the 3MF importer already had, moved to Utils so both importers share it. It treats '/' and '\' as separators on every platform, so a bundle that would escape on one OS is rejected on all of them.
This commit is contained in:
@@ -102,45 +102,6 @@ struct ZipUnicodePathExtraField
|
||||
}
|
||||
};
|
||||
|
||||
// Validate that a relative file path does not escape the root directory via path traversal.
|
||||
static bool is_path_within_root(const std::string& file_path, const boost::filesystem::path& root)
|
||||
{
|
||||
if (file_path.empty())
|
||||
return false;
|
||||
|
||||
boost::filesystem::path p(file_path);
|
||||
if (p.is_absolute())
|
||||
return false;
|
||||
|
||||
// Reject any path component that is ".."
|
||||
for (const auto& component : p) {
|
||||
if (component == "..")
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve the full path and verify it starts with the canonical root (also catches symlink escapes)
|
||||
try {
|
||||
boost::filesystem::path full_path = root / p;
|
||||
boost::filesystem::path canonical_root = boost::filesystem::weakly_canonical(root);
|
||||
boost::filesystem::path canonical_full = boost::filesystem::weakly_canonical(full_path);
|
||||
|
||||
auto root_str = canonical_root.string();
|
||||
auto full_str = canonical_full.string();
|
||||
if (full_str.length() < root_str.length())
|
||||
return false;
|
||||
if (full_str.compare(0, root_str.length(), root_str) != 0)
|
||||
return false;
|
||||
// Ensure it's a proper prefix (not just a substring of a longer directory name)
|
||||
if (full_str.length() > root_str.length() &&
|
||||
full_str[root_str.length()] != boost::filesystem::path::preferred_separator)
|
||||
return false;
|
||||
} catch (const boost::filesystem::filesystem_error&) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// VERSION NUMBERS
|
||||
// 0 : .3mf, files saved by older slic3r or other applications. No version definition in them.
|
||||
// 1 : Introduction of 3mf versioning. No other change in data saved into 3mf files.
|
||||
|
||||
Reference in New Issue
Block a user