blob: 058669e9ec7c11eda8e23155fac631cc5a949d69 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/renderer/sandbox_status_extension_android.h"
#include <utility>
#include "base/android/build_info.h"
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/task/post_task.h"
#include "base/task/thread_pool.h"
#include "chrome/common/url_constants.h"
#include "content/public/renderer/chrome_object_extensions_utils.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/seccomp_sandbox_status_android.h"
#include "content/public/renderer/v8_value_converter.h"
#include "gin/arguments.h"
#include "gin/function_template.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
#include "third_party/blink/public/platform/web_security_origin.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/public/web/blink.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "v8/include/v8.h"
SandboxStatusExtension::SandboxStatusExtension(content::RenderFrame* frame)
: content::RenderFrameObserver(frame) {
// Don't do anything else for subframes.
if (!frame->IsMainFrame())
return;
frame->GetAssociatedInterfaceRegistry()->AddInterface(base::BindRepeating(
&SandboxStatusExtension::OnSandboxStatusExtensionRequest,
base::RetainedRef(this)));
}
SandboxStatusExtension::~SandboxStatusExtension() {}
// static
void SandboxStatusExtension::Create(content::RenderFrame* frame) {
auto* extension = new SandboxStatusExtension(frame);
extension->AddRef(); // Balanced in OnDestruct().
}
void SandboxStatusExtension::OnDestruct() {
// This object is ref-counted, since a callback could still be in-flight.
Release();
}
void SandboxStatusExtension::DidClearWindowObject() {
Install();
}
void SandboxStatusExtension::AddSandboxStatusExtension() {
should_install_ = true;
}
void SandboxStatusExtension::OnSandboxStatusExtensionRequest(
mojo::PendingAssociatedReceiver<chrome::mojom::SandboxStatusExtension>
receiver) {
receiver_.Bind(std::move(receiver));
}
void SandboxStatusExtension::Install() {
if (!should_install_)
return;
v8::Isolate* isolate = blink::MainThreadIsolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
render_frame()->GetWebFrame()->MainWorldScriptContext();
if (context.IsEmpty())
return;
v8::Context::Scope context_scope(context);
v8::Local<v8::Object> chrome =
content::GetOrCreateChromeObject(isolate, context);
v8::Local<v8::Function> function;
bool success =
gin::CreateFunctionTemplate(
isolate,
base::BindRepeating(&SandboxStatusExtension::GetSandboxStatus, this))
->GetFunction(context)
.ToLocal(&function);
if (success) {
success = chrome
->Set(context,
gin::StringToSymbol(isolate, "getAndroidSandboxStatus"),
function)
.IsJust();
}
DCHECK(success);
}
void SandboxStatusExtension::GetSandboxStatus(gin::Arguments* args) {
if (!render_frame())
return;
if (render_frame()->GetWebFrame()->GetSecurityOrigin().Host() !=
chrome::kChromeUISandboxHost) {
args->ThrowTypeError("Not allowed on this origin");
return;
}
v8::HandleScope handle_scope(args->isolate());
v8::Local<v8::Function> callback;
if (!args->GetNext(&callback)) {
args->ThrowError();
return;
}
auto global_callback =
std::make_unique<v8::Global<v8::Function>>(args->isolate(), callback);
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE, {base::MayBlock()},
base::BindOnce(&SandboxStatusExtension::ReadSandboxStatus, this),
base::BindOnce(&SandboxStatusExtension::RunCallback, this,
std::move(global_callback)));
}
std::unique_ptr<base::Value> SandboxStatusExtension::ReadSandboxStatus() {
std::string secontext;
base::FilePath path(FILE_PATH_LITERAL("/proc/self/attr/current"));
base::ReadFileToString(path, &secontext);
std::string proc_status;
path = base::FilePath(FILE_PATH_LITERAL("/proc/self/status"));
base::ReadFileToString(path, &proc_status);
auto status = std::make_unique<base::DictionaryValue>();
status->SetInteger("uid", getuid());
status->SetInteger("pid", getpid());
status->SetString("secontext", secontext);
status->SetInteger("seccompStatus",
static_cast<int>(content::GetSeccompSandboxStatus()));
status->SetString("procStatus", proc_status);
status->SetString(
"androidBuildId",
base::android::BuildInfo::GetInstance()->android_build_id());
return std::move(status);
}
void SandboxStatusExtension::RunCallback(
std::unique_ptr<v8::Global<v8::Function>> callback,
std::unique_ptr<base::Value> status) {
if (!render_frame())
return;
v8::Isolate* isolate = blink::MainThreadIsolate();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
render_frame()->GetWebFrame()->MainWorldScriptContext();
v8::Context::Scope context_scope(context);
v8::Local<v8::Function> callback_local =
v8::Local<v8::Function>::New(isolate, *callback);
v8::Local<v8::Value> argv[] = {
content::V8ValueConverter::Create()->ToV8Value(status.get(), context)};
render_frame()->GetWebFrame()->CallFunctionEvenIfScriptDisabled(
callback_local, v8::Object::New(isolate), 1, argv);
}