// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// <if expr="is_linux or is_chromeos">
import './strings.m.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
// </if>
import {getRequiredElement} from 'chrome://resources/js/util.js';
/**
* CSS classes for different statuses.
*/
enum StatusClass {
GOOD = 'good',
BAD = 'bad',
MEDIUM = 'medium',
INFO = 'info',
}
/**
* Adds a row to the sandbox status table.
* @param name The name of the status item.
* @param value The status of the item.
* @param cssClass A CSS class to apply to the row.
* @return The newly added TR.
*/
function addStatusRow(
name: string, value: string, cssClass: StatusClass|null): HTMLElement {
const row = document.createElement('tr');
const nameCol = row.appendChild(document.createElement('td'));
const valueCol = row.appendChild(document.createElement('td'));
nameCol.textContent = name;
valueCol.textContent = value;
if (cssClass != null) {
nameCol.classList.add(cssClass);
valueCol.classList.add(cssClass);
}
getRequiredElement('sandbox-status').appendChild(row);
return row;
}
/**
* Reports the overall sandbox status evaluation message.
*/
function setEvaluation(result: boolean) {
const message = result ? 'You are adequately sandboxed.' :
'You are NOT adequately sandboxed.';
getRequiredElement('evaluation').innerText = message;
}
// <if expr="is_android">
/**
* Main page handler for Android.
*/
function androidHandler() {
chrome.getAndroidSandboxStatus(status => {
let isIsolated = false;
let isTsync = false;
let isChromeSeccomp = false;
addStatusRow('PID', status.pid, StatusClass.INFO);
addStatusRow('UID', status.uid, StatusClass.INFO);
isIsolated = status.secontext.indexOf(':isolated_app:') !== -1;
addStatusRow(
'SELinux Context', status.secontext,
isIsolated ? StatusClass.GOOD : StatusClass.BAD);
const procStatus = status.procStatus.split('\n');
for (const line of procStatus) {
if (line.startsWith('Seccomp')) {
let value = line.split(':')[1]!.trim();
let cssClass = StatusClass.BAD;
if (value === '2') {
value = 'Yes - TSYNC (' + line + ')';
cssClass = StatusClass.GOOD;
isTsync = true;
} else if (value === '1') {
value = 'Yes (' + line + ')';
} else {
value = line;
}
addStatusRow('Seccomp-BPF Enabled (Kernel)', value, cssClass);
break;
}
}
let seccompStatus = 'Unknown';
switch (status.seccompStatus) {
case 0:
seccompStatus = 'Not Supported';
break;
case 1:
seccompStatus = 'Run-time Detection Failed';
break;
case 2:
seccompStatus = 'Disabled by Field Trial';
break;
case 3:
seccompStatus = 'Enabled by Field Trial (not started)';
break;
case 4:
seccompStatus = 'Sandbox Started';
isChromeSeccomp = true;
break;
}
addStatusRow(
'Seccomp-BPF Enabled (Chrome)', seccompStatus,
status.seccompStatus === 4 ? StatusClass.GOOD : StatusClass.BAD);
addStatusRow('Android Build ID', status.androidBuildId, StatusClass.INFO);
setEvaluation(isIsolated && isTsync && isChromeSeccomp);
});
}
// </if>
// <if expr="is_linux or is_chromeos">
/**
* Adds a status row that reports either Yes or No.
* @param name The name of the status item.
* @param result The status (good/bad) result.
* @return The newly added TR.
*/
function addGoodBadRow(name: string, result: boolean): HTMLElement {
return addStatusRow(
name, result ? 'Yes' : 'No', result ? StatusClass.GOOD : StatusClass.BAD);
}
/**
* Main page handler for desktop Linux.
*/
function linuxHandler() {
const suidSandbox = loadTimeData.getBoolean('suid');
const 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('Network namespaces', loadTimeData.getBoolean('netNs'));
addGoodBadRow('Seccomp-BPF sandbox', loadTimeData.getBoolean('seccompBpf'));
addGoodBadRow(
'Seccomp-BPF sandbox supports TSYNC',
loadTimeData.getBoolean('seccompTsync'));
const enforcingYamaBroker = loadTimeData.getBoolean('yamaBroker');
addGoodBadRow(
'Ptrace Protection with Yama LSM (Broker)', enforcingYamaBroker);
const 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.
const 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'));
}
// </if>
document.addEventListener('DOMContentLoaded', () => {
// <if expr="is_android">
androidHandler();
// </if>
// <if expr="is_linux or is_chromeos">
linuxHandler();
// </if>
});