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

Overhead if tainting is disabled #235

Open
leeN opened this issue Nov 22, 2024 · 0 comments
Open

Overhead if tainting is disabled #235

leeN opened this issue Nov 22, 2024 · 0 comments
Assignees
Labels
enhancement New feature or request performance Performance Issues and Enhancements

Comments

@leeN
Copy link
Collaborator

leeN commented Nov 22, 2024

We can nicely disable taint tracking (i.e., introducing taints at sources) via about.config. Therefore, we can directly analyze whether our changes introduce performance penalties even in the complete absence of any tainted values.

I was playing with the built-in benchmarks, primarily jetstream2, and noticed something strange.

xvfb-run ./mach raptor --setpref tainting.active=false -t jetstream2 

When running the above, the resulting numbers barely differed between setting tainting.active to false or true. This means that disabling tainting does not gain any performance benefit, which was somewhat unexpected.

Thankfully, profiling this is straightforward. Adding the --extra-profiler-run flag stores symbolized profiling data, which you can analyze under profiler.firefox.com/. Here, the culprit became obvious right away.
Profiling Output

Generally, when tracking taints, the expensive part is creating the TaintOperation object. One would assume that if tainting is disabled, we do not need to create any of those. This is a misconception, however.

void JS::MarkTaintedFunctionArguments(JSContext* cx, JSFunction* function, const CallArgs& args)
{
  if (!function)
    return;

  RootedValue name(cx);

  JS::Rooted<JSAtom*> atom(cx);
  if (function->getDisplayAtom(cx, &atom)) {
    name = StringValue(atom);
  }

  RootedFunction fun(cx, function);

  std::u16string sourceinfo(u"unknown");
  if (fun->isInterpreted() && fun->hasBaseScript()) {
    RootedScript script(cx, JSFunction::getOrCreateScript(cx, fun));
    if (script) {
      int lineno = script->lineno();
      js::ScriptSource* source = script->scriptSource();
      if (source && source->filename()) {
        std::string filename(source->filename());
        sourceinfo = ascii2utf16(filename) + u":" + ascii2utf16(std::to_string(lineno));
      }
    }
  }

  TaintLocation location = TaintLocationFromContext(cx);
  for (unsigned i = 0; i < args.length(); i++) {
    if (args[i].isString()) {
      RootedString arg(cx, args[i].toString());
      if (arg->isTainted()) {
        arg->taint().extend(
          TaintOperation("function", location,
                         { taintarg(cx, name), sourceinfo, taintarg(cx, i), taintarg(cx, args.length()) } ));
      }
    }
  }
}

Here, the TaintLocation object (the expensive part of the TaintOperation object) is created regardless of whether any argument string is actually tainted. I will prepare a PR later today where we bail out before creating any expensive objects if none of the arguments is a tainted string. Currently measuring the performance impact of doing so.

@leeN leeN added enhancement New feature or request performance Performance Issues and Enhancements labels Nov 22, 2024
@leeN leeN self-assigned this Nov 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request performance Performance Issues and Enhancements
Projects
None yet
Development

No branches or pull requests

1 participant