Skip to content

Commit

Permalink
feat: add sandboxed / integrityLevel to app.getAppMetrics()
Browse files Browse the repository at this point in the history
  • Loading branch information
Milan Burda authored and miniak committed Jun 10, 2019
1 parent 4321df1 commit d6a912a
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 31 deletions.
76 changes: 54 additions & 22 deletions atom/browser/api/atom_api_app.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "atom/common/native_mate_converters/value_converter.h"
#include "atom/common/node_includes.h"
#include "atom/common/options_switches.h"
#include "atom/common/platform_util.h"
#include "base/command_line.h"
#include "base/environment.h"
#include "base/files/file_path.h"
Expand Down Expand Up @@ -57,6 +58,7 @@
#if defined(OS_WIN)
#include "atom/browser/ui/win/jump_list.h"
#include "base/strings/utf_string_conversions.h"
using ProcessIntegrityLevel = platform_util::ProcessIntegrityLevel;
#endif

#if defined(OS_MACOSX)
Expand All @@ -69,6 +71,25 @@ using atom::Browser;
namespace mate {

#if defined(OS_WIN)
template <>
struct Converter<ProcessIntegrityLevel> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
ProcessIntegrityLevel value) {
switch (value) {
case ProcessIntegrityLevel::Untrusted:
return mate::StringToV8(isolate, "untrusted");
case ProcessIntegrityLevel::Low:
return mate::StringToV8(isolate, "low");
case ProcessIntegrityLevel::Medium:
return mate::StringToV8(isolate, "medium");
case ProcessIntegrityLevel::High:
return mate::StringToV8(isolate, "high");
default:
return mate::StringToV8(isolate, "unknown");
}
}
};

template <>
struct Converter<Browser::UserTask> {
static bool FromV8(v8::Isolate* isolate,
Expand Down Expand Up @@ -358,11 +379,19 @@ struct Converter<content::CertificateRequestResultType> {
namespace atom {

ProcessMetric::ProcessMetric(int type,
base::ProcessId pid,
base::ProcessHandle handle,
std::unique_ptr<base::ProcessMetrics> metrics) {
this->type = type;
this->pid = pid;
this->metrics = std::move(metrics);

#if defined(OS_WIN)
HANDLE duplicate_handle = INVALID_HANDLE_VALUE;
::DuplicateHandle(::GetCurrentProcess(), handle, ::GetCurrentProcess(),
&duplicate_handle, 0, false, DUPLICATE_SAME_ACCESS);
this->process = base::Process(duplicate_handle);
#else
this->process = base::Process(handle);
#endif
}

ProcessMetric::~ProcessMetric() = default;
Expand All @@ -371,17 +400,6 @@ namespace api {

namespace {

class AppIdProcessIterator : public base::ProcessIterator {
public:
AppIdProcessIterator() : base::ProcessIterator(nullptr) {}

protected:
bool IncludeEntry() override {
return (entry().parent_pid() == base::GetCurrentProcId() ||
entry().pid() == base::GetCurrentProcId());
}
};

IconLoader::IconSize GetIconSizeByString(const std::string& size) {
if (size == "small") {
return IconLoader::IconSize::SMALL;
Expand Down Expand Up @@ -550,7 +568,7 @@ App::App(v8::Isolate* isolate) {

base::ProcessId pid = base::GetCurrentProcId();
auto process_metric = std::make_unique<atom::ProcessMetric>(
content::PROCESS_TYPE_BROWSER, pid,
content::PROCESS_TYPE_BROWSER, base::GetCurrentProcessHandle(),
base::ProcessMetrics::CreateCurrentProcessMetrics());
app_metrics_[pid] = std::move(process_metric);
Init(isolate);
Expand Down Expand Up @@ -825,15 +843,13 @@ void App::ChildProcessLaunched(int process_type, base::ProcessHandle handle) {
auto pid = base::GetProcId(handle);

#if defined(OS_MACOSX)
std::unique_ptr<base::ProcessMetrics> metrics(
base::ProcessMetrics::CreateProcessMetrics(
handle, content::BrowserChildProcessHost::GetPortProvider()));
auto metrics = base::ProcessMetrics::CreateProcessMetrics(
handle, content::BrowserChildProcessHost::GetPortProvider());
#else
std::unique_ptr<base::ProcessMetrics> metrics(
base::ProcessMetrics::CreateProcessMetrics(handle));
auto metrics = base::ProcessMetrics::CreateProcessMetrics(handle);
#endif
app_metrics_[pid] = std::make_unique<atom::ProcessMetric>(process_type, pid,
std::move(metrics));
app_metrics_[pid] = std::make_unique<atom::ProcessMetric>(
process_type, handle, std::move(metrics));
}

void App::ChildProcessDisconnected(base::ProcessId pid) {
Expand Down Expand Up @@ -1214,10 +1230,26 @@ std::vector<mate::Dictionary> App::GetAppMetrics(v8::Isolate* isolate) {
cpu_dict.Set("idleWakeupsPerSecond", 0);
#endif

auto pid = process_metric.second->process.Pid();
auto creation_time = process_metric.second->process.CreationTime();

pid_dict.Set("cpu", cpu_dict);
pid_dict.Set("pid", process_metric.second->pid);
pid_dict.Set("pid", pid);
pid_dict.Set("type", content::GetProcessTypeNameInEnglish(
process_metric.second->type));
pid_dict.Set("creationTime", creation_time.ToJsTime());

#if defined(OS_MACOSX)
pid_dict.Set("sandboxed", platform_util::IsProcessSandboxed(pid));
#elif defined(OS_WIN)
auto integrity_level = platform_util::GetProcessIntegrityLevel(
process_metric.second->process.Handle());
auto sandboxed = integrity_level > ProcessIntegrityLevel::Unknown &&
integrity_level < ProcessIntegrityLevel::Medium;
pid_dict.Set("integrityLevel", integrity_level);
pid_dict.Set("sandboxed", sandboxed);
#endif

result.push_back(pid_dict);
}

Expand Down
6 changes: 3 additions & 3 deletions atom/browser/api/atom_api_app.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#include "atom/browser/browser_observer.h"
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/promise_util.h"
#include "base/process/process_iterator.h"
#include "base/process/process.h"
#include "base/process/process_metrics.h"
#include "base/task/cancelable_task_tracker.h"
#include "chrome/browser/icon_manager.h"
Expand Down Expand Up @@ -51,11 +51,11 @@ enum class JumpListResult : int;

struct ProcessMetric {
int type;
base::ProcessId pid;
base::Process process;
std::unique_ptr<base::ProcessMetrics> metrics;

ProcessMetric(int type,
base::ProcessId pid,
base::ProcessHandle handle,
std::unique_ptr<base::ProcessMetrics> metrics);
~ProcessMetric();
};
Expand Down
14 changes: 14 additions & 0 deletions atom/common/platform_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "base/callback_forward.h"
#include "base/files/file_path.h"
#include "base/process/process_handle.h"
#include "build/build_config.h"

#if defined(OS_WIN)
Expand Down Expand Up @@ -48,6 +49,7 @@ void Beep();
#if defined(OS_MACOSX)
bool GetLoginItemEnabled();
bool SetLoginItemEnabled(bool enabled);
bool IsProcessSandboxed(pid_t pid);
#endif

#if defined(OS_LINUX)
Expand All @@ -56,6 +58,18 @@ bool SetLoginItemEnabled(bool enabled);
bool GetDesktopName(std::string* setme);
#endif

#if defined(OS_WIN)
enum class ProcessIntegrityLevel {
Unknown,
Untrusted,
Low,
Medium,
High,
};

ProcessIntegrityLevel GetProcessIntegrityLevel(base::ProcessHandle handle);
#endif

} // namespace platform_util

#endif // ATOM_COMMON_PLATFORM_UTIL_H_
10 changes: 10 additions & 0 deletions atom/common/platform_util_mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include "net/base/mac/url_conversions.h"
#include "url/gurl.h"

extern "C" int sandbox_check(pid_t pid, const char* operation, int type, ...);

namespace {

// This may be called from a global dispatch queue, the methods used here are
Expand Down Expand Up @@ -156,4 +158,12 @@ bool SetLoginItemEnabled(bool enabled) {
return SMLoginItemSetEnabled((__bridge CFStringRef)identifier, enabled);
}

bool IsProcessSandboxed(pid_t pid) {
#if defined(MAS_BUILD)
return true;
#else
return sandbox_check(pid, nullptr, 0) != 0;
#endif
}

} // namespace platform_util
51 changes: 51 additions & 0 deletions atom/common/platform_util_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -385,4 +385,55 @@ void Beep() {
MessageBeep(MB_OK);
}

ProcessIntegrityLevel GetProcessIntegrityLevel(base::ProcessHandle handle) {
HANDLE token = nullptr;
if (!::OpenProcessToken(handle, TOKEN_QUERY, &token)) {
return ProcessIntegrityLevel::Unknown;
}

base::win::ScopedHandle token_scoped(token);

DWORD token_info_length = 0;
if (::GetTokenInformation(token, TokenIntegrityLevel, nullptr, 0,
&token_info_length) ||
::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
return ProcessIntegrityLevel::Unknown;
}

auto token_label_bytes = std::make_unique<char[]>(token_info_length);
TOKEN_MANDATORY_LABEL* token_label =
reinterpret_cast<TOKEN_MANDATORY_LABEL*>(token_label_bytes.get());
if (!::GetTokenInformation(token, TokenIntegrityLevel, token_label,
token_info_length, &token_info_length)) {
return ProcessIntegrityLevel::Unknown;
}

DWORD integrity_level = *::GetSidSubAuthority(
token_label->Label.Sid,
static_cast<DWORD>(*::GetSidSubAuthorityCount(token_label->Label.Sid) -
1));

if (integrity_level >= SECURITY_MANDATORY_UNTRUSTED_RID &&
integrity_level < SECURITY_MANDATORY_LOW_RID) {
return ProcessIntegrityLevel::Untrusted;
}

if (integrity_level >= SECURITY_MANDATORY_LOW_RID &&
integrity_level < SECURITY_MANDATORY_MEDIUM_RID) {
return ProcessIntegrityLevel::Low;
}

if (integrity_level >= SECURITY_MANDATORY_MEDIUM_RID &&
integrity_level < SECURITY_MANDATORY_HIGH_RID) {
return ProcessIntegrityLevel::Medium;
}

if (integrity_level >= SECURITY_MANDATORY_HIGH_RID &&
integrity_level < SECURITY_MANDATORY_SYSTEM_RID) {
return ProcessIntegrityLevel::High;
}

return ProcessIntegrityLevel::Unknown;
}

} // namespace platform_util
9 changes: 9 additions & 0 deletions docs/api/structures/process-metric.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,12 @@
* `pid` Integer - Process id of the process.
* `type` String - Process type (Browser or Tab or GPU etc).
* `cpu` [CPUUsage](cpu-usage.md) - CPU usage of the process.
* `creationTime` Number - Creation time for this process. Since the `pid` can be reused after a process dies,
it is useful to use both the `pid` and the `creationTime` to uniquely identify a process.
* `sandboxed` Boolean (optional) _macOS_ _Windows_ - Whether the process is sandboxed on OS level.
* `integrityLevel` String (optional) _Windows_ - One of the following values:
* `untrusted`
* `low`
* `medium`
* `high`
* `unknown`
21 changes: 15 additions & 6 deletions spec-main/api-app-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -931,13 +931,22 @@ describe('app module', () => {
expect(appMetrics).to.be.an('array').and.have.lengthOf.at.least(1, 'App memory info object is not > 0')

const types = []
for (const { pid, type, cpu } of appMetrics) {
expect(pid).to.be.above(0, 'pid is not > 0')
expect(type).to.be.a('string').that.does.not.equal('')
for (const entry of appMetrics) {
expect(entry.pid).to.be.above(0, 'pid is not > 0')
expect(entry.type).to.be.a('string').that.does.not.equal('')
expect(entry.creationTime).to.be.a('number').that.is.greaterThan(0)

types.push(type)
expect(cpu).to.have.ownProperty('percentCPUUsage').that.is.a('number')
expect(cpu).to.have.ownProperty('idleWakeupsPerSecond').that.is.a('number')
types.push(entry.type)
expect(entry.cpu).to.have.ownProperty('percentCPUUsage').that.is.a('number')
expect(entry.cpu).to.have.ownProperty('idleWakeupsPerSecond').that.is.a('number')

if (process.platform !== 'linux') {
expect(entry.sandboxed).to.be.a('boolean')
}

if (process.platform === 'win32') {
expect(entry.integrityLevel).to.be.a('string')
}
}

if (process.platform === 'darwin') {
Expand Down

0 comments on commit d6a912a

Please sign in to comment.