Fix File stat-before-open crash risk, JSON string-quoting bug, and MString buffer overflow

- File: stat() only after a successful open() (previously ran first with
  its result ignored, feeding a missing file's garbage st_size into a
  realloc - could crash the whole APIServer on a request for a
  nonexistent static asset)
- JString::setString(): always quote+escape the value instead of going
  through set()'s literal-value guess, which misclassified any string
  starting with digits (e.g. a UUID) as a bare numeric literal and wrote
  it unquoted, corrupting later edits to the same JSON document
- MString::remove() (both overloads): fixed an off-by-one that read one
  byte past the buffer on a completely full string (found via ASan under
  concurrent load)
- CGIFormData: added fields() so callers can iterate every parsed field
  without knowing names in advance (used to merge POST body into
  jet::Global::variables the same way query-string params already are)
This commit is contained in:
Brad Arant committed 2026-09-03 05:14:24 +00:00
1 parent d7057ebb00
commit 78c45d378c
6 files changed
+79 -8

No files matched your search

+25 -1
View File
@@ -474,7 +474,11 @@ namespace coreutils {
formatted << value;
else
formatted << "\"" << jsonEscape(value).c_str() << "\"";
setFormatted(path, formatted);
}
void JString::setFormatted(ZString path, MString formatted) {
reset();
if (locate(path)) {
int startOffset = offset();
skipValue();
@@ -491,8 +495,28 @@ namespace coreutils {
}
void JString::setString(ZString path, std::string value) {
// Deliberately NOT routed through set() (which calls isLiteralValue()
// to guess whether the raw text should be quoted) - setString() is
// explicitly, unambiguously a string setter, so the value must
// ALWAYS be quoted+escaped regardless of what it looks like.
// isLiteralValue() classifies anything ZString::startsWithNumber()
// accepts as a bare numeric literal - true for "42", but ALSO true
// for a string that merely STARTS with digits, like a UUID
// ("00146df8-e42c-11e7-9c78-525400b869dc"). Going through set()
// wrote that UUID completely unquoted; skipValue() then only
// recognizes the JSON-number PREFIX ("00146") as the value's real
// span when locating it for a later update, so the next setString()
// call spliced its own new key/value pair in right after "00146",
// leaving "df8-e42c-...-869dc" as orphaned text outside the object
// entirely - malformed JSON, confirmed via a real corrupted session
// file (jet-2.0's own native $[@name] session variables, backed by
// this class - see Global.h). Every other setString() caller
// sitewide was silently exposed to the same risk for any string
// value that happens to start with a digit.
MString v(value);
set(path, v);
MString formatted;
formatted << "\"" << jsonEscape(v).c_str() << "\"";
setFormatted(path, formatted);
}
void JString::setNumber(ZString path, double value) {