Commit d267fd99 authored by Matthew Denton's avatar Matthew Denton Committed by Commit Bot

Modified chrome://sandbox to more accurately describe sandboxing

Originally the chrome://sandbox page displayed "SUID Sandbox" as red
when the SUID sandbox was off, even if the namespace sandbox was on. To
avoid indicating that anything is wrong, this combines "SUID Sandbox"
and "Namespace Sandbox" into one row that displays green for namespace,
yellow for SUID, and red for neither.

Also, when the Chrome renderers are sandboxed with user namespaces,
any process in the parent namespace with the same UID is able to
ptrace the renderer. However, the chrome://sandbox page displays Yama
LSM as enforcing. This makes it clear that Yama LSM is not protecting
the renderer processes from ptrace by adding "Ptrace Protection with
Yama LSM (Non-broker)" to the webpage.

start chrome with all three sandboxing possibilities, run
./browser_tests --gtest_filter="Sandbox*"

Bug: 870527, 870534
Test: start chrome with Yama disabled, enabled, and with SetUID sandbox,
Change-Id: I2e4735363a4dceee4947757a74451e3e102c4250
Reviewed-on: https://chromium-review.googlesource.com/1162764
Commit-Queue: Matthew Denton <mpdenton@chromium.org>
Reviewed-by: default avatarMichael Giuffrida <michaelpg@chromium.org>
Reviewed-by: default avatarChris Palmer <palmer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#581656}
parent 24e5fbf1
...@@ -22,6 +22,9 @@ ...@@ -22,6 +22,9 @@
.bad { .bad {
background-color: rgb(249, 156, 149); background-color: rgb(249, 156, 149);
} }
.medium {
background-color: rgb(255, 255, 90);
}
.info { .info {
background-color: rgb(169, 217, 239); background-color: rgb(169, 217, 239);
} }
......
...@@ -3,9 +3,16 @@ ...@@ -3,9 +3,16 @@
// found in the LICENSE file. // found in the LICENSE file.
(function() { (function() {
let GOOD = 'good'; /**
let BAD = 'bad'; * CSS classes for different statuses.
let INFO = 'info'; * @enum {string}
*/
const StatusClass = {
GOOD: 'good',
BAD: 'bad',
MEDIUM: 'medium',
INFO: 'info'
};
/** /**
* Adds a row to the sandbox status table. * Adds a row to the sandbox status table.
...@@ -39,7 +46,8 @@ function addStatusRow(name, value, cssClass) { ...@@ -39,7 +46,8 @@ function addStatusRow(name, value, cssClass) {
* @return {Element} The newly added TR. * @return {Element} The newly added TR.
*/ */
function addGoodBadRow(name, result) { function addGoodBadRow(name, result) {
return addStatusRow(name, result ? 'Yes' : 'No', result ? GOOD : BAD); return addStatusRow(
name, result ? 'Yes' : 'No', result ? StatusClass.GOOD : StatusClass.BAD);
} }
/** /**
...@@ -61,19 +69,21 @@ function androidHandler() { ...@@ -61,19 +69,21 @@ function androidHandler() {
var isTsync = false; var isTsync = false;
var isChromeSeccomp = false; var isChromeSeccomp = false;
addStatusRow('PID', status.pid, INFO); addStatusRow('PID', status.pid, StatusClass.INFO);
addStatusRow('UID', status.uid, INFO); addStatusRow('UID', status.uid, StatusClass.INFO);
isIsolated = status.secontext.indexOf(':isolated_app:') != -1; isIsolated = status.secontext.indexOf(':isolated_app:') != -1;
addStatusRow('SELinux Context', status.secontext, isIsolated ? GOOD : BAD); addStatusRow(
'SELinux Context', status.secontext,
isIsolated ? StatusClass.GOOD : StatusClass.BAD);
let procStatus = status.procStatus.split('\n'); let procStatus = status.procStatus.split('\n');
for (let line of procStatus) { for (let line of procStatus) {
if (line.startsWith('Seccomp')) { if (line.startsWith('Seccomp')) {
var value = line.split(':')[1].trim(); var value = line.split(':')[1].trim();
var cssClass = BAD; var cssClass = StatusClass.BAD;
if (value == '2') { if (value == '2') {
value = 'Yes - TSYNC (' + line + ')'; value = 'Yes - TSYNC (' + line + ')';
cssClass = GOOD; cssClass = StatusClass.GOOD;
isTsync = true; isTsync = true;
} else if (value == '1') { } else if (value == '1') {
value = 'Yes (' + line + ')'; value = 'Yes (' + line + ')';
...@@ -106,9 +116,9 @@ function androidHandler() { ...@@ -106,9 +116,9 @@ function androidHandler() {
} }
addStatusRow( addStatusRow(
'Seccomp-BPF Enabled (Chrome)', seccompStatus, 'Seccomp-BPF Enabled (Chrome)', seccompStatus,
status.seccompStatus == 4 ? GOOD : BAD); status.seccompStatus == 4 ? StatusClass.GOOD : StatusClass.BAD);
addStatusRow('Android Build ID', status.androidBuildId, INFO); addStatusRow('Android Build ID', status.androidBuildId, StatusClass.INFO);
setEvaluation(isIsolated && isTsync && isChromeSeccomp); setEvaluation(isIsolated && isTsync && isChromeSeccomp);
}); });
...@@ -118,15 +128,42 @@ function androidHandler() { ...@@ -118,15 +128,42 @@ function androidHandler() {
* Main page handler for desktop Linux. * Main page handler for desktop Linux.
*/ */
function linuxHandler() { function linuxHandler() {
addGoodBadRow('SUID Sandbox', loadTimeData.getBoolean('suid')); let suidSandbox = loadTimeData.getBoolean('suid');
addGoodBadRow('Namespace Sandbox', loadTimeData.getBoolean('userNs')); let nsSandbox = loadTimeData.getBoolean('userNs');
let layer1SandboxType = 'None';
let layer1SandboxCssClass = StatusClass.BAD;
if (suidSandbox) {
layer1SandboxType = 'SUID';
layer1SandboxCssClass = StatusClass.MEDIUM;
} else if (nsSandbox) {
layer1SandboxType = 'Namespace';
layer1SandboxCssClass = StatusClass.GOOD;
}
addStatusRow('Layer 1 Sandbox', layer1SandboxType, layer1SandboxCssClass);
addGoodBadRow('PID namespaces', loadTimeData.getBoolean('pidNs')); addGoodBadRow('PID namespaces', loadTimeData.getBoolean('pidNs'));
addGoodBadRow('Network namespaces', loadTimeData.getBoolean('netNs')); addGoodBadRow('Network namespaces', loadTimeData.getBoolean('netNs'));
addGoodBadRow('Seccomp-BPF sandbox', loadTimeData.getBoolean('seccompBpf')); addGoodBadRow('Seccomp-BPF sandbox', loadTimeData.getBoolean('seccompBpf'));
addGoodBadRow( addGoodBadRow(
'Seccomp-BPF sandbox supports TSYNC', 'Seccomp-BPF sandbox supports TSYNC',
loadTimeData.getBoolean('seccompTsync')); loadTimeData.getBoolean('seccompTsync'));
addGoodBadRow('Yama LSM Enforcing', loadTimeData.getBoolean('yama'));
let enforcingYamaBroker = loadTimeData.getBoolean('yamaBroker');
addGoodBadRow(
'Ptrace Protection with Yama LSM (Broker)', enforcingYamaBroker);
let enforcingYamaNonbroker = loadTimeData.getBoolean('yamaNonbroker');
// If there is no ptrace protection anywhere, that is bad.
// If there is no ptrace protection for nonbroker processes because of the
// user namespace sandbox, that is fine and we display as medium.
let yamaNonbrokerCssClass = enforcingYamaBroker ?
(enforcingYamaNonbroker ? StatusClass.GOOD : StatusClass.MEDIUM) :
StatusClass.BAD;
addStatusRow(
'Ptrace Protection with Yama LSM (Non-broker)',
enforcingYamaNonbroker ? 'Yes' : 'No', yamaNonbrokerCssClass);
setEvaluation(loadTimeData.getBoolean('sandboxGood')); setEvaluation(loadTimeData.getBoolean('sandboxGood'));
} }
......
...@@ -41,7 +41,14 @@ static void SetSandboxStatusData(content::WebUIDataSource* source) { ...@@ -41,7 +41,14 @@ static void SetSandboxStatusData(content::WebUIDataSource* source) {
status & service_manager::SandboxLinux::kSeccompBPF); status & service_manager::SandboxLinux::kSeccompBPF);
source->AddBoolean("seccompTsync", source->AddBoolean("seccompTsync",
status & service_manager::SandboxLinux::kSeccompTSYNC); status & service_manager::SandboxLinux::kSeccompTSYNC);
source->AddBoolean("yama", status & service_manager::SandboxLinux::kYama); source->AddBoolean("yamaBroker",
status & service_manager::SandboxLinux::kYama);
// Yama does not enforce in user namespaces.
bool enforcing_yama_nonbroker =
status & service_manager::SandboxLinux::kYama &&
!(status & service_manager::SandboxLinux::kUserNS);
source->AddBoolean("yamaNonbroker", enforcing_yama_nonbroker);
// Require either the setuid or namespace sandbox for our first-layer sandbox. // Require either the setuid or namespace sandbox for our first-layer sandbox.
bool good_layer1 = (status & service_manager::SandboxLinux::kSUID || bool good_layer1 = (status & service_manager::SandboxLinux::kSUID ||
......
...@@ -39,29 +39,15 @@ GEN('#endif'); ...@@ -39,29 +39,15 @@ GEN('#endif');
TEST_F( TEST_F(
'SandboxStatusUITest', 'MAYBE_testSUIDorNamespaceSandboxEnabled', 'SandboxStatusUITest', 'MAYBE_testSUIDorNamespaceSandboxEnabled',
function() { function() {
var namespaceyesstring = 'Namespace Sandbox\tYes'; var sandboxnamespacestring = 'Layer 1 Sandbox\tNamespace';
var namespacenostring = 'Namespace Sandbox\tNo'; var sandboxsuidstring = 'Layer 1 Sandbox\tSUID';
var suidyesstring = 'SUID Sandbox\tYes';
var suidnostring = 'SUID Sandbox\tNo';
var suidyes = document.body.innerText.match(suidyesstring); var namespaceyes = document.body.innerText.match(sandboxnamespacestring);
var suidno = document.body.innerText.match(suidnostring); var suidyes = document.body.innerText.match(sandboxsuidstring);
var namespaceyes = document.body.innerText.match(namespaceyesstring);
var namespaceno = document.body.innerText.match(namespacenostring);
// Exactly one of the namespace or suid sandbox should be enabled. // Exactly one of the namespace or suid sandbox should be enabled.
expectTrue(suidyes !== null || namespaceyes !== null); expectTrue(suidyes !== null || namespaceyes !== null);
expectFalse(suidyes !== null && namespaceyes !== null); expectFalse(suidyes !== null && namespaceyes !== null);
if (namespaceyes !== null) {
expectEquals(null, namespaceno);
expectEquals(namespaceyesstring, namespaceyes[0]);
}
if (suidyes !== null) {
expectEquals(null, suidno);
expectEquals(suidyesstring, suidyes[0]);
}
}); });
// The seccomp-bpf sandbox is also not compatible with ASAN. // The seccomp-bpf sandbox is also not compatible with ASAN.
......
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