Commit message: None
CVE: CVE-2016-1698
CWE: CWE-200
Vulnerability description: The createCustomType function in extensions/renderer/resources/binding.js in the extension bindings in Google Chrome before 51.0.2704.79 does not validate module types, which might allow attackers to load arbitrary modules or obtain sensitive information by leveraging a poisoned definition.

Project: Chrome

  static void Apply(const v8::FunctionCallbackInfo<v8::Value>& info) {
    CHECK(info.Length() == 5 && info[0]->IsFunction() &&  // function
          info[2]->IsObject() &&  // args
          info[3]->IsInt32() &&   // first_arg_index
          info[4]->IsInt32());    // args_length
    v8::Local<v8::Function> function = info[0].As<v8::Function>();
    v8::Local<v8::Object> recv;
    if (info[1]->IsObject()) {
      recv = v8::Local<v8::Object>::Cast(info[1]);
    } else if (info[1]->IsString()) {
      recv = v8::StringObject::New(v8::Local<v8::String>::Cast(info[1]))
                 .As<v8::Object>();
    } else {
      info.GetIsolate()->ThrowException(
          v8::Exception::TypeError(ToV8StringUnsafe(
              info.GetIsolate(),
              "The first argument is the receiver and must be an object")));
      return;
    }
    v8::Local<v8::Object> args = v8::Local<v8::Object>::Cast(info[2]);
    int first_arg_index = info[3].As<v8::Int32>()->Value();
    int args_length = info[4].As<v8::Int32>()->Value();

    v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
    int argc = args_length - first_arg_index;
    std::unique_ptr<v8::Local<v8::Value>[]> argv(
        new v8::Local<v8::Value>[argc]);
    for (int i = 0; i < argc; ++i) {
      CHECK(IsTrue(args->Has(context, i + first_arg_index)));
      if (!GetProperty(context, args, i + first_arg_index, &argv[i]))
        return;
    }

    v8::MicrotasksScope microtasks(
        info.GetIsolate(), v8::MicrotasksScope::kDoNotRunMicrotasks);
    v8::Local<v8::Value> return_value;
    if (function->Call(context, recv, argc, argv.get()).ToLocal(&return_value))
      info.GetReturnValue().Set(return_value);
  }

Project: Chrome

v8::Extension* SafeBuiltins::CreateV8Extension() { return new ExtensionImpl(); }

Project: Chrome

  ExtensionImpl() : v8::Extension(kClassName, kScript) {}

Project: Chrome

v8::Local<v8::Object> SafeBuiltins::GetArray() const {
  return Load("Array", context_->v8_context());
}

Project: Chrome

v8::Local<v8::Object> SafeBuiltins::GetError() const {
  return Load("Error", context_->v8_context());
}

Project: Chrome

v8::Local<v8::Object> SafeBuiltins::GetJSON() const {
  return Load("JSON", context_->v8_context());
}

Project: Chrome

v8::Local<v8::Object> SafeBuiltins::GetObjekt() const {
  return Load("Object", context_->v8_context());
}

Project: Chrome

v8::Local<v8::Object> SafeBuiltins::GetRegExp() const {
  return Load("RegExp", context_->v8_context());
}

Project: Chrome

v8::Local<v8::Object> SafeBuiltins::GetString() const {
  return Load("String", context_->v8_context());
}

Project: Chrome

v8::Local<v8::Object> Load(const char* name, v8::Local<v8::Context> context) {
  v8::Local<v8::Value> value =
      context->Global()
          ->GetPrivate(context, MakeKey(name, context->GetIsolate()))
          .ToLocalChecked();
  CHECK(value->IsObject()) << name;
  return v8::Local<v8::Object>::Cast(value);
}

Project: Chrome

v8::Local<v8::Private> MakeKey(const char* name, v8::Isolate* isolate) {
  return v8::Private::ForApi(
      isolate, ToV8StringUnsafe(
                   isolate, base::StringPrintf("%s::%s", kClassName, name)));
}

Project: Chrome

SafeBuiltins::SafeBuiltins(ScriptContext* context) : context_(context) {}

Project: Chrome

  static void Save(const v8::FunctionCallbackInfo<v8::Value>& info) {
    CHECK(info.Length() == 2 && info[0]->IsString() && info[1]->IsObject());
    SaveImpl(*v8::String::Utf8Value(info[0]),
             info[1],
             info.GetIsolate()->GetCurrentContext());
  }

Project: Chrome

void SaveImpl(const char* name,
              v8::Local<v8::Value> value,
              v8::Local<v8::Context> context) {
  CHECK(!value.IsEmpty() && value->IsObject()) << name;
  context->Global()
      ->SetPrivate(context, MakeKey(name, context->GetIsolate()), value)
      .FromJust();
}

Project: Chrome

SafeBuiltins::~SafeBuiltins() {}

Project: Chrome

v8::Local<v8::Context> V8SchemaRegistry::GetOrCreateContext(
    v8::Isolate* isolate) {
  if (!context_holder_) {
    context_holder_.reset(new gin::ContextHolder(isolate));
    context_holder_->SetContext(v8::Context::New(isolate));
    schema_cache_.reset(new SchemaCache(isolate));
    return context_holder_->context();
  }
  return context_holder_->context();
}

Project: Chrome

  void GetSchema(const v8::FunctionCallbackInfo<v8::Value>& args) {
    args.GetReturnValue().Set(
        registry_->GetSchema(*v8::String::Utf8Value(args[0])));
  }

Project: Chrome

v8::Local<v8::Array> V8SchemaRegistry::GetSchemas(
    const std::vector<std::string>& apis) {
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
  v8::EscapableHandleScope handle_scope(isolate);
  v8::Context::Scope context_scope(GetOrCreateContext(isolate));

  v8::Local<v8::Array> v8_apis(v8::Array::New(isolate, apis.size()));
  size_t api_index = 0;
  for (std::vector<std::string>::const_iterator i = apis.begin();
       i != apis.end();
       ++i) {
    v8_apis->Set(api_index++, GetSchema(*i));
  }
  return handle_scope.Escape(v8_apis);
}

Project: Chrome

   SchemaRegistryNativeHandler(V8SchemaRegistry* registry,
                              std::unique_ptr<ScriptContext> context)
      : ObjectBackedNativeHandler(context.get()),
        context_(std::move(context)),
        registry_(registry) {
    RouteFunction("GetSchema",
                  base::Bind(&SchemaRegistryNativeHandler::GetSchema,
                             base::Unretained(this)));
  }

Project: Chrome

V8SchemaRegistry::~V8SchemaRegistry() {
}