Commit e59ea892 authored by rsesek's avatar rsesek Committed by Commit bot

Add SeccompSupportDetector for Android.

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}
parent 2de0b55d
......@@ -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) {
......
// 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.
}
// 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_
......@@ -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"
......@@ -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"
......@@ -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();
}
......@@ -25,6 +25,7 @@ class ChromeBrowserMainPartsAndroid : public ChromeBrowserMainParts {
void PreEarlyInitialization() override;
// ChromeBrowserMainParts overrides.
void PostBrowserStart() override;
void ShowMissingLocaleMessageBox() override;
private:
......
......@@ -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',
......@@ -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': [
......
......@@ -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',
......
......@@ -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.
......@@ -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
......@@ -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, ".", "..")
......
......@@ -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",
......
......@@ -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"
......@@ -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()
......@@ -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.
......
......@@ -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,
......
......@@ -247,6 +247,32 @@ Therefore, the affected-histogram name has to have at least one dot in it.
</summary>
</histogram>
<histogram name="Android.KernelVersion" enum="AndroidKernelVersion">
<owner>rsesek@chromium.org</owner>
<summary>
Reports the kernel major and minor version from the utsname.release field.
The low 16 bits of each version are combined into a 32-bit integer. The
range is from [0x00020006,0x0004000a] to track kernel versions 2.6 through
4.10.
</summary>
</histogram>
<histogram name="Android.SeccompStatus.Prctl" enum="AndroidSeccompStatus">
<owner>rsesek@chromium.org</owner>
<summary>
Reports the level of kernel support for the seccomp-bpf sandbox using
prctl(PR_SET_SECCOMP).
</summary>
</histogram>
<histogram name="Android.SeccompStatus.Syscall" enum="AndroidSeccompStatus">
<owner>rsesek@chromium.org</owner>
<summary>
Reports the level of kernel support for the seccomp-bpf sandbox using the
seccomp system call.
</summary>
</histogram>
<histogram name="AndroidTabCloseUndo.Toast"
enum="AndroidTabCloseUndoToastEvent">
<owner>dtrainor@chromium.org</owner>
......@@ -44292,6 +44318,22 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="4" label="EvictAll"/>
</enum>
<enum name="AndroidKernelVersion" type="int">
<int value="131078" label="2.6"/>
<int value="196608" label="3.0"/>
<int value="196611" label="3.3"/>
<int value="196612" label="3.4"/>
<int value="196616" label="3.8"/>
<int value="196618" label="3.10"/>
<int value="196622" label="3.14"/>
<int value="196625" label="3.17"/>
<int value="196626" label="3.18"/>
<int value="196627" label="3.19"/>
<int value="262144" label="4.0"/>
<int value="262145" label="4.01"/>
<int value="262154" label="4.10"/>
</enum>
<enum name="AndroidMemoryNotificationBackground" type="int">
<int value="0" label="TrimMemoryUiHidden"/>
<int value="1" label="TrimMemoryBackground"/>
......@@ -44306,6 +44348,12 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<int value="3" label="LowMemory"/>
</enum>
<enum name="AndroidSeccompStatus" type="int">
<int value="0" label="Detection Failed"/>
<int value="1" label="Not Supported"/>
<int value="2" label="Supported"/>
</enum>
<enum name="AndroidSigninPromoAction" type="int">
<int value="0" label="Promo enabled">
The Android signin promo was enabled to show on next startup.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment