Skip to content
This repository has been archived by the owner on Apr 3, 2020. It is now read-only.

Commit

Permalink
Add SeccompSupportDetector for Android.
Browse files Browse the repository at this point in the history
This class will report to UMA the Android kernel version and the level of kernel
support for seccomp-bpf sandboxing.

BUG=468455

Review URL: https://codereview.chromium.org/1018953004

Cr-Commit-Position: refs/heads/master@{#321451}
  • Loading branch information
rsesek authored and Commit bot committed Mar 19, 2015
1 parent 2de0b55 commit e59ea89
Show file tree
Hide file tree
Showing 13 changed files with 300 additions and 1 deletion.
4 changes: 4 additions & 0 deletions chrome/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,10 @@ static_library("browser") {
"//components/web_modal",
]
defines += [ "ENABLE_DATA_REDUCTION_PROXY_DEBUGGING" ]

if (use_seccomp_bpf) {
defines += [ "USE_SECCOMP_BPF" ]
}
}

if (is_mac) {
Expand Down
127 changes: 127 additions & 0 deletions chrome/browser/android/seccomp_support_detector.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright 2015 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/browser/android/seccomp_support_detector.h"

#include <stdio.h>
#include <sys/utsname.h>

#include "base/message_loop/message_loop_proxy.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
#include "chrome/common/chrome_utility_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/utility_process_host.h"

using content::BrowserThread;

enum AndroidSeccompStatus {
DETECTION_FAILED, // The process crashed during detection.
NOT_SUPPORTED, // Kernel has no seccomp support.
SUPPORTED, // Kernel has seccomp support.
LAST_STATUS
};

// static
void SeccompSupportDetector::StartDetection() {
// This is instantiated here, and then ownership is maintained by the
// Closure objects when the object is being passed between threads. A
// reference is also taken by the UtilityProcessHost, which will release
// it when the process exits.
scoped_refptr<SeccompSupportDetector> detector(new SeccompSupportDetector());
BrowserThread::PostBlockingPoolTask(FROM_HERE,
base::Bind(&SeccompSupportDetector::DetectKernelVersion, detector));
}

SeccompSupportDetector::SeccompSupportDetector() : prctl_detected_(false) {
}

SeccompSupportDetector::~SeccompSupportDetector() {
}

void SeccompSupportDetector::DetectKernelVersion() {
DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());

// This method will report the kernel major and minor versions by
// taking the lower 16 bits of each version number and combining
// the two into a 32-bit number.

utsname uts;
if (uname(&uts) == 0) {
int major, minor;
if (sscanf(uts.release, "%d.%d", &major, &minor) == 2) {
int version = ((major & 0xFFFF) << 16) | (minor & 0xFFFF);
UMA_HISTOGRAM_SPARSE_SLOWLY("Android.KernelVersion", version);
}
}

#if defined(USE_SECCOMP_BPF)
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&SeccompSupportDetector::DetectSeccomp, this));
#else
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&SeccompSupportDetector::OnDetectPrctl, this, false));
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&SeccompSupportDetector::OnDetectSyscall, this, false));
#endif
}

void SeccompSupportDetector::DetectSeccomp() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);

content::UtilityProcessHost* utility_process_host =
content::UtilityProcessHost::Create(
this, base::MessageLoopProxy::current());
utility_process_host->Send(new ChromeUtilityMsg_DetectSeccompSupport());
}

void SeccompSupportDetector::OnProcessCrashed(int exit_code) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
// The process crashed. Since prctl detection happens first, report which
// probe failed.
if (prctl_detected_) {
UMA_HISTOGRAM_ENUMERATION("Android.SeccompStatus.Syscall",
DETECTION_FAILED,
LAST_STATUS);
} else {
UMA_HISTOGRAM_ENUMERATION("Android.SeccompStatus.Prctl",
DETECTION_FAILED,
LAST_STATUS);
}
}

bool SeccompSupportDetector::OnMessageReceived(const IPC::Message& message) {
bool handled = false;
IPC_BEGIN_MESSAGE_MAP(SeccompSupportDetector, message)
IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DetectSeccompSupport_ResultPrctl,
OnDetectPrctl)
IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_DetectSeccompSupport_ResultSyscall,
OnDetectSyscall)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}

void SeccompSupportDetector::OnDetectPrctl(bool prctl_supported) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(!prctl_detected_);

prctl_detected_ = true;

UMA_HISTOGRAM_ENUMERATION("Android.SeccompStatus.Prctl",
prctl_supported ? SUPPORTED : NOT_SUPPORTED,
LAST_STATUS);
}

void SeccompSupportDetector::OnDetectSyscall(bool syscall_supported) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(prctl_detected_);

UMA_HISTOGRAM_ENUMERATION("Android.SeccompStatus.Syscall",
syscall_supported ? SUPPORTED : NOT_SUPPORTED,
LAST_STATUS);

// The utility process will shutdown after this, and this object will
// be deleted when the UtilityProcessHost releases its reference.
}
46 changes: 46 additions & 0 deletions chrome/browser/android/seccomp_support_detector.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2015 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.

#ifndef CHROME_BROWSER_ANDROID_SECCOMP_SUPPORT_DETECTOR_H_
#define CHROME_BROWSER_ANDROID_SECCOMP_SUPPORT_DETECTOR_H_

#include "base/compiler_specific.h"
#include "content/public/browser/utility_process_host_client.h"

// This class is used to report via UMA the Android kernel version and
// level of seccomp-bpf support. The kernel version is read from the blocking
// thread pool, while seccomp support is tested in a utility process, in case
// the probing causes a crash.
class SeccompSupportDetector : public content::UtilityProcessHostClient {
public:
// Starts the detection process. This should be called once per browser
// session. This is safe to call from any thread.
static void StartDetection();

private:
SeccompSupportDetector();
~SeccompSupportDetector() override;

// Called on the blocking thread pool. This reads the utsname and records
// the kernel version.
void DetectKernelVersion();

// Called on the IO thread. This starts a utility process to detect seccomp.
void DetectSeccomp();

// UtilityProcessHostClient:
void OnProcessCrashed(int exit_code) override;
bool OnMessageReceived(const IPC::Message& message) override;

// OnDetectPrctl is always received before OnDetectSyscall.
void OnDetectPrctl(bool prctl_supported);
void OnDetectSyscall(bool syscall_supported);

// Whether OnDetectPrctl was received.
bool prctl_detected_;

DISALLOW_COPY_AND_ASSIGN(SeccompSupportDetector);
};

#endif // CHROME_BROWSER_ANDROID_SECCOMP_SUPPORT_DETECTOR_H_
10 changes: 10 additions & 0 deletions chrome/browser/chrome_browser_main_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "base/command_line.h"
#include "base/path_service.h"
#include "base/trace_event/trace_event.h"
#include "chrome/browser/android/seccomp_support_detector.h"
#include "chrome/browser/google/google_search_counter_android.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/common/chrome_paths.h"
Expand All @@ -15,6 +16,7 @@
#include "components/crash/browser/crash_dump_manager_android.h"
#include "components/signin/core/browser/signin_manager.h"
#include "content/public/browser/android/compositor.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/main_function_params.h"
#include "net/android/network_change_notifier_factory_android.h"
#include "net/base/network_change_notifier.h"
Expand Down Expand Up @@ -94,6 +96,14 @@ void ChromeBrowserMainPartsAndroid::PreEarlyInitialization() {
ChromeBrowserMainParts::PreEarlyInitialization();
}

void ChromeBrowserMainPartsAndroid::PostBrowserStart() {
ChromeBrowserMainParts::PostBrowserStart();

content::BrowserThread::GetBlockingPool()->PostDelayedTask(FROM_HERE,
base::Bind(&SeccompSupportDetector::StartDetection),
base::TimeDelta::FromMinutes(1));
}

void ChromeBrowserMainPartsAndroid::ShowMissingLocaleMessageBox() {
NOTREACHED();
}
1 change: 1 addition & 0 deletions chrome/browser/chrome_browser_main_android.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class ChromeBrowserMainPartsAndroid : public ChromeBrowserMainParts {
void PreEarlyInitialization() override;

// ChromeBrowserMainParts overrides.
void PostBrowserStart() override;
void ShowMissingLocaleMessageBox() override;

private:
Expand Down
7 changes: 7 additions & 0 deletions chrome/chrome_browser.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@
'browser/android/resource_id.h',
'browser/android/resource_mapper.cc',
'browser/android/resource_mapper.h',
'browser/android/seccomp_support_detector.cc',
'browser/android/seccomp_support_detector.h',
'browser/android/service_tab_launcher.cc',
'browser/android/service_tab_launcher.h',
'browser/android/shortcut_helper.cc',
Expand Down Expand Up @@ -3427,6 +3429,11 @@
],
'sources': [ '<@(chrome_browser_android_sources)' ],
'defines': [ 'ENABLE_DATA_REDUCTION_PROXY_DEBUGGING' ],
'conditions': [
['use_seccomp_bpf==1', {
'defines': ['USE_SECCOMP_BPF'],
}],
],
}],
['OS=="mac"', {
'dependencies': [
Expand Down
6 changes: 6 additions & 0 deletions chrome/chrome_utility.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@
'<@(chrome_utility_importer_sources)',
],
}],
['OS=="android" and use_seccomp_bpf==1', {
'dependencies': [
'../sandbox/sandbox.gyp:seccomp_bpf',
],
'defines': ['USE_SECCOMP_BPF'],
}],
['enable_extensions==1', {
'dependencies': [
'../extensions/extensions.gyp:extensions_utility',
Expand Down
16 changes: 16 additions & 0 deletions chrome/common/chrome_utility_messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,13 @@ IPC_MESSAGE_CONTROL1(ChromeUtilityMsg_GetSaveFileName,
ChromeUtilityMsg_GetSaveFileName_Params /* params */)
#endif // defined(OS_WIN)

#if defined(OS_ANDROID)
// Instructs the utility process to detect support for seccomp-bpf,
// and the result is reported through
// ChromeUtilityHostMsg_DetectSeccompSupport_Result.
IPC_MESSAGE_CONTROL0(ChromeUtilityMsg_DetectSeccompSupport)
#endif

//------------------------------------------------------------------------------
// Utility process host messages:
// These are messages from the utility process to the browser.
Expand Down Expand Up @@ -200,3 +207,12 @@ IPC_MESSAGE_CONTROL2(ChromeUtilityHostMsg_GetSaveFileName_Result,
IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_BuildDirectWriteFontCache,
base::FilePath /* cache file path */)
#endif // defined(OS_WIN)

#if defined(OS_ANDROID)
// Reply to ChromeUtilityMsg_DetectSeccompSupport to report the level
// of kernel support for seccomp-bpf.
IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_DetectSeccompSupport_ResultPrctl,
bool /* seccomp prctl supported */)
IPC_MESSAGE_CONTROL1(ChromeUtilityHostMsg_DetectSeccompSupport_ResultSyscall,
bool /* seccomp syscall supported */)
#endif
7 changes: 6 additions & 1 deletion chrome/utility/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ static_library("utility") {
"//chrome/common",
]

if (!is_android) {
if (is_android) {
if (use_seccomp_bpf) {
deps += [ "//sandbox/linux:seccomp_bpf" ]
defines += [ "USE_SECCOMP_BPF" ]
}
} else {
deps += [ "//net:net_utility_services" ]
sources +=
rebase_path(gypi_values.chrome_utility_importer_sources, ".", "..")
Expand Down
1 change: 1 addition & 0 deletions chrome/utility/DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ include_rules = [
"+components/wifi",
"+courgette",
"+extensions/common",
"+sandbox/linux/seccomp-bpf/sandbox_bpf.h",
"+skia/ext",
"+media",
"+third_party/zlib/google",
Expand Down
24 changes: 24 additions & 0 deletions chrome/utility/chrome_content_utility_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
#include "net/proxy/mojo_proxy_resolver_factory_impl.h"
#endif

#if defined(OS_ANDROID) && defined(USE_SECCOMP_BPF)
#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h"
#endif

#if defined(OS_WIN)
#include "chrome/utility/font_cache_handler_win.h"
#include "chrome/utility/shell_handler_win.h"
Expand Down Expand Up @@ -161,6 +165,10 @@ bool ChromeContentUtilityClient::OnMessageReceived(
#endif
#if defined(OS_CHROMEOS)
IPC_MESSAGE_HANDLER(ChromeUtilityMsg_CreateZipFile, OnCreateZipFile)
#endif
#if defined(OS_ANDROID) && defined(USE_SECCOMP_BPF)
IPC_MESSAGE_HANDLER(ChromeUtilityMsg_DetectSeccompSupport,
OnDetectSeccompSupport)
#endif
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
Expand Down Expand Up @@ -277,6 +285,22 @@ void ChromeContentUtilityClient::OnCreateZipFile(
}
#endif // defined(OS_CHROMEOS)

#if defined(OS_ANDROID) && defined(USE_SECCOMP_BPF)
void ChromeContentUtilityClient::OnDetectSeccompSupport() {
bool supports_prctl = sandbox::SandboxBPF::SupportsSeccompSandbox(
sandbox::SandboxBPF::SeccompLevel::SINGLE_THREADED);
Send(new ChromeUtilityHostMsg_DetectSeccompSupport_ResultPrctl(
supports_prctl));

bool supports_syscall = sandbox::SandboxBPF::SupportsSeccompSandbox(
sandbox::SandboxBPF::SeccompLevel::MULTI_THREADED);
Send(new ChromeUtilityHostMsg_DetectSeccompSupport_ResultSyscall(
supports_syscall));

ReleaseProcessIfNeeded();
}
#endif // defined(OS_ANDROID) && defined(USE_SECCOMP_BPF)

void ChromeContentUtilityClient::OnRobustJPEGDecodeImage(
const std::vector<unsigned char>& encoded_data) {
// Our robust jpeg decoding is using IJG libjpeg.
Expand Down
4 changes: 4 additions & 0 deletions chrome/utility/chrome_content_utility_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ class ChromeContentUtilityClient : public content::ContentUtilityClient {
const base::FileDescriptor& dest_fd);
#endif // defined(OS_CHROMEOS)

#if defined(OS_ANDROID) && defined(USE_SECCOMP_BPF)
void OnDetectSeccompSupport();
#endif

void OnParseJSON(const std::string& json);
void OnPatchFileBsdiff(const base::FilePath& input_file,
const base::FilePath& patch_file,
Expand Down

0 comments on commit e59ea89

Please sign in to comment.