Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Js math taint propagation #3

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions dom/bindings/Codegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,40 @@
NEW_ENUMERATE_HOOK_NAME = "_newEnumerate"
ENUM_ENTRY_VARIABLE_NAME = "strings"
INSTANCE_RESERVED_SLOTS = 1
PREFERENCE_PREFIX = "tainting.source."


# This size is arbitrary. It is a power of 2 to make using it as a modulo
# operand cheap, and is usually around 1/3-1/5th of the set size (sometimes
# smaller for very large sets).
GLOBAL_NAMES_PHF_SIZE = 256

def format_preference_entry(taintSource):
return "%s%s" % (PREFERENCE_PREFIX, taintSource)

def format_preference(taintSource):
return (
"pref(\"%s\", true);"
% (format_preference_entry(taintSource))
)

def maybe_add_preference(taintSource):
import pathlib
root = pathlib.Path(__file__).parent.parent.parent.resolve()
prefs = root / 'modules' / 'libpref' / 'init' / 'all.js'
prefs = prefs.resolve()
if(prefs.exists()):
preference_entry = format_preference_entry(taintSource)
with prefs.open(mode='r+') as pf:
if preference_entry in pf.read():
print("%s already defined in %s... Skipping...\n" % (preference_entry, prefs))
else:
pf.write("%s\n" % (format_preference(taintSource)))
print("Added preference '%s' to '%s'..\n" % (preference_entry, prefs))
return True
else:
print("Preference file does not exist: %s!\n"% prefs)
return False

def memberReservedSlot(member, descriptor):
return (
Expand Down Expand Up @@ -7823,6 +7851,7 @@ def _setValue(value, wrapAsType=None, setter="set"):
# Attach taint metadata to the return value if it is a source
if taintSource is not None:
print("Generating taint source:", taintSource)
maybe_add_preference(taintSource)
taintHandler = dedent(
(
"""
Expand All @@ -7846,6 +7875,7 @@ def wrapAndSetPtr(wrapCall, failureCode=None):
markTaintSnippet = ""
if taintSource is not None:
print("Generating taint source for wrapped value:", taintSource)
maybe_add_preference(taintSource)
markTaintSnippet = dedent(
f"""
// Add taint source for wrapped value
Expand Down Expand Up @@ -11189,6 +11219,7 @@ def definition_body(self):
markTaintSnippet = ""
if self.taintSource is not None:
print("Generating taint source for cached value:", self.taintSource)
maybe_add_preference(self.taintSource)
markTaintSnippet = dedent(
f"""
// Add taint source for cached value
Expand Down
98 changes: 5 additions & 93 deletions js/src/builtin/String.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,103 +169,15 @@ str_taint_getter(JSContext* cx, unsigned argc, Value* vp)
if (!str)
return false;

// Wrap all taint ranges of the string.
RootedValueVector ranges(cx);
for (const TaintRange& taint_range : str->taint()) {
RootedObject range(cx, JS_NewObject(cx, nullptr));
if(!range)
return false;

if (!JS_DefineProperty(cx, range, "begin", taint_range.begin(), JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT) ||
!JS_DefineProperty(cx, range, "end", taint_range.end(), JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT))
return false;

// Wrap the taint flow for the current range.
RootedValueVector taint_flow(cx);
for (TaintNode& taint_node : taint_range.flow()) {
RootedObject node(cx, JS_NewObject(cx, nullptr));
if (!node)
return false;

RootedString operation(cx, JS_NewStringCopyZ(cx, taint_node.operation().name()));
if (!operation)
return false;

if (!JS_DefineProperty(cx, node, "operation", operation, JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT))
return false;

RootedValue isBuiltIn(cx);
isBuiltIn.setBoolean(taint_node.operation().is_native());

if (!JS_DefineProperty(cx, node, "builtin", isBuiltIn, JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT))
return false;

RootedValue isSource(cx);
isSource.setBoolean(taint_node.operation().isSource());

if (!JS_DefineProperty(cx, node, "source", isSource, JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT))
return false;

// Wrap the location
RootedObject location(cx, JS_NewObject(cx, nullptr));
if (!location)
return false;
RootedString filename(cx, JS_NewUCStringCopyZ(cx, taint_node.operation().location().filename().c_str()));
if (!filename)
return false;
RootedString function(cx, JS_NewUCStringCopyZ(cx, taint_node.operation().location().function().c_str()));
if (!function)
return false;
// Also add the MD5 hash of the containing function
RootedString hash(cx, JS_NewStringCopyZ(cx, JS::convertDigestToHexString(taint_node.operation().location().scriptHash()).c_str()));
if (!hash)
return false;

if (!JS_DefineProperty(cx, location, "filename", filename, JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT) ||
!JS_DefineProperty(cx, location, "function", function, JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT) ||
!JS_DefineProperty(cx, location, "line", taint_node.operation().location().line(), JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT) ||
!JS_DefineProperty(cx, location, "pos", taint_node.operation().location().pos(), JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT) ||
!JS_DefineProperty(cx, location, "scriptline", taint_node.operation().location().scriptStartLine(), JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT) ||
!JS_DefineProperty(cx, location, "scripthash", hash, JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT))
return false;

if (!JS_DefineProperty(cx, node, "location", location, JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT))
return false;

// Wrap the arguments
RootedValueVector taint_arguments(cx);
for (auto& taint_argument : taint_node.operation().arguments()) {
RootedString argument(cx, JS_NewUCStringCopyZ(cx, taint_argument.c_str()));
if (!argument)
return false;

if (!taint_arguments.append(StringValue(argument)))
return false;
}

RootedObject arguments(cx, NewDenseCopiedArray(cx, taint_arguments.length(), taint_arguments.begin()));
if (!JS_DefineProperty(cx, node, "arguments", arguments, JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT))
return false;

if (!taint_flow.append(ObjectValue(*node)))
return false;
}

RootedObject flow(cx, NewDenseCopiedArray(cx, taint_flow.length(), taint_flow.begin()));
if (!flow)
return false;
if (!JS_DefineProperty(cx, range, "flow", flow, JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT))
return false;

if (!ranges.append(ObjectValue(*range)))
return false;
RootedObject taint_obj(cx, JS_NewObject(cx, nullptr));
if (!getStringTaintObject(cx, str->taint(), taint_obj)) {
return false;
}

JSObject* array = NewDenseCopiedArray(cx, ranges.length(), ranges.begin());
if (!array)
if (!JS_GetProperty(cx, taint_obj, "ranges", args.rval())) {
return false;
}

args.rval().setObject(*array);
return true;
}

Expand Down
Loading