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? 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/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/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..d28f707cfbf5f 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,83 @@ 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) { + 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()) { + 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 +} + +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 767f48c302850..b604c7530d486 100644 --- a/js/src/jstaint.h +++ b/js/src/jstaint.h @@ -85,6 +85,11 @@ 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); +// Write a message to the file +void MaybeSpewMessage(JSContext* cx, JSString* str); + // Print a message to stdout. void TaintFoxReport(JSContext* cx, const char* msg); 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 613ef65b59ae7..ae7c34deb20c0 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 { @@ -125,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() { diff --git a/js/src/vm/JSONPrinter.cpp b/js/src/vm/JSONPrinter.cpp index 5b5183d9fb7c5..cac6a93a5014b 100644 --- a/js/src/vm/JSONPrinter.cpp +++ b/js/src/vm/JSONPrinter.cpp @@ -143,6 +143,18 @@ 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(); + first_ = false; +} + 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);