From db7aacdf68e4ebe513762068e5cc72fe4ec8368b Mon Sep 17 00:00:00 2001 From: Thomas Barber Date: Tue, 3 Dec 2024 12:29:07 +0000 Subject: [PATCH 1/7] Foxhound: bugfixing segmentation fault on close --- dom/base/NodeInfo.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dom/base/NodeInfo.cpp b/dom/base/NodeInfo.cpp index 0a66d4deff9cb..6aa73e2a853a5 100644 --- a/dom/base/NodeInfo.cpp +++ b/dom/base/NodeInfo.cpp @@ -152,6 +152,10 @@ void NodeInfo::GetPrefix(nsAString& aPrefix) const { void NodeInfo::GetNamespaceURI(nsAString& aNameSpaceURI) const { if (mInner.mNamespaceID > 0) { + if (!nsNameSpaceManager::GetInstance()) { + SetDOMStringToNull(aNameSpaceURI); + return; + } nsresult rv = nsNameSpaceManager::GetInstance()->GetNameSpaceURI( mInner.mNamespaceID, aNameSpaceURI); // How can we possibly end up with a bogus namespace ID here? From 19ef468f2de00e656dd1b732ff48db808879aec2 Mon Sep 17 00:00:00 2001 From: Thomas Barber Date: Tue, 3 Dec 2024 13:20:06 +0000 Subject: [PATCH 2/7] Dump StringTaint to file via a Spewer --- js/moz.configure | 9 +++++++ js/src/jsapi.cpp | 2 ++ js/src/jstaint.cpp | 49 ++++++++++++++++++++++++++++++++++ js/src/jstaint.h | 3 +++ js/src/util/StructuredSpewer.h | 3 ++- js/src/vm/JSONPrinter.cpp | 11 ++++++++ js/src/vm/JSONPrinter.h | 3 +++ 7 files changed, 79 insertions(+), 1 deletion(-) diff --git a/js/moz.configure b/js/moz.configure index cbcaf38f01c9d..b52afe7c75230 100644 --- a/js/moz.configure +++ b/js/moz.configure @@ -494,6 +494,15 @@ set_config("JS_JITSPEW", depends_if("--enable-jitspew")(lambda _: True)) set_define("JS_STRUCTURED_SPEW", depends_if("--enable-jitspew")(lambda _: True)) set_config("JS_STRUCTURED_SPEW", depends_if("--enable-jitspew")(lambda _: True)) +option( + "--enable-taintspew", + default=False, + help="{Enable|Disable} the taint flow spew variable", +) + +# Also enable the structured spewer for tainting +set_define("JS_STRUCTURED_SPEW", depends_if("--enable-taintspew")(lambda _: True)) +set_config("JS_STRUCTURED_SPEW", depends_if("--enable-taintspew")(lambda _: True)) @depends("--enable-jit", "--enable-jitspew", simulator, target, moz_debug) def jit_disasm_arm(jit_enabled, spew, simulator, target, debug): diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index c4fa087b08251..8e02208c3ecf6 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -5072,6 +5072,8 @@ JS_ReportTaintSink(JSContext* cx, JS::HandleString str, const char* sink, JS::Ha RootedValue rval(cx); JS_CallFunction(cx, nullptr, report, arguments, &rval); MOZ_ASSERT(!cx->isExceptionPending()); + + MaybeSpewStringTaint(cx, str); } JS_PUBLIC_API bool JS::FinishIncrementalEncoding(JSContext* cx, diff --git a/js/src/jstaint.cpp b/js/src/jstaint.cpp index 22a4da241f96a..7a2897a9a4202 100644 --- a/js/src/jstaint.cpp +++ b/js/src/jstaint.cpp @@ -17,6 +17,7 @@ #include "js/ErrorReport.h" #include "js/UniquePtr.h" #include "vm/FrameIter.h" +#include "vm/JSAtomUtils.h" #include "vm/JSContext.h" #include "vm/JSFunction.h" #include "vm/StringType.h" @@ -371,6 +372,54 @@ void JS::MarkTaintedFunctionArguments(JSContext* cx, JSFunction* function, const } } +void JS::MaybeSpewStringTaint(JSContext* cx, JSString* str) { +//#ifdef JS_STRUCTURED_SPEW + if (!str || !str->taint()) { + return; + } + + AutoStructuredSpewer spew(cx, SpewChannel::TaintFlowSpewer, cx->currentScript()); + if (spew) { + spew->beginList(); + for (const TaintRange& range : str->taint()) { + spew->beginObject(); + spew->property("begin", range.begin()); + spew->property("end", range.end()); + + spew->beginListProperty("flow"); + for (TaintNode& node : range.flow()) { + const TaintOperation& op = node.operation(); + spew->beginObject(); + spew->property("operation", op.name()); + spew->boolProperty("builtin", op.is_native()); + spew->boolProperty("source", op.isSource()); + + const TaintLocation& loc = op.location(); + spew->beginObjectProperty("location"); + spew->property("filename", loc.filename().c_str(), loc.filename().size()); + spew->property("line", loc.line()); + spew->property("pos", loc.pos()); + spew->property("scriptline", loc.scriptStartLine()); + spew->property("scripthash", JS::convertDigestToHexString(loc.scriptHash()).c_str()); + spew->endObject(); // Location + + spew->beginListProperty("arguments"); + for (auto& arg : op.arguments()) { + spew->string(arg.c_str(), arg.size()); + } + spew->endList(); + + spew->endObject(); // Operation + } + spew->endList(); // flow + spew->endObject(); // range + } + spew->endList(); + + } +//#endif +} + // Print a message to stdout. void JS::TaintFoxReport(JSContext* cx, const char* msg) { diff --git a/js/src/jstaint.h b/js/src/jstaint.h index 767f48c302850..a3e45003ac99b 100644 --- a/js/src/jstaint.h +++ b/js/src/jstaint.h @@ -85,6 +85,9 @@ TaintOperation TaintOperationFromContext(JSContext* cx, const char* name, bool i // This is mainly useful for tracing tainted arguments through the code. void MarkTaintedFunctionArguments(JSContext* cx, JSFunction* function, const JS::CallArgs& args); +// Write the taint report to file +void MaybeSpewStringTaint(JSContext* cx, JSString* str); + // Print a message to stdout. void TaintFoxReport(JSContext* cx, const char* msg); diff --git a/js/src/util/StructuredSpewer.h b/js/src/util/StructuredSpewer.h index 613ef65b59ae7..46d4daeba1be3 100644 --- a/js/src/util/StructuredSpewer.h +++ b/js/src/util/StructuredSpewer.h @@ -73,7 +73,8 @@ namespace js { # define STRUCTURED_CHANNEL_LIST(_) \ _(BaselineICStats) \ - _(CacheIRHealthReport) + _(CacheIRHealthReport) \ + _(TaintFlowSpewer) // Structured spew channels enum class SpewChannel { diff --git a/js/src/vm/JSONPrinter.cpp b/js/src/vm/JSONPrinter.cpp index 5b5183d9fb7c5..6f93054b06e83 100644 --- a/js/src/vm/JSONPrinter.cpp +++ b/js/src/vm/JSONPrinter.cpp @@ -143,6 +143,17 @@ void JSONPrinter::property(const char* name, const char* value) { endStringProperty(); } +void JSONPrinter::property(const char* name, const char16_t* value, size_t length) { + beginStringProperty(name); + JSONString(out_, value, length); + endStringProperty(); +} + +void JSONPrinter::string(const char16_t* value, size_t length) { + JSONString(beginString(), value, length); + endString(); +} + void JSONPrinter::formatProperty(const char* name, const char* format, ...) { va_list ap; va_start(ap, format); diff --git a/js/src/vm/JSONPrinter.h b/js/src/vm/JSONPrinter.h index b90696a2b448f..06a16e4c2b662 100644 --- a/js/src/vm/JSONPrinter.h +++ b/js/src/vm/JSONPrinter.h @@ -49,6 +49,7 @@ class JSONPrinter { void property(const char* name, JSLinearString* value); void property(const char* name, const char* value); + void property(const char* name, const char16_t* value, size_t length); void property(const char* name, int32_t value); void property(const char* name, uint32_t value); void property(const char* name, int64_t value); @@ -60,6 +61,8 @@ class JSONPrinter { void property(const char* name, size_t value); #endif + void string(const char16_t* value, size_t length); + void formatProperty(const char* name, const char* format, ...) MOZ_FORMAT_PRINTF(3, 4); void formatProperty(const char* name, const char* format, va_list ap); From 2a8327f95b08334503fa214197786a3f5690bdff Mon Sep 17 00:00:00 2001 From: Thomas Barber Date: Tue, 3 Dec 2024 13:37:03 +0000 Subject: [PATCH 3/7] Adding string list commas --- js/src/vm/JSONPrinter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/js/src/vm/JSONPrinter.cpp b/js/src/vm/JSONPrinter.cpp index 6f93054b06e83..cac6a93a5014b 100644 --- a/js/src/vm/JSONPrinter.cpp +++ b/js/src/vm/JSONPrinter.cpp @@ -152,6 +152,7 @@ void JSONPrinter::property(const char* name, const char16_t* value, size_t lengt void JSONPrinter::string(const char16_t* value, size_t length) { JSONString(beginString(), value, length); endString(); + first_ = false; } void JSONPrinter::formatProperty(const char* name, const char* format, ...) { From b51843ef1f5809502d402354f309316d0ace18fc Mon Sep 17 00:00:00 2001 From: Thomas Barber Date: Tue, 3 Dec 2024 13:37:18 +0000 Subject: [PATCH 4/7] Adding string to TaintSpew output --- js/src/jstaint.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/js/src/jstaint.cpp b/js/src/jstaint.cpp index 7a2897a9a4202..924fac645d601 100644 --- a/js/src/jstaint.cpp +++ b/js/src/jstaint.cpp @@ -380,7 +380,9 @@ void JS::MaybeSpewStringTaint(JSContext* cx, JSString* str) { AutoStructuredSpewer spew(cx, SpewChannel::TaintFlowSpewer, cx->currentScript()); if (spew) { - spew->beginList(); + spew->property("str", str); + + spew->beginListProperty("taint"); for (const TaintRange& range : str->taint()) { spew->beginObject(); spew->property("begin", range.begin()); From eda203a9149975ae4dadd34a3934bd3d1ac459c8 Mon Sep 17 00:00:00 2001 From: Thomas Barber Date: Tue, 3 Dec 2024 13:44:29 +0000 Subject: [PATCH 5/7] Wrap TaintSpew in compiler flag --- js/src/jstaint.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/js/src/jstaint.cpp b/js/src/jstaint.cpp index 924fac645d601..73b23b6d39267 100644 --- a/js/src/jstaint.cpp +++ b/js/src/jstaint.cpp @@ -373,14 +373,19 @@ void JS::MarkTaintedFunctionArguments(JSContext* cx, JSFunction* function, const } void JS::MaybeSpewStringTaint(JSContext* cx, JSString* str) { -//#ifdef JS_STRUCTURED_SPEW +#ifdef JS_STRUCTURED_SPEW if (!str || !str->taint()) { return; } AutoStructuredSpewer spew(cx, SpewChannel::TaintFlowSpewer, cx->currentScript()); if (spew) { - spew->property("str", str); + JSLinearString* linear = str->ensureLinear(cx); + if (linear) { + spew->property("str", linear); + } else { + spew->property("str", "Non-linear String!"); + } spew->beginListProperty("taint"); for (const TaintRange& range : str->taint()) { @@ -419,7 +424,7 @@ void JS::MaybeSpewStringTaint(JSContext* cx, JSString* str) { spew->endList(); } -//#endif +#endif } // Print a message to stdout. From bf18101439a328a1f837cbd6a69769ca180453ac Mon Sep 17 00:00:00 2001 From: Thomas Barber Date: Wed, 4 Dec 2024 09:39:45 +0000 Subject: [PATCH 6/7] Adding xXSSvalidation function --- js/src/builtin/String.cpp | 19 ++++++++++++++++++- js/src/jstaint.cpp | 22 ++++++++++++++++++++++ js/src/jstaint.h | 2 ++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/js/src/builtin/String.cpp b/js/src/builtin/String.cpp index a841a52f05d22..98f1e7aabefbc 100644 --- a/js/src/builtin/String.cpp +++ b/js/src/builtin/String.cpp @@ -123,6 +123,8 @@ static bool str_encodeURI(JSContext* cx, unsigned argc, Value* vp); static bool str_encodeURI_Component(JSContext* cx, unsigned argc, Value* vp); +static bool str_foxhound(JSContext* cx, unsigned argc, Value* vp); + /* * Global string methods */ @@ -723,7 +725,7 @@ static const JSFunctionSpec string_functions[] = { JS_FN("encodeURI", str_encodeURI, 1, JSPROP_RESOLVING), JS_FN("decodeURIComponent", str_decodeURI_Component, 1, JSPROP_RESOLVING), JS_FN("encodeURIComponent", str_encodeURI_Component, 1, JSPROP_RESOLVING), - + JS_FN("foxhound", str_foxhound, 1, JSPROP_RESOLVING), JS_FS_END, }; @@ -5325,6 +5327,21 @@ JSString* js::EncodeURI(JSContext* cx, const char* chars, size_t length) { return sb.finishString(); } +static bool str_foxhound(JSContext* cx, unsigned argc, Value* vp) { + AutoJSMethodProfilerEntry pseudoFrame(cx, "foxhound"); + CallArgs args = CallArgsFromVp(argc, vp); + // This will also do conversions from numbers to strings + Rooted str(cx, ArgToLinearString(cx, args, 0)); + if (!str) { + return false; + } + + MaybeSpewMessage(cx, str); + + args.rval().setUndefined(); + return true; +} + static bool FlatStringMatchHelper(JSContext* cx, HandleString str, HandleString pattern, bool* isFlat, int32_t* match) { diff --git a/js/src/jstaint.cpp b/js/src/jstaint.cpp index 73b23b6d39267..d28f707cfbf5f 100644 --- a/js/src/jstaint.cpp +++ b/js/src/jstaint.cpp @@ -427,6 +427,28 @@ void JS::MaybeSpewStringTaint(JSContext* cx, JSString* str) { #endif } +void JS::MaybeSpewMessage(JSContext* cx, JSString* str) { + // First print message to stderr + SEprinter p; + p.put("!!! foxhound() called with message: "); + p.putString(cx, str); + p.put("\n"); + p.flush(); + +#ifdef JS_STRUCTURED_SPEW + // Spew to file if enabled + AutoStructuredSpewer spew(cx, SpewChannel::TaintFlowSpewer, cx->currentScript()); + if (spew) { + JSLinearString* linear = str->ensureLinear(cx); + if (linear) { + spew->property("foxhound", linear); + } else { + spew->property("foxhound", "Non-linear String!"); + } + } +#endif +} + // Print a message to stdout. void JS::TaintFoxReport(JSContext* cx, const char* msg) { diff --git a/js/src/jstaint.h b/js/src/jstaint.h index a3e45003ac99b..b604c7530d486 100644 --- a/js/src/jstaint.h +++ b/js/src/jstaint.h @@ -87,6 +87,8 @@ void MarkTaintedFunctionArguments(JSContext* cx, JSFunction* function, const JS: // Write the taint report to file void MaybeSpewStringTaint(JSContext* cx, JSString* str); +// Write a message to the file +void MaybeSpewMessage(JSContext* cx, JSString* str); // Print a message to stdout. void TaintFoxReport(JSContext* cx, const char* msg); From 0fb4f2dce1cc083c400ca39ec463d208a70999bb Mon Sep 17 00:00:00 2001 From: Thomas Barber Date: Thu, 5 Dec 2024 12:26:16 +0000 Subject: [PATCH 7/7] Updating default spew location for Android --- js/src/util/StructuredSpewer.cpp | 2 +- js/src/util/StructuredSpewer.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/js/src/util/StructuredSpewer.cpp b/js/src/util/StructuredSpewer.cpp index 72f483c6b5472..f2fe82ca0f6d0 100644 --- a/js/src/util/StructuredSpewer.cpp +++ b/js/src/util/StructuredSpewer.cpp @@ -31,7 +31,7 @@ const StructuredSpewer::NameArray StructuredSpewer::names_ = { # if defined(_WIN32) # define DEFAULT_SPEW_DIRECTORY "." # elif defined(__ANDROID__) -# define DEFAULT_SPEW_DIRECTORY "/data/local/tmp" +# define DEFAULT_SPEW_DIRECTORY "/sdcard/Download" # else # define DEFAULT_SPEW_DIRECTORY "." # endif diff --git a/js/src/util/StructuredSpewer.h b/js/src/util/StructuredSpewer.h index 46d4daeba1be3..ae7c34deb20c0 100644 --- a/js/src/util/StructuredSpewer.h +++ b/js/src/util/StructuredSpewer.h @@ -126,9 +126,13 @@ class StructuredSpewer { spewingEnabled_(0), json_(mozilla::Nothing()), selectedChannel_() { +#if defined(__ANDROID__) + parseSpewFlags("TaintFlowSpewer,AtStartup"); +#else if (getenv("SPEW")) { parseSpewFlags(getenv("SPEW")); } +#endif } ~StructuredSpewer() {