Review changes

This commit is contained in:
jpirnay
2026-05-20 19:34:27 +02:00
parent dc15186e22
commit 78e1d2eacb
3 changed files with 43 additions and 3 deletions
+13
View File
@@ -30,6 +30,19 @@ bool FontInstaller::isValidFamilyName(const char* name) {
return true;
}
bool FontInstaller::isValidFontFileName(const char* name) {
if (name == nullptr || name[0] == '\0') return false;
// Matches the cap used by the web-server manifest parser; the SD-side path buffer is 128
// bytes including the family prefix, so 60 leaves plenty of headroom.
static constexpr size_t MAX_FONT_FILE_NAME_LEN = 60;
const size_t nameLen = strlen(name);
if (nameLen > MAX_FONT_FILE_NAME_LEN) return false;
if (name[0] == '/') return false;
if (strchr(name, '\\') != nullptr) return false;
if (strstr(name, "..") != nullptr) return false;
return true;
}
bool FontInstaller::ensureFamilyDir(const char* familyName) {
if (!isValidFamilyName(familyName)) {
LOG_ERR("FONT", "Invalid family name: %s", familyName ? familyName : "<null>");
+5
View File
@@ -25,6 +25,11 @@ class FontInstaller {
/// Validate a family name: alphanumeric + hyphen + underscore only, no path traversal.
static bool isValidFamilyName(const char* name);
/// Validate a font file name as it appears in a manifest entry: non-empty, length-bounded,
/// no absolute paths, no backslashes, no traversal components. Slashes are allowed for
/// "<family>/<file>"-style entries.
static bool isValidFontFileName(const char* name);
/// Ensure /.crosspoint/fonts/<family>/ directory exists.
bool ensureFamilyDir(const char* familyName);
@@ -130,7 +130,13 @@ bool FontDownloadActivity::fetchAndParseManifest() {
family.description = fObj["description"] | "";
// styles[] in the JSON is intentionally ignored — see ManifestFamily.
if (!FontInstaller::isValidFamilyName(family.name.c_str())) {
LOG_ERR("FONT", "Manifest entry rejected, invalid family name: %s", family.name.c_str());
continue;
}
family.totalSize = 0;
bool fileNamesOk = true;
for (JsonObject fileObj : fObj["files"].as<JsonArray>()) {
ManifestFile file;
file.name = fileObj["name"] | "";
@@ -139,9 +145,15 @@ bool FontDownloadActivity::fetchAndParseManifest() {
file.crc32 = fileObj["crc32"].as<uint32_t>();
file.hasCrc32 = true;
}
if (!FontInstaller::isValidFontFileName(file.name.c_str())) {
LOG_ERR("FONT", "Manifest entry rejected, invalid file name in %s: %s", family.name.c_str(), file.name.c_str());
fileNamesOk = false;
break;
}
family.totalSize += file.size;
family.files.push_back(std::move(file));
}
if (!fileNamesOk) continue;
family.installed = fontInstaller_.isFamilyInstalled(family.name.c_str());
@@ -225,7 +237,8 @@ bool readU8(FsFile& f, uint8_t& v) { return f.read(&v, 1) == 1; }
bool readU32(FsFile& f, uint32_t& v) {
uint8_t buf[4];
if (f.read(buf, 4) != 4) return false;
v = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
v = static_cast<uint32_t>(buf[0]) | (static_cast<uint32_t>(buf[1]) << 8) | (static_cast<uint32_t>(buf[2]) << 16) |
(static_cast<uint32_t>(buf[3]) << 24);
return true;
}
bool readStr(FsFile& f, std::string& s) {
@@ -460,8 +473,17 @@ void FontDownloadActivity::downloadFamily(int familyIdx) {
downloadingFamilyHasResumable_ = family.hasResumableDownload;
// Restore families_ regardless of success/error/abort outcome, then merge
// back the mutations the impl made on the local family copy.
if (restoreFamiliesFromSd() && familyIdx >= 0 && familyIdx < static_cast<int>(families_.size())) {
// back the mutations the impl made on the local family copy. Without the
// restored manifest the activity can't render the family list, so a failed
// restore is fatal — drop to ERROR rather than continuing with empty state.
if (!restoreFamiliesFromSd()) {
RenderLock lock(*this);
state_ = ERROR;
pendingErrorAction_ = PendingFontAction::Download;
errorMessage_ = "Failed to restore manifest";
return;
}
if (familyIdx >= 0 && familyIdx < static_cast<int>(families_.size())) {
families_[familyIdx].installed = family.installed;
families_[familyIdx].hasUpdate = family.hasUpdate;
families_[familyIdx].hasResumableDownload = family.hasResumableDownload;