зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland
This commit is contained in:
Коммит
1a3f1390bc
|
@ -410,14 +410,6 @@ var SessionHistoryInternal = {
|
|||
}
|
||||
}
|
||||
|
||||
// The field entry.owner_b64 got renamed to entry.triggeringPricipal_b64 in
|
||||
// Bug 1286472. To remain backward compatible we still have to support that
|
||||
// field for a few cycles before we can remove it within Bug 1289785.
|
||||
if (entry.owner_b64) {
|
||||
entry.triggeringPricipal_b64 = entry.owner_b64;
|
||||
delete entry.owner_b64;
|
||||
}
|
||||
|
||||
// Before introducing the concept of principalToInherit we only had
|
||||
// a triggeringPrincipal within every entry which basically is the
|
||||
// equivalent of the new principalToInherit. To avoid compatibility
|
||||
|
|
|
@ -733,6 +733,7 @@
|
|||
#if defined(MOZ_SANDBOX)
|
||||
#if defined(XP_LINUX)
|
||||
@BINPATH@/@DLL_PREFIX@mozsandbox@DLL_SUFFIX@
|
||||
@RESPATH@/components/sandbox.xpt
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -625,11 +625,9 @@ private:
|
|||
CreateDecoder(const D3D11_VIDEO_DECODER_DESC& aDesc) const;
|
||||
|
||||
RefPtr<ID3D11Device> mDevice;
|
||||
RefPtr<ID3D11DeviceContext> mContext;
|
||||
RefPtr<IMFDXGIDeviceManager> mDXGIDeviceManager;
|
||||
RefPtr<MFTDecoder> mTransform;
|
||||
RefPtr<D3D11RecycleAllocator> mTextureClientAllocator;
|
||||
RefPtr<ID3D11Texture2D> mSyncSurface;
|
||||
RefPtr<ID3D11VideoDecoder> mDecoder;
|
||||
GUID mDecoderGUID;
|
||||
uint32_t mWidth = 0;
|
||||
|
@ -679,13 +677,6 @@ D3D11DXVA2Manager::Init(layers::KnowsCompositor* aKnowsCompositor,
|
|||
return E_FAIL;
|
||||
}
|
||||
|
||||
mDevice->GetImmediateContext(getter_AddRefs(mContext));
|
||||
if (!mContext) {
|
||||
aFailureReason.AssignLiteral(
|
||||
"Failed to get immediate context for d3d11 device");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
hr = wmf::MFCreateDXGIDeviceManager(&mDeviceManagerToken,
|
||||
getter_AddRefs(mDXGIDeviceManager));
|
||||
if (!SUCCEEDED(hr)) {
|
||||
|
@ -791,22 +782,6 @@ D3D11DXVA2Manager::Init(layers::KnowsCompositor* aKnowsCompositor,
|
|||
}
|
||||
}
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc;
|
||||
desc.Width = kSyncSurfaceSize;
|
||||
desc.Height = kSyncSurfaceSize;
|
||||
desc.MipLevels = 1;
|
||||
desc.ArraySize = 1;
|
||||
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.SampleDesc.Quality = 0;
|
||||
desc.Usage = D3D11_USAGE_STAGING;
|
||||
desc.BindFlags = 0;
|
||||
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||
desc.MiscFlags = 0;
|
||||
|
||||
hr = mDevice->CreateTexture2D(&desc, NULL, getter_AddRefs(mSyncSurface));
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
if (layers::ImageBridgeChild::GetSingleton()) {
|
||||
// There's no proper KnowsCompositor for ImageBridge currently (and it
|
||||
// implements the interface), so just use that if it's available.
|
||||
|
@ -865,26 +840,23 @@ D3D11DXVA2Manager::CopyToImage(IMFSample* aVideoSample,
|
|||
HRESULT hr = mTransform->Input(aVideoSample);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
RefPtr<IDXGIKeyedMutex> mutex;
|
||||
RefPtr<IMFSample> sample;
|
||||
RefPtr<ID3D11Texture2D> texture = image->GetTexture();
|
||||
|
||||
texture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));
|
||||
|
||||
hr = mutex->AcquireSync(0, 2000);
|
||||
|
||||
if (hr != S_OK) {
|
||||
NS_WARNING("Acquire sync didn't manage to return within 2 seconds.");
|
||||
}
|
||||
|
||||
hr = CreateOutputSample(sample, texture);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
hr = mTransform->Output(&sample);
|
||||
|
||||
RefPtr<ID3D11DeviceContext> ctx;
|
||||
mDevice->GetImmediateContext(getter_AddRefs(ctx));
|
||||
|
||||
// Copy a small rect into our sync surface, and then map it
|
||||
// to block until decoding/color conversion completes.
|
||||
D3D11_BOX rect = { 0, 0, 0, kSyncSurfaceSize, kSyncSurfaceSize, 1 };
|
||||
ctx->CopySubresourceRegion(mSyncSurface, 0, 0, 0, 0, texture, 0, &rect);
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE mapped;
|
||||
hr = ctx->Map(mSyncSurface, 0, D3D11_MAP_READ, 0, &mapped);
|
||||
NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
|
||||
|
||||
ctx->Unmap(mSyncSurface, 0);
|
||||
mutex->ReleaseSync(0);
|
||||
|
||||
image.forget(aOutImage);
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ D3D11ShareHandleImage::GetAsSourceSurface()
|
|||
{
|
||||
RefPtr<ID3D11Texture2D> texture = GetTexture();
|
||||
if (!texture) {
|
||||
NS_WARNING("Cannot readback from shared texture because no texture is available.");
|
||||
gfxWarning() << "Cannot readback from shared texture because no texture is available.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,19 @@ D3D11ShareHandleImage::GetAsSourceSurface()
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<IDXGIKeyedMutex> mutex;
|
||||
hr = texture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex));
|
||||
|
||||
if (SUCCEEDED(hr) && mutex) {
|
||||
hr = mutex->AcquireSync(0, 2000);
|
||||
if (hr != S_OK) {
|
||||
NS_WARNING("Acquire sync didn't manage to return within 2 seconds.");
|
||||
}
|
||||
}
|
||||
context->CopyResource(softTexture, texture);
|
||||
if (SUCCEEDED(hr) && mutex) {
|
||||
mutex->ReleaseSync(0);
|
||||
}
|
||||
|
||||
RefPtr<gfx::DataSourceSurface> surface =
|
||||
gfx::Factory::CreateDataSourceSurface(mSize, gfx::SurfaceFormat::B8G8R8A8);
|
||||
|
@ -154,7 +166,7 @@ D3D11RecycleAllocator::CreateOrRecycleClient(gfx::SurfaceFormat aFormat,
|
|||
aSize,
|
||||
BackendSelector::Content,
|
||||
layers::TextureFlags::DEFAULT,
|
||||
TextureAllocationFlags::ALLOC_MANUAL_SYNCHRONIZATION);
|
||||
TextureAllocationFlags::ALLOC_DEFAULT);
|
||||
return textureClient.forget();
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,10 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
|
||||
#include "mozilla/SandboxReporter.h"
|
||||
#endif
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
|
@ -912,6 +916,15 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExt
|
|||
# endif // OS_LINUX
|
||||
#endif
|
||||
|
||||
#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
|
||||
{
|
||||
int srcFd, dstFd;
|
||||
SandboxReporter::Singleton()
|
||||
->GetClientFileDescriptorMapping(&srcFd, &dstFd);
|
||||
mFileMap.push_back(std::make_pair(srcFd, dstFd));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
// Add a mach port to the command line so the child can communicate its
|
||||
// 'task_t' back to the parent.
|
||||
|
|
|
@ -1412,14 +1412,6 @@ SessionStore.prototype = {
|
|||
}
|
||||
}
|
||||
|
||||
// The field aEntry.owner_b64 got renamed to aEntry.triggeringPricipal_b64 in
|
||||
// Bug 1286472. To remain backward compatible we still have to support that
|
||||
// field for a few cycles before we can remove it within Bug 1289785.
|
||||
if (aEntry.owner_b64) {
|
||||
aEntry.triggeringPricipal_b64 = aEntry.owner_b64;
|
||||
delete aEntry.owner_b64;
|
||||
}
|
||||
|
||||
// Before introducing the concept of principalToInherit we only had
|
||||
// a triggeringPrincipal within every entry which basically is the
|
||||
// equivalent of the new principalToInherit. To avoid compatibility
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "SandboxFilter.h"
|
||||
#include "SandboxInternal.h"
|
||||
#include "SandboxLogging.h"
|
||||
#include "SandboxReporterClient.h"
|
||||
#include "SandboxUtil.h"
|
||||
|
||||
#include <dirent.h>
|
||||
|
@ -73,6 +74,8 @@ int gSeccompTsyncBroadcastSignum = 0;
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
static bool gSandboxCrashOnError = false;
|
||||
|
||||
// This is initialized by SandboxSetCrashFunc().
|
||||
SandboxCrashFunc gSandboxCrashFunc;
|
||||
|
||||
|
@ -83,6 +86,7 @@ SandboxCrashFunc gSandboxCrashFunc;
|
|||
static SandboxOpenedFile gMediaPluginFile;
|
||||
#endif
|
||||
|
||||
static Maybe<SandboxReporterClient> gSandboxReporterClient;
|
||||
static UniquePtr<SandboxChroot> gChrootHelper;
|
||||
static void (*gChromiumSigSysHandler)(int, siginfo_t*, void*);
|
||||
|
||||
|
@ -135,29 +139,25 @@ SigSysHandler(int nr, siginfo_t *info, void *void_context)
|
|||
return;
|
||||
}
|
||||
|
||||
pid_t pid = getpid();
|
||||
unsigned long syscall_nr = SECCOMP_SYSCALL(&savedCtx);
|
||||
unsigned long args[6];
|
||||
args[0] = SECCOMP_PARM1(&savedCtx);
|
||||
args[1] = SECCOMP_PARM2(&savedCtx);
|
||||
args[2] = SECCOMP_PARM3(&savedCtx);
|
||||
args[3] = SECCOMP_PARM4(&savedCtx);
|
||||
args[4] = SECCOMP_PARM5(&savedCtx);
|
||||
args[5] = SECCOMP_PARM6(&savedCtx);
|
||||
SandboxReport report = gSandboxReporterClient->MakeReportAndSend(&savedCtx);
|
||||
|
||||
// TODO, someday when this is enabled on MIPS: include the two extra
|
||||
// args in the error message.
|
||||
SANDBOX_LOG_ERROR("seccomp sandbox violation: pid %d, syscall %d,"
|
||||
" args %d %d %d %d %d %d. Killing process.",
|
||||
pid, syscall_nr,
|
||||
args[0], args[1], args[2], args[3], args[4], args[5]);
|
||||
SANDBOX_LOG_ERROR("seccomp sandbox violation: pid %d, tid %d, syscall %d,"
|
||||
" args %d %d %d %d %d %d.%s",
|
||||
report.mPid, report.mTid, report.mSyscall,
|
||||
report.mArgs[0], report.mArgs[1], report.mArgs[2],
|
||||
report.mArgs[3], report.mArgs[4], report.mArgs[5],
|
||||
gSandboxCrashOnError ? " Killing process." : "");
|
||||
|
||||
if (gSandboxCrashOnError) {
|
||||
// Bug 1017393: record syscall number somewhere useful.
|
||||
info->si_addr = reinterpret_cast<void*>(syscall_nr);
|
||||
info->si_addr = reinterpret_cast<void*>(report.mSyscall);
|
||||
|
||||
gSandboxCrashFunc(nr, info, &savedCtx);
|
||||
_exit(127);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function installs the SIGSYS handler. This is slightly
|
||||
|
@ -459,6 +459,7 @@ static void
|
|||
SetCurrentProcessSandbox(UniquePtr<sandbox::bpf_dsl::Policy> aPolicy)
|
||||
{
|
||||
MOZ_ASSERT(gSandboxCrashFunc);
|
||||
MOZ_RELEASE_ASSERT(gSandboxReporterClient.isSome());
|
||||
|
||||
// Note: PolicyCompiler borrows the policy and registry for its
|
||||
// lifetime, but does not take ownership of them.
|
||||
|
@ -515,6 +516,21 @@ SandboxEarlyInit(GeckoProcessType aType)
|
|||
}
|
||||
MOZ_RELEASE_ASSERT(IsSingleThreaded());
|
||||
|
||||
// Set gSandboxCrashOnError if appropriate. This doesn't need to
|
||||
// happen this early, but for now it's here so that I don't need to
|
||||
// add NSPR dependencies for PR_GetEnv.
|
||||
//
|
||||
// This also means that users with "unexpected threads" setups won't
|
||||
// crash even on nightly.
|
||||
#ifdef NIGHTLY_BUILD
|
||||
gSandboxCrashOnError = true;
|
||||
#endif
|
||||
if (const char* envVar = getenv("MOZ_SANDBOX_CRASH_ON_ERROR")) {
|
||||
if (envVar[0]) {
|
||||
gSandboxCrashOnError = envVar[0] != '0';
|
||||
}
|
||||
}
|
||||
|
||||
// Which kinds of resource isolation (of those that need to be set
|
||||
// up at this point) can be used by this process?
|
||||
bool canChroot = false;
|
||||
|
@ -643,6 +659,8 @@ SetContentProcessSandbox(int aBrokerFd, std::vector<int>& aSyscallWhitelist)
|
|||
return false;
|
||||
}
|
||||
|
||||
gSandboxReporterClient.emplace(SandboxReport::ProcType::CONTENT);
|
||||
|
||||
// This needs to live until the process exits.
|
||||
static Maybe<SandboxBrokerClient> sBroker;
|
||||
if (aBrokerFd >= 0) {
|
||||
|
@ -674,6 +692,8 @@ SetMediaPluginSandbox(const char *aFilePath)
|
|||
return;
|
||||
}
|
||||
|
||||
gSandboxReporterClient.emplace(SandboxReport::ProcType::MEDIA_PLUGIN);
|
||||
|
||||
MOZ_ASSERT(!gMediaPluginFile.mPath);
|
||||
if (aFilePath) {
|
||||
gMediaPluginFile.mPath = strdup(aFilePath);
|
||||
|
|
|
@ -169,6 +169,7 @@ public:
|
|||
Arg<clockid_t> clk_id(0);
|
||||
return If(clk_id == CLOCK_MONOTONIC, Allow())
|
||||
#ifdef CLOCK_MONOTONIC_COARSE
|
||||
// Used by SandboxReporter, among other things.
|
||||
.ElseIf(clk_id == CLOCK_MONOTONIC_COARSE, Allow())
|
||||
#endif
|
||||
.ElseIf(clk_id == CLOCK_PROCESS_CPUTIME_ID, Allow())
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "SandboxReporterClient.h"
|
||||
#include "SandboxLogging.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "sandbox/linux/bpf_dsl/seccomp_macros.h"
|
||||
#ifdef ANDROID
|
||||
#include "sandbox/linux/system_headers/linux_ucontext.h"
|
||||
#else
|
||||
#include <ucontext.h>
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
SandboxReporterClient::SandboxReporterClient(SandboxReport::ProcType aProcType,
|
||||
int aFd)
|
||||
: mProcType(aProcType)
|
||||
, mFd(aFd)
|
||||
{
|
||||
// Unfortunately, there isn't a good way to check that the fd is a
|
||||
// socket connected to the right thing without attempting some kind
|
||||
// of in-band handshake. However, the crash reporter (which also
|
||||
// uses a "magic number" fd) doesn't do any kind of checking either,
|
||||
// so it's probably okay to skip it here.
|
||||
}
|
||||
|
||||
SandboxReport
|
||||
SandboxReporterClient::MakeReport(const void* aContext)
|
||||
{
|
||||
SandboxReport report;
|
||||
const auto ctx = static_cast<const ucontext_t*>(aContext);
|
||||
|
||||
// Zero the entire struct; some memory safety analyses care about
|
||||
// sending uninitialized alignment padding to another process.
|
||||
PodZero(&report);
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC_COARSE, &report.mTime);
|
||||
report.mPid = getpid();
|
||||
report.mTid = syscall(__NR_gettid);
|
||||
report.mProcType = mProcType;
|
||||
report.mSyscall = SECCOMP_SYSCALL(ctx);
|
||||
report.mArgs[0] = SECCOMP_PARM1(ctx);
|
||||
report.mArgs[1] = SECCOMP_PARM2(ctx);
|
||||
report.mArgs[2] = SECCOMP_PARM3(ctx);
|
||||
report.mArgs[3] = SECCOMP_PARM4(ctx);
|
||||
report.mArgs[4] = SECCOMP_PARM5(ctx);
|
||||
report.mArgs[5] = SECCOMP_PARM6(ctx);
|
||||
// Named Return Value Optimization allows the compiler to optimize
|
||||
// out the copy here (and the one in MakeReportAndSend).
|
||||
return report;
|
||||
}
|
||||
|
||||
void
|
||||
SandboxReporterClient::SendReport(const SandboxReport& aReport)
|
||||
{
|
||||
// The "common" seccomp-bpf policy allows sendmsg but not send(to),
|
||||
// so just use sendmsg even though send would suffice for this.
|
||||
struct iovec iov;
|
||||
struct msghdr msg;
|
||||
|
||||
iov.iov_base = const_cast<void*>(static_cast<const void*>(&aReport));
|
||||
iov.iov_len = sizeof(SandboxReport);
|
||||
PodZero(&msg);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
const auto sent = sendmsg(mFd, &msg, MSG_NOSIGNAL);
|
||||
|
||||
if (sent != sizeof(SandboxReport)) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(sent == -1);
|
||||
SANDBOX_LOG_ERROR("Failed to report rejected syscall: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,43 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_SandboxReporterClient_h
|
||||
#define mozilla_SandboxReporterClient_h
|
||||
|
||||
#include "reporter/SandboxReporterCommon.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// This class is instantiated in child processes in Sandbox.cpp to
|
||||
// send reports from the SIGSYS handler to the SandboxReporter
|
||||
// instance in the parent.
|
||||
class SandboxReporterClient {
|
||||
public:
|
||||
// Note: this does not take ownership of the file descriptor; if
|
||||
// it's not kSandboxReporterFileDesc (e.g., for unit testing), the
|
||||
// caller will need to close it to avoid leaks.
|
||||
explicit SandboxReporterClient(SandboxReport::ProcType aProcType,
|
||||
int aFd = kSandboxReporterFileDesc);
|
||||
|
||||
// Constructs a report from a signal context (the ucontext_t* passed
|
||||
// as void* to an sa_sigaction handler); uses the caller's pid and tid.
|
||||
SandboxReport MakeReport(const void* aContext);
|
||||
|
||||
void SendReport(const SandboxReport& aReport);
|
||||
|
||||
SandboxReport MakeReportAndSend(const void* aContext) {
|
||||
SandboxReport report = MakeReport(aContext);
|
||||
SendReport(report);
|
||||
return report;
|
||||
}
|
||||
private:
|
||||
SandboxReport::ProcType mProcType;
|
||||
int mFd;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_SandboxReporterClient_h
|
|
@ -0,0 +1,11 @@
|
|||
# -*- Mode: python; python-indent: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
XPIDL_MODULE = 'sandbox'
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'mozISandboxReporter.idl',
|
||||
]
|
|
@ -0,0 +1,65 @@
|
|||
/* -*- Mode: IDL; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
// A wrapper for the C++ class SandboxReport, representing one system
|
||||
// call that was rejected by policy.
|
||||
[scriptable, builtinclass, uuid(ed1e84d3-3346-42e1-b28c-e76a77f549f0)]
|
||||
interface mozISandboxReport : nsISupports
|
||||
{
|
||||
// The timestamp relative to the time when this property is read.
|
||||
// This is mainly meant for distinguishing recent events that might
|
||||
// be related to an observable failure from older ones that may be
|
||||
// unrelated, not for exact timing.
|
||||
readonly attribute uint64_t msecAgo;
|
||||
readonly attribute int32_t pid;
|
||||
readonly attribute int32_t tid;
|
||||
readonly attribute ACString procType;
|
||||
readonly attribute uint32_t syscall;
|
||||
// Currently numArgs is effectively a constant and indicates the
|
||||
// maximum number of arguments possible on the platform; the actual
|
||||
// system call may use fewer.
|
||||
readonly attribute uint32_t numArgs;
|
||||
// The argument values are presented as strings because JS doesn't
|
||||
// have 64-bit integers and data would be lost on 64-bit platforms
|
||||
// if the XPIDL type uint64_t were used. The string may be decimal
|
||||
// or hex (with leading "0x").
|
||||
ACString getArg(in uint32_t aIndex);
|
||||
};
|
||||
|
||||
// A wrapper for SandboxReporter::Snapshot, representing the most
|
||||
// recent SandboxReport events. Index 0 is the first report in the
|
||||
// session, and so on; exposing the indices like this lets us see how
|
||||
// many reports have been received even though only a limited number
|
||||
// of them are stored.
|
||||
[scriptable, builtinclass, uuid(6e8ff6e5-05c9-42d3-853d-40523fd86a50)]
|
||||
interface mozISandboxReportArray : nsISupports
|
||||
{
|
||||
readonly attribute uint64_t begin;
|
||||
readonly attribute uint64_t end;
|
||||
// (aIndex >= begin && aIndex < end) must be true.
|
||||
mozISandboxReport getElement(in uint64_t aIndex);
|
||||
};
|
||||
|
||||
// A wrapper for the SandboxReporter; use the component/contract IDs
|
||||
// below to access the SandboxReporter singleton. The component
|
||||
// constructor will fail if called in a child process.
|
||||
[scriptable, builtinclass, uuid(8535bdf7-6d9e-4853-acf9-a146449c4a3b)]
|
||||
interface mozISandboxReporter : nsISupports
|
||||
{
|
||||
mozISandboxReportArray snapshot();
|
||||
};
|
||||
|
||||
%{ C++
|
||||
|
||||
#define MOZ_SANDBOX_REPORTER_CID \
|
||||
{0x5118a6f9, 0x2493, 0x4f97, {0x95, 0x52, 0x62, 0x06, 0x63, 0xe0, 0x3c, 0xb3}}
|
||||
|
||||
#define MOZ_SANDBOX_REPORTER_CONTRACTID \
|
||||
"@mozilla.org/sandbox/syscall-reporter;1"
|
||||
|
||||
%}
|
|
@ -67,6 +67,7 @@ SOURCES += [
|
|||
'SandboxHooks.cpp',
|
||||
'SandboxInfo.cpp',
|
||||
'SandboxLogging.cpp',
|
||||
'SandboxReporterClient.cpp',
|
||||
'SandboxUtil.cpp',
|
||||
]
|
||||
|
||||
|
@ -109,6 +110,8 @@ if CONFIG['OS_TARGET'] != 'Android':
|
|||
DIRS += [
|
||||
'broker',
|
||||
'glue',
|
||||
'interfaces',
|
||||
'reporter',
|
||||
]
|
||||
|
||||
TEST_DIRS += [
|
||||
|
|
|
@ -0,0 +1,295 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "SandboxReporter.h"
|
||||
#include "SandboxLogging.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h> // for clockid_t
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/StaticMutex.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "sandbox/linux/system_headers/linux_syscalls.h"
|
||||
|
||||
// Distinguish architectures for the telemetry key.
|
||||
#if defined(__i386__)
|
||||
#define SANDBOX_ARCH_NAME "x86"
|
||||
#elif defined(__x86_64__)
|
||||
#define SANDBOX_ARCH_NAME "amd64"
|
||||
#else
|
||||
#error "unrecognized architecture"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
StaticAutoPtr<SandboxReporter> SandboxReporter::sSingleton;
|
||||
|
||||
SandboxReporter::SandboxReporter()
|
||||
: mClientFd(-1)
|
||||
, mServerFd(-1)
|
||||
, mMutex("SandboxReporter")
|
||||
, mBuffer(MakeUnique<SandboxReport[]>(kSandboxReporterBufferSize))
|
||||
, mCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
SandboxReporter::Init()
|
||||
{
|
||||
int fds[2];
|
||||
|
||||
if (0 != socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds)) {
|
||||
SANDBOX_LOG_ERROR("SandboxReporter: socketpair failed: %s",
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
mClientFd = fds[0];
|
||||
mServerFd = fds[1];
|
||||
|
||||
if (!PlatformThread::Create(0, this, &mThread)) {
|
||||
SANDBOX_LOG_ERROR("SandboxReporter: thread creation failed: %s",
|
||||
strerror(errno));
|
||||
close(mClientFd);
|
||||
close(mServerFd);
|
||||
mClientFd = mServerFd = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SandboxReporter::~SandboxReporter()
|
||||
{
|
||||
if (mServerFd < 0) {
|
||||
return;
|
||||
}
|
||||
shutdown(mServerFd, SHUT_RD);
|
||||
PlatformThread::Join(mThread);
|
||||
close(mServerFd);
|
||||
close(mClientFd);
|
||||
}
|
||||
|
||||
/* static */ SandboxReporter*
|
||||
SandboxReporter::Singleton()
|
||||
{
|
||||
static StaticMutex sMutex;
|
||||
StaticMutexAutoLock lock(sMutex);
|
||||
|
||||
if (sSingleton == nullptr) {
|
||||
sSingleton = new SandboxReporter();
|
||||
if (!sSingleton->Init()) {
|
||||
// If socketpair or thread creation failed, trying to continue
|
||||
// with child process creation is unlikely to succeed; crash
|
||||
// instead of trying to handle that case.
|
||||
MOZ_CRASH("SandboxRepoter::Singleton: initialization failed");
|
||||
}
|
||||
// ClearOnShutdown must be called on the main thread and will
|
||||
// destroy the object on the main thread. That *should* be safe;
|
||||
// the destructor will shut down the reporter's socket reader
|
||||
// thread before freeing anything, IPC should already be shut down
|
||||
// by that point (so it won't race by calling Singleton()), all
|
||||
// non-main XPCOM threads will also be shut down, and currently
|
||||
// the only other user is the main-thread-only Troubleshoot.jsm.
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction([] {
|
||||
ClearOnShutdown(&sSingleton);
|
||||
}));
|
||||
}
|
||||
return sSingleton.get();
|
||||
}
|
||||
|
||||
void
|
||||
SandboxReporter::GetClientFileDescriptorMapping(int* aSrcFd, int* aDstFd) const
|
||||
{
|
||||
MOZ_ASSERT(mClientFd >= 0);
|
||||
*aSrcFd = mClientFd;
|
||||
*aDstFd = kSandboxReporterFileDesc;
|
||||
}
|
||||
|
||||
// This function is mentioned in Histograms.json; keep that in mind if
|
||||
// it's renamed or moved to a different file.
|
||||
static void
|
||||
SubmitToTelemetry(const SandboxReport& aReport)
|
||||
{
|
||||
nsAutoCString key;
|
||||
// The key contains the process type, something that uniquely
|
||||
// identifies the syscall, and in some cases arguments (see below
|
||||
// for details). Arbitrary formatting choice: fields in the key are
|
||||
// separated by ':', except that (arch, syscall#) pairs are
|
||||
// separated by '/'.
|
||||
//
|
||||
// Examples:
|
||||
// * "content:x86/64" (bug 1285768)
|
||||
// * "content:x86_64/110" (bug 1285768)
|
||||
// * "gmp:madvise:8" (bug 1303813)
|
||||
// * "content:clock_gettime:4" (bug 1334687)
|
||||
|
||||
switch (aReport.mProcType) {
|
||||
case SandboxReport::ProcType::CONTENT:
|
||||
key.AppendLiteral("content");
|
||||
break;
|
||||
case SandboxReport::ProcType::MEDIA_PLUGIN:
|
||||
key.AppendLiteral("gmp");
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(false);
|
||||
}
|
||||
key.Append(':');
|
||||
|
||||
switch(aReport.mSyscall) {
|
||||
// Syscalls that are filtered by arguments in one or more of the
|
||||
// policies in SandboxFilter.cpp should generally have those
|
||||
// arguments included here, but don't include irrelevant
|
||||
// information that would cause large numbers of distinct keys for
|
||||
// the same issue -- for example, pids or pointers. When in
|
||||
// doubt, include arguments only if they would typically be
|
||||
// constants (or asm immediates) in the code making the syscall.
|
||||
//
|
||||
// Also, keep in mind that this is opt-out data collection and
|
||||
// privacy is critical. While it's unlikely that information in
|
||||
// the register values alone could personally identify a user
|
||||
// (see also crash reports, where register contents are public),
|
||||
// and the guidelines in the previous paragraph should rule out
|
||||
// any value that's capable of holding PII, please be careful.
|
||||
//
|
||||
// When making changes here, please consult with a data steward
|
||||
// (https://wiki.mozilla.org/Firefox/Data_Collection) and ask for
|
||||
// a review if you are unsure about anything.
|
||||
|
||||
// This macro includes one argument as a decimal number; it should
|
||||
// be enough for most cases.
|
||||
#define ARG_DECIMAL(name, idx) \
|
||||
case __NR_##name: \
|
||||
key.AppendLiteral(#name ":"); \
|
||||
key.AppendInt(aReport.mArgs[idx]); \
|
||||
break
|
||||
|
||||
// This may be more convenient if the argument is a set of bit flags.
|
||||
#define ARG_HEX(name, idx) \
|
||||
case __NR_##name: \
|
||||
key.AppendLiteral(#name ":0x"); \
|
||||
key.AppendInt(aReport.mArgs[idx], 16); \
|
||||
break
|
||||
|
||||
// clockid_t is annoying: there are a small set of fixed timers,
|
||||
// but it can also encode a pid/tid (or a fd for a hardware clock
|
||||
// device); in this case the value is negative.
|
||||
#define ARG_CLOCKID(name, idx) \
|
||||
case __NR_##name: \
|
||||
key.AppendLiteral(#name ":"); \
|
||||
if (static_cast<clockid_t>(aReport.mArgs[idx]) < 0) { \
|
||||
key.AppendLiteral("dynamic"); \
|
||||
} else { \
|
||||
key.AppendInt(aReport.mArgs[idx]); \
|
||||
} \
|
||||
break
|
||||
|
||||
// The syscalls handled specially:
|
||||
|
||||
ARG_HEX(clone, 0); // flags
|
||||
ARG_DECIMAL(prctl, 0); // option
|
||||
ARG_DECIMAL(madvise, 2); // advice
|
||||
ARG_CLOCKID(clock_gettime, 0); // clk_id
|
||||
|
||||
#ifdef __NR_socketcall
|
||||
ARG_DECIMAL(socketcall, 0); // call
|
||||
#endif
|
||||
#ifdef __NR_ipc
|
||||
ARG_DECIMAL(ipc, 0); // call
|
||||
#endif
|
||||
|
||||
#undef ARG_DECIMAL
|
||||
#undef ARG_HEX
|
||||
#undef ARG_CLOCKID
|
||||
|
||||
default:
|
||||
// Otherwise just use the number, with the arch name to disambiguate.
|
||||
key.Append(SANDBOX_ARCH_NAME "/");
|
||||
key.AppendInt(aReport.mSyscall);
|
||||
}
|
||||
|
||||
Telemetry::Accumulate(Telemetry::SANDBOX_REJECTED_SYSCALLS, key);
|
||||
}
|
||||
|
||||
void
|
||||
SandboxReporter::AddOne(const SandboxReport& aReport)
|
||||
{
|
||||
SubmitToTelemetry(aReport);
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
mBuffer[mCount % kSandboxReporterBufferSize] = aReport;
|
||||
++mCount;
|
||||
}
|
||||
|
||||
void
|
||||
SandboxReporter::ThreadMain(void)
|
||||
{
|
||||
for (;;) {
|
||||
SandboxReport rep;
|
||||
struct iovec iov;
|
||||
struct msghdr msg;
|
||||
|
||||
iov.iov_base = &rep;
|
||||
iov.iov_len = sizeof(rep);
|
||||
PodZero(&msg);
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
const auto recvd = recvmsg(mServerFd, &msg, 0);
|
||||
if (recvd < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
SANDBOX_LOG_ERROR("SandboxReporter: recvmsg: %s", strerror(errno));
|
||||
}
|
||||
if (recvd <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (static_cast<size_t>(recvd) < sizeof(rep)) {
|
||||
SANDBOX_LOG_ERROR("SandboxReporter: packet too short (%d < %d)",
|
||||
recvd, sizeof(rep));
|
||||
continue;
|
||||
}
|
||||
if (msg.msg_flags & MSG_TRUNC) {
|
||||
SANDBOX_LOG_ERROR("SandboxReporter: packet too long");
|
||||
continue;
|
||||
}
|
||||
|
||||
AddOne(rep);
|
||||
}
|
||||
}
|
||||
|
||||
SandboxReporter::Snapshot
|
||||
SandboxReporter::GetSnapshot()
|
||||
{
|
||||
Snapshot snapshot;
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
const uint64_t bufSize = static_cast<uint64_t>(kSandboxReporterBufferSize);
|
||||
const uint64_t start = std::max(mCount, bufSize) - bufSize;
|
||||
snapshot.mOffset = start;
|
||||
snapshot.mReports.Clear();
|
||||
snapshot.mReports.SetCapacity(mCount - start);
|
||||
for (size_t i = start; i < mCount; ++i) {
|
||||
const SandboxReport* rep = &mBuffer[i % kSandboxReporterBufferSize];
|
||||
MOZ_ASSERT(rep->IsValid());
|
||||
snapshot.mReports.AppendElement(*rep);
|
||||
}
|
||||
// Named Return Value Optimization would apply here, but C++11
|
||||
// doesn't require it; so, instead of possibly copying the entire
|
||||
// array contents, invoke the move constructor and copy at most a
|
||||
// few words.
|
||||
return Move(snapshot);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,87 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_SandboxReporter_h
|
||||
#define mozilla_SandboxReporter_h
|
||||
|
||||
#include "SandboxReporterCommon.h"
|
||||
|
||||
#include "base/platform_thread.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/Types.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// This object collects the SandboxReport messages from all of the
|
||||
// child processes, submits them to Telemetry, and maintains a ring
|
||||
// buffer of the last kSandboxReporterBufferSize reports.
|
||||
class SandboxReporter final
|
||||
: public PlatformThread::Delegate
|
||||
{
|
||||
public:
|
||||
// For normal use, don't construct this directly; use the
|
||||
// Singleton() method.
|
||||
//
|
||||
// For unit testing, use this constructor followed by the Init
|
||||
// method; the object isn't usable unless Init returns true.
|
||||
explicit SandboxReporter();
|
||||
~SandboxReporter();
|
||||
|
||||
// See above; this method is not thread-safe.
|
||||
bool Init();
|
||||
|
||||
// Used in GeckoChildProcessHost to connect the child process's
|
||||
// client to this report collector.
|
||||
void GetClientFileDescriptorMapping(int* aSrcFd, int* aDstFd) const;
|
||||
|
||||
// A snapshot of the report ring buffer; element 0 of `mReports` is
|
||||
// the `mOffset`th report to be received, and so on.
|
||||
struct Snapshot {
|
||||
// The buffer has to fit in memory, but the total number of
|
||||
// reports received in the session can increase without bound and
|
||||
// could potentially overflow a uint32_t, so this is 64-bit.
|
||||
// (It's exposed to JS as a 53-bit int, effectively, but that
|
||||
// should also be large enough.)
|
||||
uint64_t mOffset;
|
||||
nsTArray<SandboxReport> mReports;
|
||||
};
|
||||
|
||||
// Read the ring buffer contents; this method is thread-safe.
|
||||
Snapshot GetSnapshot();
|
||||
|
||||
// Gets or creates the singleton report collector. Crashes if
|
||||
// initialization fails (if a socketpair and/or thread can't be
|
||||
// created, there was almost certainly about to be a crash anyway).
|
||||
// Thread-safe as long as the pointer isn't used during/after XPCOM
|
||||
// shutdown.
|
||||
static SandboxReporter* Singleton();
|
||||
private:
|
||||
// These are constant over the life of the object:
|
||||
int mClientFd;
|
||||
int mServerFd;
|
||||
PlatformThreadHandle mThread;
|
||||
|
||||
Mutex mMutex;
|
||||
// These are protected by mMutex:
|
||||
UniquePtr<SandboxReport[]> mBuffer;
|
||||
uint64_t mCount;
|
||||
|
||||
static StaticAutoPtr<SandboxReporter> sSingleton;
|
||||
|
||||
void ThreadMain(void) override;
|
||||
void AddOne(const SandboxReport& aReport);
|
||||
};
|
||||
|
||||
// This is a constant so the % operations can be optimized. This is
|
||||
// exposed in the header so that unit tests can see it.
|
||||
static const size_t kSandboxReporterBufferSize = 32;
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_SandboxReporter_h
|
|
@ -0,0 +1,62 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_SandboxReporterCommon_h
|
||||
#define mozilla_SandboxReporterCommon_h
|
||||
|
||||
#include "mozilla/IntegerTypeTraits.h"
|
||||
#include "mozilla/Types.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
// Note: this is also used in libmozsandbox, so dependencies on
|
||||
// symbols from libxul probably won't work.
|
||||
|
||||
namespace mozilla {
|
||||
static const size_t kSandboxSyscallArguments = 6;
|
||||
// fds 0-2: stdio; fd 3: IPC; fd 4: crash reporter. (The IPC child
|
||||
// process launching code will check that we don't try to use the same
|
||||
// fd twice.)
|
||||
static const int kSandboxReporterFileDesc = 5;
|
||||
|
||||
// This struct represents a system call that was rejected by a
|
||||
// seccomp-bpf policy.
|
||||
struct SandboxReport {
|
||||
// In the future this may include finer distinctions than
|
||||
// GeckoProcessType -- e.g., whether a content process can load
|
||||
// file:/// URLs, or if it's reserved for content with certain
|
||||
// user-granted permissions.
|
||||
enum class ProcType : uint8_t {
|
||||
CONTENT,
|
||||
MEDIA_PLUGIN,
|
||||
};
|
||||
|
||||
// The syscall number and arguments are usually `unsigned long`, but
|
||||
// that causes ambiguous overload errors with nsACString::AppendInt.
|
||||
using ULong = UnsignedStdintTypeForSize<sizeof(unsigned long)>::Type;
|
||||
|
||||
// This time uses CLOCK_MONOTONIC_COARSE. Displaying or reporting
|
||||
// it should usually be done relative to the current value of that
|
||||
// clock (or the time at some other event of interest, like a
|
||||
// subsequent crash).
|
||||
struct timespec mTime;
|
||||
|
||||
// The pid/tid values, like every other field in this struct, aren't
|
||||
// authenticated and a compromised process could send anything, so
|
||||
// use the values with caution.
|
||||
pid_t mPid;
|
||||
pid_t mTid;
|
||||
ProcType mProcType;
|
||||
ULong mSyscall;
|
||||
ULong mArgs[kSandboxSyscallArguments];
|
||||
|
||||
SandboxReport() : mPid(0) { }
|
||||
bool IsValid() const { return mPid > 0; }
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_SandboxReporterCommon_h
|
|
@ -0,0 +1,220 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozISandboxReporter.h"
|
||||
#include "SandboxReporter.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class SandboxReportWrapper final : public mozISandboxReport
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_MOZISANDBOXREPORT
|
||||
|
||||
explicit SandboxReportWrapper(const SandboxReport& aReport)
|
||||
: mReport(aReport)
|
||||
{ }
|
||||
|
||||
private:
|
||||
~SandboxReportWrapper() { }
|
||||
SandboxReport mReport;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(SandboxReportWrapper, mozISandboxReport)
|
||||
|
||||
/* readonly attribute uint64_t msecAgo; */
|
||||
NS_IMETHODIMP SandboxReportWrapper::GetMsecAgo(uint64_t* aMsec)
|
||||
{
|
||||
struct timespec then = mReport.mTime, now = { 0, 0 };
|
||||
clock_gettime(CLOCK_MONOTONIC_COARSE, &now);
|
||||
|
||||
const uint64_t now_msec =
|
||||
uint64_t(now.tv_sec) * 1000 + now.tv_nsec / 1000000;
|
||||
const uint64_t then_msec =
|
||||
uint64_t(then.tv_sec) * 1000 + then.tv_nsec / 1000000;
|
||||
MOZ_DIAGNOSTIC_ASSERT(now_msec >= then_msec);
|
||||
if (now_msec >= then_msec) {
|
||||
*aMsec = now_msec - then_msec;
|
||||
} else {
|
||||
*aMsec = 0;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute int32_t pid; */
|
||||
NS_IMETHODIMP SandboxReportWrapper::GetPid(int32_t *aPid)
|
||||
{
|
||||
*aPid = mReport.mPid;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute int32_t tid; */
|
||||
NS_IMETHODIMP SandboxReportWrapper::GetTid(int32_t *aTid)
|
||||
{
|
||||
*aTid = mReport.mTid;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute ACString procType; */
|
||||
NS_IMETHODIMP SandboxReportWrapper::GetProcType(nsACString& aProcType)
|
||||
{
|
||||
switch (mReport.mProcType) {
|
||||
case SandboxReport::ProcType::CONTENT:
|
||||
aProcType.AssignLiteral("content");
|
||||
return NS_OK;
|
||||
case SandboxReport::ProcType::MEDIA_PLUGIN:
|
||||
aProcType.AssignLiteral("mediaPlugin");
|
||||
return NS_OK;
|
||||
default:
|
||||
MOZ_ASSERT(false);
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
|
||||
/* readonly attribute uint32_t syscall; */
|
||||
NS_IMETHODIMP SandboxReportWrapper::GetSyscall(uint32_t *aSyscall)
|
||||
{
|
||||
*aSyscall = static_cast<uint32_t>(mReport.mSyscall);
|
||||
MOZ_ASSERT(static_cast<SandboxReport::ULong>(*aSyscall) == mReport.mSyscall);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute uint32_t numArgs; */
|
||||
NS_IMETHODIMP SandboxReportWrapper::GetNumArgs(uint32_t *aNumArgs)
|
||||
{
|
||||
*aNumArgs = static_cast<uint32_t>(kSandboxSyscallArguments);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* ACString getArg (in uint32_t aIndex); */
|
||||
NS_IMETHODIMP SandboxReportWrapper::GetArg(uint32_t aIndex,
|
||||
nsACString& aRetval)
|
||||
{
|
||||
if (aIndex >= kSandboxSyscallArguments) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
const auto arg = mReport.mArgs[aIndex];
|
||||
nsAutoCString str;
|
||||
// Use decimal for smaller numbers (more likely ints) and hex for
|
||||
// larger (more likely pointers). This cutoff is arbitrary.
|
||||
if (arg >= 1000000) {
|
||||
str.AppendLiteral("0x");
|
||||
str.AppendInt(arg, 16);
|
||||
} else {
|
||||
str.AppendInt(arg, 10);
|
||||
}
|
||||
aRetval = str;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class SandboxReportArray final : public mozISandboxReportArray
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_MOZISANDBOXREPORTARRAY
|
||||
|
||||
explicit SandboxReportArray(SandboxReporter::Snapshot&& aSnap)
|
||||
: mOffset(aSnap.mOffset)
|
||||
, mArray(Move(aSnap.mReports))
|
||||
{ }
|
||||
|
||||
private:
|
||||
~SandboxReportArray() { }
|
||||
uint64_t mOffset;
|
||||
nsTArray<SandboxReport> mArray;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(SandboxReportArray, mozISandboxReportArray)
|
||||
|
||||
/* readonly attribute uint64_t begin; */
|
||||
NS_IMETHODIMP SandboxReportArray::GetBegin(uint64_t *aBegin)
|
||||
{
|
||||
*aBegin = mOffset;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute uint64_t end; */
|
||||
NS_IMETHODIMP SandboxReportArray::GetEnd(uint64_t *aEnd)
|
||||
{
|
||||
*aEnd = mOffset + mArray.Length();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* mozISandboxReport getElement (in uint64_t aIndex); */
|
||||
NS_IMETHODIMP SandboxReportArray::GetElement(uint64_t aIndex, mozISandboxReport ** aRetval)
|
||||
{
|
||||
uint64_t relIndex = aIndex - mOffset;
|
||||
if (relIndex >= mArray.Length()) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsCOMPtr<mozISandboxReport> wrapper =
|
||||
new SandboxReportWrapper(mArray[relIndex]);
|
||||
wrapper.forget(aRetval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class SandboxReporterWrapper final : public mozISandboxReporter
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_MOZISANDBOXREPORTER
|
||||
|
||||
SandboxReporterWrapper() { }
|
||||
|
||||
private:
|
||||
~SandboxReporterWrapper() { }
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(SandboxReporterWrapper, mozISandboxReporter)
|
||||
|
||||
/* mozISandboxReportArray snapshot(); */
|
||||
NS_IMETHODIMP SandboxReporterWrapper::Snapshot(mozISandboxReportArray** aRetval)
|
||||
{
|
||||
if (!XRE_IsParentProcess()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
nsCOMPtr<mozISandboxReportArray> wrapper =
|
||||
new SandboxReportArray(SandboxReporter::Singleton()->GetSnapshot());
|
||||
wrapper.forget(aRetval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(SandboxReporterWrapper)
|
||||
|
||||
NS_DEFINE_NAMED_CID(MOZ_SANDBOX_REPORTER_CID);
|
||||
|
||||
static const mozilla::Module::CIDEntry kSandboxReporterCIDs[] = {
|
||||
{ &kMOZ_SANDBOX_REPORTER_CID, false, nullptr,
|
||||
SandboxReporterWrapperConstructor },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const mozilla::Module::ContractIDEntry kSandboxReporterContracts[] = {
|
||||
{ MOZ_SANDBOX_REPORTER_CONTRACTID, &kMOZ_SANDBOX_REPORTER_CID },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const mozilla::Module kSandboxReporterModule = {
|
||||
mozilla::Module::kVersion,
|
||||
kSandboxReporterCIDs,
|
||||
kSandboxReporterContracts
|
||||
};
|
||||
|
||||
NSMODULE_DEFN(SandboxReporterModule) = &kSandboxReporterModule;
|
||||
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,30 @@
|
|||
# -*- Mode: python; python-indent: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'SandboxReporter.h',
|
||||
'SandboxReporterCommon.h',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'SandboxReporter.cpp',
|
||||
'SandboxReporterWrappers.cpp',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/security/sandbox/linux', # SandboxLogging.h
|
||||
]
|
||||
|
||||
# Need this for base::PlatformThread
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
# Need this for safe_sprintf.h used by SandboxLogging.h,
|
||||
# but it has to be after ipc/chromium/src.
|
||||
LOCAL_INCLUDES += [
|
||||
'/security/sandbox/chromium',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
|
@ -10553,6 +10553,16 @@
|
|||
"cpp_guard": "XP_LINUX",
|
||||
"description": "Whether the sandbox is enabled for the content process"
|
||||
},
|
||||
"SANDBOX_REJECTED_SYSCALLS": {
|
||||
"alert_emails": ["jld@mozilla.com", "gcp@mozilla.com"],
|
||||
"bug_numbers": [1286865],
|
||||
"expires_in_version": "never",
|
||||
"releaseChannelCollection": "opt-out",
|
||||
"kind": "count",
|
||||
"keyed": true,
|
||||
"cpp_guard": "XP_LINUX",
|
||||
"description": "System calls blocked by a seccomp-bpf sandbox policy; limited to syscalls where we would crash on Nightly. The key is generally the architecture and syscall ID but in some cases we include non-personally-identifying information from the syscall arguments; see the function SubmitToTelemetry in security/sandbox/linux/reporter/SandboxReporter.cpp for details."
|
||||
},
|
||||
"SYNC_WORKER_OPERATION": {
|
||||
"alert_emails": ["amarchesini@mozilla.com", "khuey@mozilla.com" ],
|
||||
"bug_numbers": [1267904],
|
||||
|
|
|
@ -587,11 +587,36 @@ var snapshotFormatters = {
|
|||
data[key] === data["hasUserNamespaces"]) {
|
||||
continue;
|
||||
}
|
||||
if (key === "syscallLog") {
|
||||
// Not in this table.
|
||||
continue;
|
||||
}
|
||||
tbody.appendChild($.new("tr", [
|
||||
$.new("th", strings.GetStringFromName(key), "column"),
|
||||
$.new("td", data[key])
|
||||
$.new("td", data[key]),
|
||||
]));
|
||||
}
|
||||
|
||||
let syscallBody = $("sandbox-syscalls-tbody");
|
||||
let argsHead = $("sandbox-syscalls-argshead");
|
||||
for (let syscall of data.syscallLog) {
|
||||
if (argsHead.colSpan < syscall.args.length) {
|
||||
argsHead.colSpan = syscall.args.length;
|
||||
}
|
||||
let cells = [
|
||||
$.new("td", syscall.index, "integer"),
|
||||
$.new("td", syscall.msecAgo / 1000),
|
||||
$.new("td", syscall.pid, "integer"),
|
||||
$.new("td", syscall.tid, "integer"),
|
||||
$.new("td", strings.GetStringFromName("sandboxProcType." +
|
||||
syscall.procType)),
|
||||
$.new("td", syscall.syscall, "integer"),
|
||||
];
|
||||
for (let arg of syscall.args) {
|
||||
cells.push($.new("td", arg, "integer"));
|
||||
}
|
||||
syscallBody.appendChild($.new("tr", cells));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -548,6 +548,39 @@
|
|||
<tbody id="sandbox-tbody">
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
#if defined(XP_LINUX)
|
||||
<h4>&aboutSupport.sandboxSyscallLogTitle;</h4>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
&aboutSupport.sandboxSyscallIndex;
|
||||
</th>
|
||||
<th>
|
||||
&aboutSupport.sandboxSyscallAge;
|
||||
</th>
|
||||
<th>
|
||||
&aboutSupport.sandboxSyscallPID;
|
||||
</th>
|
||||
<th>
|
||||
&aboutSupport.sandboxSyscallTID;
|
||||
</th>
|
||||
<th>
|
||||
&aboutSupport.sandboxSyscallProcType;
|
||||
</th>
|
||||
<th>
|
||||
&aboutSupport.sandboxSyscallNumber;
|
||||
</th>
|
||||
<th id="sandbox-syscalls-argshead">
|
||||
&aboutSupport.sandboxSyscallArgs;
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="sandbox-syscalls-tbody">
|
||||
</tbody>
|
||||
</table>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
</div>
|
||||
|
|
|
@ -110,6 +110,14 @@ variant of aboutSupport.showDir.label. -->
|
|||
<!ENTITY aboutSupport.copyRawDataToClipboard.label "Copy raw data to clipboard">
|
||||
|
||||
<!ENTITY aboutSupport.sandboxTitle "Sandbox">
|
||||
<!ENTITY aboutSupport.sandboxSyscallLogTitle "Rejected System Calls">
|
||||
<!ENTITY aboutSupport.sandboxSyscallIndex "#">
|
||||
<!ENTITY aboutSupport.sandboxSyscallAge "Seconds Ago">
|
||||
<!ENTITY aboutSupport.sandboxSyscallPID "PID">
|
||||
<!ENTITY aboutSupport.sandboxSyscallTID "TID">
|
||||
<!ENTITY aboutSupport.sandboxSyscallProcType "Process Type">
|
||||
<!ENTITY aboutSupport.sandboxSyscallNumber "Syscall">
|
||||
<!ENTITY aboutSupport.sandboxSyscallArgs "Arguments">
|
||||
|
||||
<!ENTITY aboutSupport.safeModeTitle "Try Safe Mode">
|
||||
<!ENTITY aboutSupport.restartInSafeMode.label "Restart with Add-ons Disabled…">
|
||||
|
|
|
@ -104,6 +104,8 @@ hasPrivilegedUserNamespaces = User Namespaces for privileged processes
|
|||
canSandboxContent = Content Process Sandboxing
|
||||
canSandboxMedia = Media Plugin Sandboxing
|
||||
contentSandboxLevel = Content Process Sandbox Level
|
||||
sandboxProcType.content = content
|
||||
sandboxProcType.mediaPlugin = media plugin
|
||||
|
||||
# LOCALIZATION NOTE %1$S and %2$S will be replaced with the number of remote and the total number
|
||||
# of windows, respectively, while %3$S will be replaced with one of the status strings below,
|
||||
|
|
|
@ -575,6 +575,21 @@ if (AppConstants.MOZ_SANDBOX) {
|
|||
data[key] = sysInfo.getPropertyAsBool(key);
|
||||
}
|
||||
}
|
||||
|
||||
let reporter = Cc["@mozilla.org/sandbox/syscall-reporter;1"].
|
||||
getService(Ci.mozISandboxReporter);
|
||||
const snapshot = reporter.snapshot();
|
||||
let syscalls = [];
|
||||
for (let index = snapshot.begin; index < snapshot.end; ++index) {
|
||||
let report = snapshot.getElement(index);
|
||||
let { msecAgo, pid, tid, procType, syscall } = report;
|
||||
let args = []
|
||||
for (let i = 0; i < report.numArgs; ++i) {
|
||||
args.push(report.getArg(i));
|
||||
}
|
||||
syscalls.push({ index, msecAgo, pid, tid, procType, syscall, args });
|
||||
}
|
||||
data.syscallLog = syscalls;
|
||||
}
|
||||
|
||||
if (AppConstants.MOZ_CONTENT_SANDBOX) {
|
||||
|
|
|
@ -487,6 +487,42 @@ const SNAPSHOT_SCHEMA = {
|
|||
required: AppConstants.MOZ_CONTENT_SANDBOX,
|
||||
type: "number"
|
||||
},
|
||||
syscallLog: {
|
||||
required: AppConstants.platform == "linux",
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
properties: {
|
||||
index: {
|
||||
required: true,
|
||||
type: "number",
|
||||
},
|
||||
pid: {
|
||||
required: true,
|
||||
type: "number",
|
||||
},
|
||||
tid: {
|
||||
required: true,
|
||||
type: "number",
|
||||
},
|
||||
procType: {
|
||||
required: true,
|
||||
type: "string",
|
||||
},
|
||||
syscall: {
|
||||
required: true,
|
||||
type: "number",
|
||||
},
|
||||
args: {
|
||||
required: true,
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -69,6 +69,11 @@ td {
|
|||
border-color: var(--in-content-table-border-dark-color);
|
||||
}
|
||||
|
||||
td.integer {
|
||||
text-align: end;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.prefs-table {
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
|
|
Загрузка…
Ссылка в новой задаче