Tighten RSBK package-format validation for review remediation
Reject NUL/control bytes and Windows-hostile names in entry names, relax the over-broad ".." substring ban to component-only, close the trailing-garbage gap on empty manifests, and relocate the package CMake subdirectory to its ladder home.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
#include "core/package/package_format.h"
|
||||
|
||||
#include <cctype>
|
||||
|
||||
namespace reasampler::package {
|
||||
|
||||
PackageReadability classifyPackageVersion(std::uint32_t formatVersion,
|
||||
@@ -10,13 +12,40 @@ PackageReadability classifyPackageVersion(std::uint32_t formatVersion,
|
||||
return PackageReadability::Readable;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// Windows device names claim the whole entry regardless of extension
|
||||
// (CON, CON.wav, con.WAV are all the same reserved device) — checked against
|
||||
// the portion before the first dot only.
|
||||
bool isDosDeviceName(const std::string& name) {
|
||||
std::string base = name.substr(0, name.find('.'));
|
||||
for (char& c : base) c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
|
||||
static const std::string kReserved[] = {
|
||||
"CON", "PRN", "AUX", "NUL",
|
||||
"COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
|
||||
"LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
|
||||
};
|
||||
for (const auto& r : kReserved) if (base == r) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool isValidEntryName(const std::string& name) {
|
||||
if (name.empty() || name.size() > kMaxEntryNameBytes) return false;
|
||||
if (name == ".") return false;
|
||||
if (name.find("..") != std::string::npos) return false;
|
||||
for (char c : name) {
|
||||
if (name == "." || name == "..") return false;
|
||||
// fopen/CreateFileW both silently strip a trailing dot or space at
|
||||
// creation, so "a.wav " and "a.wav" would collide on one file.
|
||||
if (name.back() == '.' || name.back() == ' ') return false;
|
||||
for (unsigned char c : name) {
|
||||
// NUL and other control bytes truncate at the first filesystem call
|
||||
// (std::ofstream, fopen, CreateFileW off .c_str()) — two names that
|
||||
// differ only after the NUL land on the same file.
|
||||
if (c < 0x20 || c == 0x7F) return false;
|
||||
if (c == '/' || c == '\\' || c == ':') return false;
|
||||
if (c == '*' || c == '?' || c == '|' || c == '<' || c == '>' || c == '"') return false;
|
||||
}
|
||||
if (isDosDeviceName(name)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user