Commit 5d0ab61a authored by Alex Gough's avatar Alex Gough Committed by Commit Bot

Adds detailed diagnostics to chrome://sandbox

Exports basic fields of active sandbox policies and formats these into
a table for the chrome://sandbox webui.

Bug: 997273
Change-Id: Ic437441fc11a4ebc052fac159e786daf74479863
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1817417
Commit-Queue: Alex Gough <ajgo@chromium.org>
Reviewed-by: default avatarDemetrios Papadopoulos <dpapad@chromium.org>
Reviewed-by: default avatarWill Harris <wfh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#701912}
parent b94b4644
......@@ -45,7 +45,6 @@
<table id="sandbox-status">
</table>
<p id="evaluation"></p>
<if expr="is_win">
<pre id="raw-info"></pre>
......
......@@ -20,8 +20,13 @@ let BrowserHostProcess;
let RendererHostProcess;
/**
* This may have additional fields displayed in the JSON output.
* See //sandbox/win/src/sandbox_constants.cc for keys in policy.
* @typedef {{
* processIds: !Array<number>
* processIds: !Array<number>,
* lockdownLevel: string,
* desiredIntegrityLevel: string,
* platformMitigations: string
* }}
*/
let PolicyDiagnostic;
......@@ -36,16 +41,66 @@ let PolicyDiagnostic;
let SandboxDiagnostics;
/**
* TODO(997273) Join lists into a single table with one row per process
* and add additional fields from Policy objects.
* Adds a row to the sandbox-status table.
* @param {!Array<string>} args
*/
function addRow(args) {
const row = document.createElement('tr');
for (const text of args) {
const col = row.appendChild(document.createElement('td'));
col.textContent = text;
}
$('sandbox-status').appendChild(row);
}
/**
* Adds policy information for a process to the sandbox-status table.
* @param {number} pid
* @param {string} type
* @param {string} name
* @param {PolicyDiagnostic} policy
*/
function addRowForProcess(pid, type, name, policy) {
if (policy) {
addRow([
pid, type, name, policy.lockdownLevel, policy.desiredIntegrityLevel,
policy.platformMitigations
]);
} else {
addRow([pid, type, name, 'Not Sandboxed', '', '']);
}
}
/** @param {!SandboxDiagnostics} results */
function onGetSandboxDiagnostics(results) {
// Make it easy to look up policies.
/** @type {!Map<number,!PolicyDiagnostic>} */
const policies = new Map();
for (const policy of results.policies) {
// At present only one process per TargetPolicy object.
const pid = policy.processIds[0];
policies.set(pid, policy);
}
// Titles.
addRow(['Process', 'Type', 'Name', 'Sandbox', 'Intregity', 'Mitigations']);
// Browser Processes.
for (const process of results.browser) {
const pid = process.processId;
const name = process.name || process.metricsName;
addRowForProcess(pid, process.processType, name, policies.get(pid));
}
// Renderer Processes.
for (const process of results.renderer) {
const pid = process.processId;
addRowForProcess(pid, 'Renderer', '', policies.get(pid));
}
// Raw Diagnostics.
$('raw-info').textContent =
'browserProcesses:' + JSON.stringify(results.browser, null, 2) + '\n' +
'rendererProcesses:' + JSON.stringify(results.renderer, null, 2) + '\n' +
'policies:' + JSON.stringify(results.policies, null, 2);
'policies: ' + JSON.stringify(results.policies, null, 2);
}
document.addEventListener('DOMContentLoaded', () => {
......
......@@ -6,6 +6,12 @@
namespace sandbox {
// Strings used as keys in base::Value snapshots of Policies for WebUI.
extern const char kAppContainerSid[] = "appContainerSid";
extern const char kDesiredIntegrityLevel[] = "desiredIntegrityLevel";
extern const char kDesiredMitigations[] = "desiredMitigations";
extern const char kJobLevel[] = "jobLevel";
extern const char kLockdownLevel[] = "lockdownLevel";
extern const char kLowboxSid[] = "lowboxSid";
extern const char kPlatformMitigations[] = "platformMitigations";
extern const char kProcessIds[] = "processIds";
} // namespace sandbox
......@@ -7,6 +7,13 @@
namespace sandbox {
// Strings used as keys in base::Value snapshots of Policies.
extern const char kAppContainerSid[];
extern const char kDesiredIntegrityLevel[];
extern const char kDesiredMitigations[];
extern const char kJobLevel[];
extern const char kLockdownLevel[];
extern const char kLowboxSid[];
extern const char kPlatformMitigations[];
extern const char kProcessIds[];
} // namespace sandbox
......
......@@ -6,13 +6,16 @@
#include <stddef.h>
#include <cinttypes>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/json/json_string_value_serializer.h"
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "sandbox/win/src/sandbox_constants.h"
#include "sandbox/win/src/sandbox_policy_base.h"
......@@ -31,6 +34,98 @@ base::Value ProcessIdList(std::vector<uint32_t> process_ids) {
return results;
}
std::string GetTokenLevelInEnglish(TokenLevel token) {
switch (token) {
case USER_LOCKDOWN:
return "Lockdown";
case USER_RESTRICTED:
return "Restricted";
case USER_LIMITED:
return "Limited";
case USER_INTERACTIVE:
return "Interactive";
case USER_NON_ADMIN:
return "Non Admin";
case USER_RESTRICTED_SAME_ACCESS:
return "Restricted Same Access";
case USER_UNPROTECTED:
return "Unprotected";
case USER_LAST:
default:
DCHECK(false) << "Unknown TokenType";
return "Unknown";
}
}
std::string GetJobLevelInEnglish(JobLevel job) {
switch (job) {
case JOB_LOCKDOWN:
return "Lockdown";
case JOB_RESTRICTED:
return "Restricted";
case JOB_LIMITED_USER:
return "Limited User";
case JOB_INTERACTIVE:
return "Interactive";
case JOB_UNPROTECTED:
return "Unprotected";
case JOB_NONE:
return "None";
default:
DCHECK(false) << "Unknown JobLevel";
return "Unknown";
}
}
std::string GetIntegrityLevelInEnglish(IntegrityLevel integrity) {
switch (integrity) {
case INTEGRITY_LEVEL_SYSTEM:
return "S-1-16-16384 System";
case INTEGRITY_LEVEL_HIGH:
return "S-1-16-12288 High";
case INTEGRITY_LEVEL_MEDIUM:
return "S-1-16-8192 Medium";
case INTEGRITY_LEVEL_MEDIUM_LOW:
return "S-1-16-6144 Medium Low";
case INTEGRITY_LEVEL_LOW:
return "S-1-16-4096 Low";
case INTEGRITY_LEVEL_BELOW_LOW:
return "S-1-16-2048 Below Low";
case INTEGRITY_LEVEL_UNTRUSTED:
return "S-1-16-0 Untrusted";
case INTEGRITY_LEVEL_LAST:
return "Default";
default:
DCHECK(false) << "Unknown IntegrityLevel";
return "Unknown";
}
}
base::string16 GetSidAsString(const Sid* sid) {
base::string16 result;
if (!sid->ToSddlString(&result))
DCHECK(false) << "Failed to make sddl string";
return result;
}
std::string GetMitigationsAsHex(MitigationFlags mitigations) {
return base::StringPrintf("%016" PRIx64,
base::checked_cast<uint64_t>(mitigations));
}
std::string GetPlatformMitigationsAsHex(MitigationFlags mitigations) {
DWORD64 platform_flags[2] = {0};
size_t flags_size = 0;
sandbox::ConvertProcessMitigationsToPolicy(mitigations, &(platform_flags[0]),
&flags_size);
DCHECK(flags_size / sizeof(DWORD64) <= 2)
<< "Unexpected mitigation flags size";
if (flags_size == 2 * sizeof(DWORD64))
return base::StringPrintf("%016" PRIx64 "%016" PRIx64, platform_flags[0],
platform_flags[1]);
return base::StringPrintf("%016" PRIx64, platform_flags[0]);
}
} // namespace
// We are a friend of PolicyBase so that we can steal its private members
......@@ -45,6 +140,22 @@ PolicyDiagnostic::PolicyDiagnostic(PolicyBase* policy) {
base::strict_cast<uint32_t>(target_process->ProcessId()));
}
}
lockdown_level_ = policy->lockdown_level_;
job_level_ = policy->job_level_;
// Select the final integrity level.
if (policy->delayed_integrity_level_ == INTEGRITY_LEVEL_LAST)
desired_integrity_level_ = policy->integrity_level_;
else
desired_integrity_level_ = policy->delayed_integrity_level_;
desired_mitigations_ = policy->mitigations_ | policy->delayed_mitigations_;
if (policy->app_container_profile_)
app_container_sid_ =
std::make_unique<Sid>(policy->app_container_profile_->GetPackageSid());
if (policy->lowbox_sid_)
lowbox_sid_ = std::make_unique<Sid>(policy->lowbox_sid_);
}
PolicyDiagnostic::~PolicyDiagnostic() = default;
......@@ -54,9 +165,27 @@ const char* PolicyDiagnostic::JsonString() {
if (json_string_)
return json_string_->c_str();
auto json_string = std::make_unique<std::string>();
base::Value value(base::Value::Type::DICTIONARY);
value.SetKey(kProcessIds, ProcessIdList(process_ids_));
value.SetKey(kLockdownLevel,
base::Value(GetTokenLevelInEnglish(lockdown_level_)));
value.SetKey(kJobLevel, base::Value(GetJobLevelInEnglish(job_level_)));
value.SetKey(
kDesiredIntegrityLevel,
base::Value(GetIntegrityLevelInEnglish(desired_integrity_level_)));
value.SetKey(kDesiredMitigations,
base::Value(GetMitigationsAsHex(desired_mitigations_)));
value.SetKey(kPlatformMitigations,
base::Value(GetPlatformMitigationsAsHex(desired_mitigations_)));
if (app_container_sid_)
value.SetKey(kAppContainerSid,
base::Value(GetSidAsString(app_container_sid_.get())));
if (lowbox_sid_)
value.SetKey(kLowboxSid, base::Value(GetSidAsString(lowbox_sid_.get())));
auto json_string = std::make_unique<std::string>();
JSONStringValueSerializer to_json(json_string.get());
CHECK(to_json.Serialize(value));
json_string_ = std::move(json_string);
......
......@@ -13,7 +13,10 @@
#include "base/macros.h"
#include "base/values.h"
#include "sandbox/win/src/process_mitigations.h"
#include "sandbox/win/src/sandbox.h"
#include "sandbox/win/src/security_level.h"
#include "sandbox/win/src/sid.h"
namespace sandbox {
......@@ -33,6 +36,12 @@ class PolicyDiagnostic final : public PolicyInfo {
// |json_string_| is lazily constructed.
std::unique_ptr<std::string> json_string_;
std::vector<uint32_t> process_ids_;
TokenLevel lockdown_level_ = USER_LAST;
JobLevel job_level_ = JOB_NONE;
IntegrityLevel desired_integrity_level_ = INTEGRITY_LEVEL_LAST;
MitigationFlags desired_mitigations_ = 0;
std::unique_ptr<Sid> app_container_sid_ = nullptr;
std::unique_ptr<Sid> lowbox_sid_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(PolicyDiagnostic);
};
......
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