blob: bfaff31047e06c9fb8cb1b51cb3a87e3ee7191c8 [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 "base/android/build_info.h"
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/memory/ptr_util.h"
#include "base/task_scheduler/post_task.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
#include "content/public/child/v8_value_converter.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 "gin/arguments.h"
#include "gin/function_template.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/platform/WebURLRequest.h"
#include "third_party/WebKit/public/web/WebDataSource.h"
#include "third_party/WebKit/public/web/WebKit.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "v8/include/v8.h"
SandboxStatusExtension::SandboxStatusExtension(content::RenderFrame* frame)
: content::RenderFrameObserver(frame) {}
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();
}
bool SandboxStatusExtension::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(SandboxStatusExtension, message)
IPC_MESSAGE_HANDLER(ChromeViewMsg_AddSandboxStatusExtension,
OnAddSandboxStatusExtension)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void SandboxStatusExtension::DidClearWindowObject() {
Install();
}
void SandboxStatusExtension::OnAddSandboxStatusExtension() {
should_install_ = true;
}
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->Global());
DCHECK(chrome->Set(
gin::StringToSymbol(isolate, "getAndroidSandboxStatus"),
gin::CreateFunctionTemplate(
isolate, base::Bind(&SandboxStatusExtension::GetSandboxStatus, this))
->GetFunction()));
}
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 =
base::MakeUnique<v8::Global<v8::Function>>(args->isolate(), callback);
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE, base::TaskTraits().MayBlock(),
base::Bind(&SandboxStatusExtension::ReadSandboxStatus, this),
base::Bind(&SandboxStatusExtension::RunCallback, this,
base::Passed(&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 = base::MakeUnique<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);
std::unique_ptr<content::V8ValueConverter> converter(
content::V8ValueConverter::create());
v8::Local<v8::Value> argv[] = {converter->ToV8Value(status.get(), context)};
render_frame()->GetWebFrame()->CallFunctionEvenIfScriptDisabled(
callback_local, v8::Object::New(isolate), 1, argv);
}