Commit 051090c6 authored by Alex Gough's avatar Alex Gough Committed by Commit Bot

Add expansion of platform mitigations to chrome://sandbox

This takes the values returned as base::Value from the sandbox
policy and allows them to be expanded in the summary display of
chrome://sandbox.

Expansion is deferred as the page can become slow in debug builds if
it is performed every time, and expanded values are not always
required for debugging.

Bug: 1115305
Change-Id: I96d71b21ccc28e678fdb3fb9714f30cf88b730ef
Tests: manual testing on Win7 x86 and Win10 10.0.18362
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2350331Reviewed-by: default avatarWill Harris <wfh@chromium.org>
Reviewed-by: default avatarMichael Giuffrida <michaelpg@chromium.org>
Commit-Queue: Alex Gough <ajgo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#797783}
parent 9bedb05b
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#sandbox-status td { #sandbox-status td {
border: 1px solid gray; border: 1px solid gray;
padding: 3px; padding: 3px;
vertical-align: top;
} }
#evaluation { #evaluation {
font-weight: bold; font-weight: bold;
...@@ -28,6 +29,16 @@ ...@@ -28,6 +29,16 @@
.info { .info {
background-color: rgb(169, 217, 239); background-color: rgb(169, 217, 239);
} }
<if expr="is_win">
.expander {
display: inline;
padding-right: 1em;
}
.mitigations {
display: inline;
font-family: monospace;
}
</if>
</style> </style>
<script src="chrome://resources/js/cr.js"></script> <script src="chrome://resources/js/cr.js"></script>
<if expr="is_linux"> <if expr="is_linux">
......
...@@ -41,19 +41,313 @@ let PolicyDiagnostic; ...@@ -41,19 +41,313 @@ let PolicyDiagnostic;
*/ */
let SandboxDiagnostics; let SandboxDiagnostics;
/**
* Represents a mitigation field from the PROCESS_CREATION_MITITAGION_POLICY*
* series in Winbase.h.
* @typedef {{
* mitigation: !string,
* value: !number,
* mask: !number,
* offset: !number
* }}
*/
class MitigationField {
/**
* mask & value must be 0<=x<=255.
* @param {string} mitigation human name of mitigation.
* @param {number} value value to match within mask.
* @param {number} mask applied before matching.
* @param {number} offset within PC section.
*/
constructor(mitigation, value, mask, offset) {
this.mitigation = mitigation;
this.value = value;
this.mask = mask;
this.offset = offset;
}
/**
* Each PC field overrides this as they know where their data is.
* @param {Uint8Array} platform mitigations data.
* @return {Uint8Array} chunk containing this field or null.
*/
getFieldData(bytes) {
assertNotReached();
}
/**
* Are all the bits of this field set in the mitigations represented by
* |bytes|.
* @param {Uint8Array} platform mitigations.
* @return {boolean}
*/
isFieldSet(bytes) {
if (bytes.length != 4 && bytes.length != 8 && bytes.length != 16) {
throw ('Platform mitigations has unexpected size');
}
const subfield = this.getFieldData(bytes);
if (subfield == null || this.offset > subfield.length * 8) {
return false;
}
const idx = subfield.length - 1 - Math.floor(this.offset / 8);
const ibit = this.offset % 8;
return (subfield[idx] & (this.mask << ibit)) == (this.value << ibit);
}
}
/**
* PROCESS_CREATION_MITIGATION_POLICY legacy bits.
*/
class PC0Field extends MitigationField {
/**
* @param {Uint8Array} platform mitigations data.
* @return {Uint8Array} chunk containing this field or null.
*/
getFieldData(bytes) {
if (bytes.length == 4) {
// Win32 only 4 bytes of fields.
return bytes;
} else if (bytes.length == 8) {
return bytes;
} else {
return bytes.slice(0, 8);
}
}
}
/**
* PROCESS_CREATION_MITIGATION_POLICY_*
*/
class PC1Field extends MitigationField {
/** @override */
getFieldData(bytes) {
if (bytes.length == 4) {
return null;
} else if (bytes.length == 8) {
return bytes;
} else if (bytes.length == 16) {
return bytes.slice(0, 8);
}
}
}
/**
* PROCESS_CREATION_MITIGATION_POLICY2_*
*/
class PC2Field extends MitigationField {
/** @override */
getFieldData(bytes) {
if (bytes.length == 4) {
return null;
} else if (bytes.length == 8) {
return null;
} else if (bytes.length == 16) {
return bytes.slice(8, 16);
}
}
}
/**
* Helper to show enabled mitigations from a stringified hex
representation of PROCESS_CREATION_MITIGATION_POLICY_* entries.
*/
class DecodeMitigations {
constructor() {
/* @typedef {{Array<MitigationField>}} */
this.fields = [
// Defined in Windows.h from Winbase.h
// basic (pc0) mitigations in {win7},{lsb of pc1}.
new PC0Field('DEP_ENABLE', 0x1, 0x01, 0),
new PC0Field('DEP_ATL_THUNK_ENABLE', 0x2, 0x02, 0),
new PC0Field('SEHOP_ENABLE', 0x4, 0x04, 0),
// pc1 mitigations in {lsb of pc1}.
new PC1Field('FORCE_RELOCATE_IMAGES', 0x1, 0x03, 8),
new PC1Field('FORCE_RELOCATE_IMAGES_ALWAYS_OFF', 0x2, 0x03, 8),
new PC1Field('FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS', 0x3, 0x03, 8),
new PC1Field('HEAP_TERMINATE', 0x1, 0x03, 12),
new PC1Field('HEAP_TERMINATE_ALWAYS_OFF', 0x2, 0x03, 12),
new PC1Field('HEAP_TERMINATE_RESERVED', 0x3, 0x03, 12),
new PC1Field('BOTTOM_UP_ASLR', 0x1, 0x03, 16),
new PC1Field('BOTTOM_UP_ASLR_ALWAYS_OFF', 0x2, 0x03, 16),
new PC1Field('BOTTOM_UP_ASLR_RESERVED', 0x3, 0x03, 16),
new PC1Field('HIGH_ENTROPY_ASLR', 0x1, 0x03, 20),
new PC1Field('HIGH_ENTROPY_ASLR_ALWAYS_OFF', 0x2, 0x03, 20),
new PC1Field('HIGH_ENTROPY_ASLR_RESERVED', 0x3, 0x03, 20),
new PC1Field('STRICT_HANDLE_CHECKS', 0x1, 0x03, 24),
new PC1Field('STRICT_HANDLE_CHECKS_ALWAYS_OFF', 0x2, 0x03, 24),
new PC1Field('STRICT_HANDLE_CHECKS_RESERVED', 0x3, 0x03, 24),
new PC1Field('WIN32K_SYSTEM_CALL_DISABLE', 0x1, 0x03, 28),
new PC1Field('WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_OFF', 0x2, 0x03, 28),
new PC1Field('WIN32K_SYSTEM_CALL_DISABLE_RESERVED', 0x3, 0x03, 28),
new PC1Field('EXTENSION_POINT_DISABLE', 0x1, 0x03, 32),
new PC1Field('EXTENSION_POINT_DISABLE_ALWAYS_OFF', 0x2, 0x03, 32),
new PC1Field('EXTENSION_POINT_DISABLE_RESERVED', 0x3, 0x03, 32),
new PC1Field('PROHIBIT_DYNAMIC_CODE', 0x1, 0x03, 36),
new PC1Field('PROHIBIT_DYNAMIC_CODE_ALWAYS_OFF', 0x2, 0x03, 36),
new PC1Field(
'PROHIBIT_DYNAMIC_CODE_ALWAYS_ON_ALLOW_OPT_OUT', 0x3, 0x03, 36),
new PC1Field('CONTROL_FLOW_GUARD', 0x1, 0x03, 40),
new PC1Field('CONTROL_FLOW_GUARD_ALWAYS_OFF', 0x2, 0x03, 40),
new PC1Field('CONTROL_FLOW_GUARD_EXPORT_SUPPRESSION', 0x3, 0x03, 40),
new PC1Field('BLOCK_NON_MICROSOFT_BINARIES', 0x1, 0x03, 44),
new PC1Field('BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_OFF', 0x2, 0x03, 44),
new PC1Field('BLOCK_NON_MICROSOFT_BINARIES_ALLOW_STORE', 0x3, 0x03, 44),
new PC1Field('FONT_DISABLE', 0x1, 0x03, 48),
new PC1Field('FONT_DISABLE_ALWAYS_OFF', 0x2, 0x03, 48),
new PC1Field('AUDIT_NONSYSTEM_FONTS', 0x3, 0x03, 48),
new PC1Field('IMAGE_LOAD_NO_REMOTE', 0x1, 0x03, 52),
new PC1Field('IMAGE_LOAD_NO_REMOTE_ALWAYS_OFF', 0x2, 0x03, 52),
new PC1Field('IMAGE_LOAD_NO_REMOTE_RESERVED', 0x3, 0x03, 52),
new PC1Field('IMAGE_LOAD_NO_LOW_LABEL', 0x1, 0x03, 56),
new PC1Field('IMAGE_LOAD_NO_LOW_LABEL_ALWAYS_OFF', 0x2, 0x03, 56),
new PC1Field('IMAGE_LOAD_NO_LOW_LABEL_RESERVED', 0x3, 0x03, 56),
new PC1Field('IMAGE_LOAD_PREFER_SYSTEM32', 0x1, 0x03, 60),
new PC1Field('IMAGE_LOAD_PREFER_SYSTEM32_ALWAYS_OFF', 0x2, 0x03, 60),
new PC1Field('IMAGE_LOAD_PREFER_SYSTEM32_RESERVED', 0x3, 0x03, 60),
// pc2: in second 64bit block only.
new PC2Field('LOADER_INTEGRITY_CONTINUITY', 0x1, 0x03, 4),
new PC2Field('LOADER_INTEGRITY_CONTINUITY_ALWAYS_OFF', 0x2, 0x03, 4),
new PC2Field('LOADER_INTEGRITY_CONTINUITY_AUDIT', 0x3, 0x03, 4),
new PC2Field('STRICT_CONTROL_FLOW_GUARD', 0x1, 0x03, 8),
new PC2Field('STRICT_CONTROL_FLOW_GUARD_ALWAYS_OFF', 0x2, 0x03, 8),
new PC2Field('STRICT_CONTROL_FLOW_GUARD_RESERVED', 0x3, 0x03, 8),
new PC2Field('MODULE_TAMPERING_PROTECTION', 0x1, 0x03, 12),
new PC2Field('MODULE_TAMPERING_PROTECTION_ALWAYS_OFF', 0x2, 0x03, 12),
new PC2Field('MODULE_TAMPERING_PROTECTION_NOINHERIT', 0x3, 0x03, 12),
new PC2Field('RESTRICT_INDIRECT_BRANCH_PREDICTION', 0x1, 0x03, 16),
new PC2Field(
'RESTRICT_INDIRECT_BRANCH_PREDICTION_ALWAYS_OFF', 0x2, 0x03, 16),
new PC2Field(
'RESTRICT_INDIRECT_BRANCH_PREDICTION_RESERVED', 0x3, 0x03, 16),
new PC2Field('ALLOW_DOWNGRADE_DYNAMIC_CODE_POLICY', 0x1, 0x03, 20),
new PC2Field(
'ALLOW_DOWNGRADE_DYNAMIC_CODE_POLICY_ALWAYS_OFF', 0x2, 0x03, 20),
new PC2Field(
'ALLOW_DOWNGRADE_DYNAMIC_CODE_POLICY_RESERVED', 0x3, 0x03, 20),
new PC2Field('SPECULATIVE_STORE_BYPASS_DISABLE', 0x1, 0x03, 24),
new PC2Field(
'SPECULATIVE_STORE_BYPASS_DISABLE_ALWAYS_OFF', 0x2, 0x03, 24),
new PC2Field('SPECULATIVE_STORE_BYPASS_DISABLE_RESERVED', 0x3, 0x03, 24),
new PC2Field('CET_USER_SHADOW_STACKS', 0x1, 0x03, 28),
new PC2Field('CET_USER_SHADOW_STACKS_ALWAYS_OFF', 0x2, 0x03, 28),
new PC2Field('CET_USER_SHADOW_STACKS_RESERVED', 0x3, 0x03, 28)
];
}
/**
* @param {string} str Hex encoded data.
* @return {Uint8Array} bytes Decoded bytes.
*/
parseHexString(str) {
assert((str.length % 2 == 0), 'str must have even length');
const bytes = new Uint8Array(str.length / 2);
for (let idx = 0; idx < str.length / 2; idx++) {
bytes[idx] = parseInt(str.slice(idx * 2, idx * 2 + 2), 16);
}
return bytes;
}
/**
* Return a list of platform mitigation which are set in |mitigations|.
* Mitigations will be in the same order as Winbase.h.
* @param {string} str Hex encoded process mitigation flags.
* @return {Array<string>} Matched mitigation values.
*/
enabledMitigations(mitigations) {
const bytes = this.parseHexString(mitigations);
const output = [];
for (const item of this.fields) {
if (item.isFieldSet(bytes)) {
output.push(item.mitigation);
}
}
return output;
}
}
const DECODE_MITIGATIONS = new DecodeMitigations();
/** /**
* Adds a row to the sandbox-status table. * Adds a row to the sandbox-status table.
* @param {!Array<string>} args * @param {!Array<Node>} args
*/ */
function addRow(args) { function addRow(args) {
const row = document.createElement('tr'); const row = document.createElement('tr');
for (const text of args) { for (const td of args) {
const col = row.appendChild(document.createElement('td')); row.appendChild(td);
col.textContent = text;
} }
$('sandbox-status').appendChild(row); $('sandbox-status').appendChild(row);
} }
/**
* Makes a <td> containing arg as textContent.
* @param {string} textContent
* @return {Node}
*/
function makeTextEntry(textContent) {
const col = document.createElement('td');
col.textContent = textContent;
return col;
}
/**
* Makes an expandable <td> containing arg as textContent.
* @param {string} mainEntry is always shown
* @param {Object} expandable
* @return {Node}
*/
function makeExpandableEntry(mainEntry, expandable) {
const button = document.createElement('div');
const expand = document.createElement('div');
button.innerText = '\u2795'; // (+)
button.classList.add('expander');
button.addEventListener('click', function() {
if (expandable.onClick(expand)) {
button.innerText = '\u2796'; // (-)
} else {
button.innerText = '\u2795'; // (+)
}
});
const fixed = document.createElement('div');
fixed.classList.add('mitigations');
fixed.innerText = mainEntry;
const col = document.createElement('td');
col.appendChild(button);
col.appendChild(fixed);
col.appendChild(expand);
return col;
}
/**
* Adds a mitigations entry that can expand to show friendly names of the
* mitigations.
* @param {string} platformMitigations
* @return {Node}
*/
function makeMitigationEntry(platformMitigations) {
const expander = {
expanded: false,
mitigations: platformMitigations,
onClick: function(col) {
this.expanded = !this.expanded;
col.innerText = this.getText();
return this.expanded;
},
getText: function() {
if (this.expanded) {
return DECODE_MITIGATIONS.enabledMitigations(this.mitigations)
.join('\n');
} else {
return '';
}
}
};
return makeExpandableEntry(platformMitigations, expander);
}
/** /**
* Adds policy information for a process to the sandbox-status table. * Adds policy information for a process to the sandbox-status table.
* @param {number} pid * @param {number} pid
...@@ -64,12 +358,16 @@ function addRow(args) { ...@@ -64,12 +358,16 @@ function addRow(args) {
*/ */
function addRowForProcess(pid, type, name, sandbox, policy) { function addRowForProcess(pid, type, name, sandbox, policy) {
if (policy) { if (policy) {
addRow([ // Text-only items.
const entries = [
pid, type, name, sandbox, policy.lockdownLevel, pid, type, name, sandbox, policy.lockdownLevel,
policy.desiredIntegrityLevel, policy.platformMitigations policy.desiredIntegrityLevel
]); ].map(makeTextEntry);
// Clickable mitigations item.
entries.push(makeMitigationEntry(policy.platformMitigations));
addRow(entries);
} else { } else {
addRow([pid, type, name, 'Not Sandboxed', '', '', '']); addRow([pid, type, name, 'Not Sandboxed', '', '', ''].map(makeTextEntry));
} }
} }
...@@ -87,7 +385,7 @@ function onGetSandboxDiagnostics(results) { ...@@ -87,7 +385,7 @@ function onGetSandboxDiagnostics(results) {
// Titles. // Titles.
addRow([ addRow([
'Process', 'Type', 'Name', 'Sandbox', 'Lockdown', 'Integrity', 'Mitigations' 'Process', 'Type', 'Name', 'Sandbox', 'Lockdown', 'Integrity', 'Mitigations'
]); ].map(makeTextEntry));
// Browser Processes. // Browser Processes.
for (const process of results.browser) { for (const process of results.browser) {
......
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