mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-30 12:27:29 +09:00
Remove content process sandbox code.
This commit is contained in:
parent
d87cc84005
commit
369378d566
41 changed files with 1 additions and 1823 deletions
|
|
@ -89,15 +89,6 @@ InitLoggingIfRequired(ProvideLogFunctionCb aProvideLogFunctionCb)
|
|||
if (Preferences::GetBool("security.sandbox.windows.log") ||
|
||||
PR_GetEnv("MOZ_WIN_SANDBOX_LOGGING")) {
|
||||
aProvideLogFunctionCb(Log);
|
||||
|
||||
#if defined(MOZ_CONTENT_SANDBOX)
|
||||
// We can only log the stack trace on process types where we know that the
|
||||
// sandbox won't prevent it.
|
||||
if (XRE_IsContentProcess()) {
|
||||
Preferences::AddUintVarCache(&sStackTraceDepth,
|
||||
"security.sandbox.windows.log.stackTraceDepth");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -626,34 +626,6 @@ SandboxEarlyInit(GeckoProcessType aType)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef MOZ_CONTENT_SANDBOX
|
||||
/**
|
||||
* Starts the seccomp sandbox for a content process. Should be called
|
||||
* only once, and before any potentially harmful content is loaded.
|
||||
*
|
||||
* Will normally make the process exit on failure.
|
||||
*/
|
||||
bool
|
||||
SetContentProcessSandbox(int aBrokerFd)
|
||||
{
|
||||
if (!SandboxInfo::Get().Test(SandboxInfo::kEnabledForContent)) {
|
||||
if (aBrokerFd >= 0) {
|
||||
close(aBrokerFd);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// This needs to live until the process exits.
|
||||
static Maybe<SandboxBrokerClient> sBroker;
|
||||
if (aBrokerFd >= 0) {
|
||||
sBroker.emplace(aBrokerFd);
|
||||
}
|
||||
|
||||
SetCurrentProcessSandbox(GetContentSandboxPolicy(sBroker.ptrOr(nullptr)));
|
||||
return true;
|
||||
}
|
||||
#endif // MOZ_CONTENT_SANDBOX
|
||||
|
||||
#ifdef MOZ_GMP_SANDBOX
|
||||
/**
|
||||
* Starts the seccomp sandbox for a media plugin process. Should be
|
||||
|
|
|
|||
|
|
@ -19,14 +19,6 @@ namespace mozilla {
|
|||
// This must be called early, while the process is still single-threaded.
|
||||
MOZ_EXPORT void SandboxEarlyInit(GeckoProcessType aType);
|
||||
|
||||
#ifdef MOZ_CONTENT_SANDBOX
|
||||
// Call only if SandboxInfo::CanSandboxContent() returns true.
|
||||
// (No-op if MOZ_DISABLE_CONTENT_SANDBOX is set.)
|
||||
// aBrokerFd is the filesystem broker client file descriptor,
|
||||
// or -1 to allow direct filesystem access.
|
||||
MOZ_EXPORT bool SetContentProcessSandbox(int aBrokerFd);
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_GMP_SANDBOX
|
||||
// Call only if SandboxInfo::CanSandboxMedia() returns true.
|
||||
// (No-op if MOZ_DISABLE_GMP_SANDBOX is set.)
|
||||
|
|
|
|||
|
|
@ -340,495 +340,6 @@ public:
|
|||
|
||||
// The process-type-specific syscall rules start here:
|
||||
|
||||
#ifdef MOZ_CONTENT_SANDBOX
|
||||
// The seccomp-bpf filter for content processes is not a true sandbox
|
||||
// on its own; its purpose is attack surface reduction and syscall
|
||||
// interception in support of a semantic sandboxing layer. On B2G
|
||||
// this is the Android process permission model; on desktop,
|
||||
// namespaces and chroot() will be used.
|
||||
class ContentSandboxPolicy : public SandboxPolicyCommon {
|
||||
SandboxBrokerClient* mBroker;
|
||||
|
||||
// Trap handlers for filesystem brokering.
|
||||
// (The amount of code duplication here could be improved....)
|
||||
#ifdef __NR_open
|
||||
static intptr_t OpenTrap(ArgsRef aArgs, void* aux) {
|
||||
auto broker = static_cast<SandboxBrokerClient*>(aux);
|
||||
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
|
||||
auto flags = static_cast<int>(aArgs.args[1]);
|
||||
return broker->Open(path, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
static intptr_t OpenAtTrap(ArgsRef aArgs, void* aux) {
|
||||
auto broker = static_cast<SandboxBrokerClient*>(aux);
|
||||
auto fd = static_cast<int>(aArgs.args[0]);
|
||||
auto path = reinterpret_cast<const char*>(aArgs.args[1]);
|
||||
auto flags = static_cast<int>(aArgs.args[2]);
|
||||
if (fd != AT_FDCWD && path[0] != '/') {
|
||||
SANDBOX_LOG_ERROR("unsupported fd-relative openat(%d, \"%s\", 0%o)",
|
||||
fd, path, flags);
|
||||
return BlockedSyscallTrap(aArgs, nullptr);
|
||||
}
|
||||
return broker->Open(path, flags);
|
||||
}
|
||||
|
||||
#ifdef __NR_access
|
||||
static intptr_t AccessTrap(ArgsRef aArgs, void* aux) {
|
||||
auto broker = static_cast<SandboxBrokerClient*>(aux);
|
||||
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
|
||||
auto mode = static_cast<int>(aArgs.args[1]);
|
||||
return broker->Access(path, mode);
|
||||
}
|
||||
#endif
|
||||
|
||||
static intptr_t AccessAtTrap(ArgsRef aArgs, void* aux) {
|
||||
auto broker = static_cast<SandboxBrokerClient*>(aux);
|
||||
auto fd = static_cast<int>(aArgs.args[0]);
|
||||
auto path = reinterpret_cast<const char*>(aArgs.args[1]);
|
||||
auto mode = static_cast<int>(aArgs.args[2]);
|
||||
// Linux's faccessat syscall has no "flags" argument. Attempting
|
||||
// to handle the flags != 0 case is left to userspace; this is
|
||||
// impossible to do correctly in all cases, but that's not our
|
||||
// problem.
|
||||
if (fd != AT_FDCWD && path[0] != '/') {
|
||||
SANDBOX_LOG_ERROR("unsupported fd-relative faccessat(%d, \"%s\", %d)",
|
||||
fd, path, mode);
|
||||
return BlockedSyscallTrap(aArgs, nullptr);
|
||||
}
|
||||
return broker->Access(path, mode);
|
||||
}
|
||||
|
||||
static intptr_t StatTrap(ArgsRef aArgs, void* aux) {
|
||||
auto broker = static_cast<SandboxBrokerClient*>(aux);
|
||||
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
|
||||
auto buf = reinterpret_cast<statstruct*>(aArgs.args[1]);
|
||||
return broker->Stat(path, buf);
|
||||
}
|
||||
|
||||
static intptr_t LStatTrap(ArgsRef aArgs, void* aux) {
|
||||
auto broker = static_cast<SandboxBrokerClient*>(aux);
|
||||
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
|
||||
auto buf = reinterpret_cast<statstruct*>(aArgs.args[1]);
|
||||
return broker->LStat(path, buf);
|
||||
}
|
||||
|
||||
static intptr_t StatAtTrap(ArgsRef aArgs, void* aux) {
|
||||
auto broker = static_cast<SandboxBrokerClient*>(aux);
|
||||
auto fd = static_cast<int>(aArgs.args[0]);
|
||||
auto path = reinterpret_cast<const char*>(aArgs.args[1]);
|
||||
auto buf = reinterpret_cast<statstruct*>(aArgs.args[2]);
|
||||
auto flags = static_cast<int>(aArgs.args[3]);
|
||||
if (fd != AT_FDCWD && path[0] != '/') {
|
||||
SANDBOX_LOG_ERROR("unsupported fd-relative fstatat(%d, \"%s\", %p, %d)",
|
||||
fd, path, buf, flags);
|
||||
return BlockedSyscallTrap(aArgs, nullptr);
|
||||
}
|
||||
if ((flags & ~AT_SYMLINK_NOFOLLOW) != 0) {
|
||||
SANDBOX_LOG_ERROR("unsupported flags %d in fstatat(%d, \"%s\", %p, %d)",
|
||||
(flags & ~AT_SYMLINK_NOFOLLOW), fd, path, buf, flags);
|
||||
return BlockedSyscallTrap(aArgs, nullptr);
|
||||
}
|
||||
return (flags & AT_SYMLINK_NOFOLLOW) == 0
|
||||
? broker->Stat(path, buf)
|
||||
: broker->LStat(path, buf);
|
||||
}
|
||||
|
||||
static intptr_t ChmodTrap(ArgsRef aArgs, void* aux) {
|
||||
auto broker = static_cast<SandboxBrokerClient*>(aux);
|
||||
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
|
||||
auto mode = static_cast<mode_t>(aArgs.args[1]);
|
||||
return broker->Chmod(path, mode);
|
||||
}
|
||||
|
||||
static intptr_t LinkTrap(ArgsRef aArgs, void *aux) {
|
||||
auto broker = static_cast<SandboxBrokerClient*>(aux);
|
||||
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
|
||||
auto path2 = reinterpret_cast<const char*>(aArgs.args[1]);
|
||||
return broker->Link(path, path2);
|
||||
}
|
||||
|
||||
static intptr_t SymlinkTrap(ArgsRef aArgs, void *aux) {
|
||||
auto broker = static_cast<SandboxBrokerClient*>(aux);
|
||||
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
|
||||
auto path2 = reinterpret_cast<const char*>(aArgs.args[1]);
|
||||
return broker->Symlink(path, path2);
|
||||
}
|
||||
|
||||
static intptr_t RenameTrap(ArgsRef aArgs, void *aux) {
|
||||
auto broker = static_cast<SandboxBrokerClient*>(aux);
|
||||
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
|
||||
auto path2 = reinterpret_cast<const char*>(aArgs.args[1]);
|
||||
return broker->Rename(path, path2);
|
||||
}
|
||||
|
||||
static intptr_t MkdirTrap(ArgsRef aArgs, void* aux) {
|
||||
auto broker = static_cast<SandboxBrokerClient*>(aux);
|
||||
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
|
||||
auto mode = static_cast<mode_t>(aArgs.args[1]);
|
||||
return broker->Mkdir(path, mode);
|
||||
}
|
||||
|
||||
static intptr_t RmdirTrap(ArgsRef aArgs, void* aux) {
|
||||
auto broker = static_cast<SandboxBrokerClient*>(aux);
|
||||
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
|
||||
return broker->Rmdir(path);
|
||||
}
|
||||
|
||||
static intptr_t UnlinkTrap(ArgsRef aArgs, void* aux) {
|
||||
auto broker = static_cast<SandboxBrokerClient*>(aux);
|
||||
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
|
||||
return broker->Unlink(path);
|
||||
}
|
||||
|
||||
static intptr_t ReadlinkTrap(ArgsRef aArgs, void* aux) {
|
||||
auto broker = static_cast<SandboxBrokerClient*>(aux);
|
||||
auto path = reinterpret_cast<const char*>(aArgs.args[0]);
|
||||
auto buf = reinterpret_cast<char*>(aArgs.args[1]);
|
||||
auto size = static_cast<size_t>(aArgs.args[2]);
|
||||
return broker->Readlink(path, buf, size);
|
||||
}
|
||||
|
||||
static intptr_t GetPPidTrap(ArgsRef aArgs, void* aux) {
|
||||
// In a pid namespace, getppid() will return 0. We will return 0 instead
|
||||
// of the real parent pid to see what breaks when we introduce the
|
||||
// pid namespace (Bug 1151624).
|
||||
return 0;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit ContentSandboxPolicy(SandboxBrokerClient* aBroker):mBroker(aBroker) { }
|
||||
virtual ~ContentSandboxPolicy() { }
|
||||
virtual ResultExpr PrctlPolicy() const override {
|
||||
// Ideally this should be restricted to a whitelist, but content
|
||||
// uses enough things that it's not trivial to determine it.
|
||||
return Allow();
|
||||
}
|
||||
virtual Maybe<ResultExpr> EvaluateSocketCall(int aCall) const override {
|
||||
switch(aCall) {
|
||||
case SYS_RECVFROM:
|
||||
case SYS_SENDTO:
|
||||
return Some(Allow());
|
||||
|
||||
case SYS_SOCKETPAIR: {
|
||||
// See bug 1066750.
|
||||
if (!kSocketCallHasArgs) {
|
||||
// We can't filter the args if the platform passes them by pointer.
|
||||
return Some(Allow());
|
||||
}
|
||||
Arg<int> domain(0), type(1);
|
||||
return Some(If(AllOf(domain == AF_UNIX,
|
||||
AnyOf(type == SOCK_STREAM, type == SOCK_SEQPACKET)),
|
||||
Allow())
|
||||
.Else(InvalidSyscall()));
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
case SYS_SOCKET:
|
||||
return Some(Error(EACCES));
|
||||
#else // #ifdef DESKTOP
|
||||
case SYS_RECV:
|
||||
case SYS_SEND:
|
||||
case SYS_SOCKET: // DANGEROUS
|
||||
case SYS_CONNECT: // DANGEROUS
|
||||
case SYS_ACCEPT:
|
||||
case SYS_ACCEPT4:
|
||||
case SYS_BIND:
|
||||
case SYS_LISTEN:
|
||||
case SYS_GETSOCKOPT:
|
||||
case SYS_SETSOCKOPT:
|
||||
case SYS_GETSOCKNAME:
|
||||
case SYS_GETPEERNAME:
|
||||
case SYS_SHUTDOWN:
|
||||
return Some(Allow());
|
||||
#endif
|
||||
default:
|
||||
return SandboxPolicyCommon::EvaluateSocketCall(aCall);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DESKTOP
|
||||
virtual Maybe<ResultExpr> EvaluateIpcCall(int aCall) const override {
|
||||
switch(aCall) {
|
||||
// These are a problem: SysV shared memory follows the Unix
|
||||
// "same uid policy" and can't be restricted/brokered like file
|
||||
// access. But the graphics layer might not be using them
|
||||
// anymore; this needs to be studied.
|
||||
case SHMGET:
|
||||
case SHMCTL:
|
||||
case SHMAT:
|
||||
case SHMDT:
|
||||
case SEMGET:
|
||||
case SEMCTL:
|
||||
case SEMOP:
|
||||
case MSGGET:
|
||||
return Some(Allow());
|
||||
default:
|
||||
return SandboxPolicyCommon::EvaluateIpcCall(aCall);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual ResultExpr EvaluateSyscall(int sysno) const override {
|
||||
if (mBroker) {
|
||||
// Have broker; route the appropriate syscalls to it.
|
||||
switch (sysno) {
|
||||
case __NR_open:
|
||||
return Trap(OpenTrap, mBroker);
|
||||
case __NR_openat:
|
||||
return Trap(OpenAtTrap, mBroker);
|
||||
case __NR_access:
|
||||
return Trap(AccessTrap, mBroker);
|
||||
case __NR_faccessat:
|
||||
return Trap(AccessAtTrap, mBroker);
|
||||
CASES_FOR_stat:
|
||||
return Trap(StatTrap, mBroker);
|
||||
CASES_FOR_lstat:
|
||||
return Trap(LStatTrap, mBroker);
|
||||
CASES_FOR_fstatat:
|
||||
return Trap(StatAtTrap, mBroker);
|
||||
case __NR_chmod:
|
||||
return Trap(ChmodTrap, mBroker);
|
||||
case __NR_link:
|
||||
return Trap(LinkTrap, mBroker);
|
||||
case __NR_mkdir:
|
||||
return Trap(MkdirTrap, mBroker);
|
||||
case __NR_symlink:
|
||||
return Trap(SymlinkTrap, mBroker);
|
||||
case __NR_rename:
|
||||
return Trap(RenameTrap, mBroker);
|
||||
case __NR_rmdir:
|
||||
return Trap(RmdirTrap, mBroker);
|
||||
case __NR_unlink:
|
||||
return Trap(UnlinkTrap, mBroker);
|
||||
case __NR_readlink:
|
||||
return Trap(ReadlinkTrap, mBroker);
|
||||
}
|
||||
} else {
|
||||
// No broker; allow the syscalls directly. )-:
|
||||
switch(sysno) {
|
||||
case __NR_open:
|
||||
case __NR_openat:
|
||||
case __NR_access:
|
||||
case __NR_faccessat:
|
||||
CASES_FOR_stat:
|
||||
CASES_FOR_lstat:
|
||||
CASES_FOR_fstatat:
|
||||
case __NR_chmod:
|
||||
case __NR_link:
|
||||
case __NR_mkdir:
|
||||
case __NR_symlink:
|
||||
case __NR_rename:
|
||||
case __NR_rmdir:
|
||||
case __NR_unlink:
|
||||
case __NR_readlink:
|
||||
return Allow();
|
||||
}
|
||||
}
|
||||
|
||||
switch (sysno) {
|
||||
#ifdef DESKTOP
|
||||
case __NR_getppid:
|
||||
return Trap(GetPPidTrap, nullptr);
|
||||
|
||||
// Filesystem syscalls that need more work to determine who's
|
||||
// using them, if they need to be, and what we intend to about it.
|
||||
case __NR_getcwd:
|
||||
CASES_FOR_statfs:
|
||||
CASES_FOR_fstatfs:
|
||||
case __NR_quotactl:
|
||||
CASES_FOR_fchown:
|
||||
case __NR_fchmod:
|
||||
case __NR_flock:
|
||||
#endif
|
||||
return Allow();
|
||||
|
||||
case __NR_readlinkat:
|
||||
#ifdef DESKTOP
|
||||
// Bug 1290896
|
||||
return Allow();
|
||||
#else
|
||||
// Workaround for bug 964455:
|
||||
return Error(EINVAL);
|
||||
#endif
|
||||
|
||||
CASES_FOR_select:
|
||||
case __NR_pselect6:
|
||||
return Allow();
|
||||
|
||||
CASES_FOR_getdents:
|
||||
CASES_FOR_ftruncate:
|
||||
case __NR_writev:
|
||||
case __NR_pread64:
|
||||
#ifdef DESKTOP
|
||||
case __NR_pwrite64:
|
||||
case __NR_readahead:
|
||||
#endif
|
||||
return Allow();
|
||||
|
||||
case __NR_ioctl:
|
||||
// ioctl() is for GL. Remove when GL proxy is implemented.
|
||||
// Additionally ioctl() might be a place where we want to have
|
||||
// argument filtering
|
||||
return Allow();
|
||||
|
||||
CASES_FOR_fcntl:
|
||||
// Some fcntls have significant side effects like sending
|
||||
// arbitrary signals, and there's probably nontrivial kernel
|
||||
// attack surface; this should be locked down more if possible.
|
||||
return Allow();
|
||||
|
||||
case __NR_mprotect:
|
||||
case __NR_brk:
|
||||
case __NR_madvise:
|
||||
#if !defined(MOZ_MEMORY)
|
||||
// libc's realloc uses mremap (Bug 1286119).
|
||||
case __NR_mremap:
|
||||
#endif
|
||||
return Allow();
|
||||
|
||||
case __NR_sigaltstack:
|
||||
return Allow();
|
||||
|
||||
#ifdef __NR_set_thread_area
|
||||
case __NR_set_thread_area:
|
||||
return Allow();
|
||||
#endif
|
||||
|
||||
case __NR_getrusage:
|
||||
case __NR_times:
|
||||
return Allow();
|
||||
|
||||
case __NR_dup:
|
||||
return Allow();
|
||||
|
||||
CASES_FOR_getuid:
|
||||
CASES_FOR_getgid:
|
||||
CASES_FOR_geteuid:
|
||||
CASES_FOR_getegid:
|
||||
return Allow();
|
||||
|
||||
case __NR_fsync:
|
||||
case __NR_msync:
|
||||
return Allow();
|
||||
|
||||
case __NR_getpriority:
|
||||
case __NR_setpriority:
|
||||
case __NR_sched_get_priority_min:
|
||||
case __NR_sched_get_priority_max:
|
||||
case __NR_sched_getscheduler:
|
||||
case __NR_sched_setscheduler:
|
||||
case __NR_sched_getparam:
|
||||
case __NR_sched_setparam:
|
||||
#ifdef DESKTOP
|
||||
case __NR_sched_getaffinity:
|
||||
#endif
|
||||
return Allow();
|
||||
|
||||
#ifdef DESKTOP
|
||||
case __NR_pipe2:
|
||||
return Allow();
|
||||
|
||||
CASES_FOR_getrlimit:
|
||||
case __NR_clock_getres:
|
||||
CASES_FOR_getresuid:
|
||||
CASES_FOR_getresgid:
|
||||
return Allow();
|
||||
|
||||
case __NR_umask:
|
||||
case __NR_kill:
|
||||
case __NR_wait4:
|
||||
#ifdef __NR_waitpid
|
||||
case __NR_waitpid:
|
||||
#endif
|
||||
#ifdef __NR_arch_prctl
|
||||
case __NR_arch_prctl:
|
||||
#endif
|
||||
return Allow();
|
||||
|
||||
case __NR_eventfd2:
|
||||
case __NR_inotify_init1:
|
||||
case __NR_inotify_add_watch:
|
||||
case __NR_inotify_rm_watch:
|
||||
return Allow();
|
||||
|
||||
#ifdef __NR_memfd_create
|
||||
case __NR_memfd_create:
|
||||
return Allow();
|
||||
#endif
|
||||
|
||||
#ifdef __NR_rt_tgsigqueueinfo
|
||||
// Only allow to send signals within the process.
|
||||
case __NR_rt_tgsigqueueinfo: {
|
||||
Arg<pid_t> tgid(0);
|
||||
return If(tgid == getpid(), Allow())
|
||||
.Else(InvalidSyscall());
|
||||
}
|
||||
#endif
|
||||
|
||||
case __NR_mlock:
|
||||
case __NR_munlock:
|
||||
return Allow();
|
||||
|
||||
// We can't usefully allow fork+exec, even on a temporary basis;
|
||||
// the child would inherit the seccomp-bpf policy and almost
|
||||
// certainly die from an unexpected SIGSYS. We also can't have
|
||||
// fork() crash, currently, because there are too many system
|
||||
// libraries/plugins that try to run commands. But they can
|
||||
// usually do something reasonable on error.
|
||||
case __NR_clone:
|
||||
return ClonePolicy(Error(EPERM));
|
||||
|
||||
#ifdef __NR_fadvise64
|
||||
case __NR_fadvise64:
|
||||
return Allow();
|
||||
#endif
|
||||
|
||||
#ifdef __NR_fadvise64_64
|
||||
case __NR_fadvise64_64:
|
||||
return Allow();
|
||||
#endif
|
||||
|
||||
case __NR_fallocate:
|
||||
return Allow();
|
||||
|
||||
case __NR_get_mempolicy:
|
||||
return Allow();
|
||||
|
||||
#endif // DESKTOP
|
||||
|
||||
#ifdef __NR_getrandom
|
||||
case __NR_getrandom:
|
||||
return Allow();
|
||||
#endif
|
||||
|
||||
// nsSystemInfo uses uname (and we cache an instance, so
|
||||
// the info remains present even if we block the syscall)
|
||||
case __NR_uname:
|
||||
#ifdef DESKTOP
|
||||
case __NR_sysinfo:
|
||||
#endif
|
||||
return Allow();
|
||||
|
||||
#ifdef MOZ_JPROF
|
||||
case __NR_setitimer:
|
||||
return Allow();
|
||||
#endif // MOZ_JPROF
|
||||
|
||||
default:
|
||||
return SandboxPolicyCommon::EvaluateSyscall(sysno);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
UniquePtr<sandbox::bpf_dsl::Policy>
|
||||
GetContentSandboxPolicy(SandboxBrokerClient* aMaybeBroker)
|
||||
{
|
||||
return UniquePtr<sandbox::bpf_dsl::Policy>(new ContentSandboxPolicy(aMaybeBroker));
|
||||
}
|
||||
#endif // MOZ_CONTENT_SANDBOX
|
||||
|
||||
|
||||
#ifdef MOZ_GMP_SANDBOX
|
||||
// Unlike for content, the GeckoMediaPlugin seccomp-bpf policy needs
|
||||
// to be an effective sandbox by itself, because we allow GMP on Linux
|
||||
|
|
|
|||
|
|
@ -18,12 +18,6 @@ class Policy;
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
#ifdef MOZ_CONTENT_SANDBOX
|
||||
class SandboxBrokerClient;
|
||||
|
||||
UniquePtr<sandbox::bpf_dsl::Policy> GetContentSandboxPolicy(SandboxBrokerClient* aMaybeBroker);
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_GMP_SANDBOX
|
||||
struct SandboxOpenedFile {
|
||||
const char *mPath;
|
||||
|
|
|
|||
|
|
@ -225,14 +225,6 @@ SandboxInfo::SandboxInfo() {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef MOZ_CONTENT_SANDBOX
|
||||
if (!getenv("MOZ_DISABLE_CONTENT_SANDBOX")) {
|
||||
flags |= kEnabledForContent;
|
||||
}
|
||||
if (getenv("MOZ_PERMISSIVE_CONTENT_SANDBOX")) {
|
||||
flags |= kPermissive;
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_GMP_SANDBOX
|
||||
if (!getenv("MOZ_DISABLE_GMP_SANDBOX")) {
|
||||
flags |= kEnabledForMedia;
|
||||
|
|
|
|||
|
|
@ -41,154 +41,10 @@ SandboxBrokerPolicyFactory::IsSystemSupported() {
|
|||
return false;
|
||||
}
|
||||
|
||||
#if defined(MOZ_CONTENT_SANDBOX)
|
||||
namespace {
|
||||
static const int rdonly = SandboxBroker::MAY_READ;
|
||||
static const int wronly = SandboxBroker::MAY_WRITE;
|
||||
static const int rdwr = rdonly | wronly;
|
||||
static const int rdwrcr = rdwr | SandboxBroker::MAY_CREATE;
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
static const int wrlog = wronly | SandboxBroker::MAY_CREATE;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
SandboxBrokerPolicyFactory::SandboxBrokerPolicyFactory()
|
||||
{
|
||||
// Policy entries that are the same in every process go here, and
|
||||
// are cached over the lifetime of the factory.
|
||||
#if defined(MOZ_CONTENT_SANDBOX) && defined(MOZ_WIDGET_GONK)
|
||||
SandboxBroker::Policy* policy = new SandboxBroker::Policy;
|
||||
|
||||
// Devices that need write access:
|
||||
policy->AddPath(rdwr, "/dev/genlock"); // bug 980924
|
||||
policy->AddPath(rdwr, "/dev/ashmem"); // bug 980947
|
||||
policy->AddTree(wronly, "/dev/log"); // bug 1199857
|
||||
// Graphics devices are a significant source of attack surface, but
|
||||
// there's not much we can do about it without proxying (which is
|
||||
// very difficult and a perforamnce hit).
|
||||
policy->AddPrefix(rdwr, "/dev", "kgsl"); // bug 995072
|
||||
policy->AddPath(rdwr, "/dev/qemu_pipe"); // but 1198410: goldfish gralloc.
|
||||
|
||||
// Bug 1198475: mochitest logs. (This is actually passed in via URL
|
||||
// query param to the mochitest page, and is configurable, so this
|
||||
// isn't enough in general, but hopefully it's good enough for B2G.)
|
||||
// Conditional on tests being run, using the same check seen in
|
||||
// DirectoryProvider.js to set ProfD.
|
||||
if (access("/data/local/tests/profile", R_OK) == 0) {
|
||||
policy->AddPath(wrlog, "/data/local/tests/log/mochitest.log");
|
||||
}
|
||||
|
||||
// Read-only items below this line.
|
||||
|
||||
policy->AddPath(rdonly, "/dev/urandom"); // bug 964500, bug 995069
|
||||
policy->AddPath(rdonly, "/dev/ion"); // bug 980937
|
||||
policy->AddPath(rdonly, "/proc/cpuinfo"); // bug 995067
|
||||
policy->AddPath(rdonly, "/proc/meminfo"); // bug 1025333
|
||||
policy->AddPath(rdonly, "/sys/devices/system/cpu/present"); // bug 1025329
|
||||
policy->AddPath(rdonly, "/sys/devices/system/soc/soc0/id"); // bug 1025339
|
||||
policy->AddPath(rdonly, "/etc/media_profiles.xml"); // bug 1198419
|
||||
policy->AddPath(rdonly, "/etc/media_codecs.xml"); // bug 1198460
|
||||
policy->AddTree(rdonly, "/system/fonts"); // bug 1026063
|
||||
|
||||
// Bug 1199051 (crossplatformly, this is NS_GRE_DIR).
|
||||
policy->AddTree(rdonly, "/system/b2g");
|
||||
|
||||
// Bug 1026356: dynamic library loading from assorted frameworks we
|
||||
// don't control (media codecs, maybe others).
|
||||
//
|
||||
// Bug 1198515: Also, the profiler calls breakpad code to get info
|
||||
// on all loaded ELF objects, which opens those files.
|
||||
policy->AddTree(rdonly, "/system/lib");
|
||||
policy->AddTree(rdonly, "/vendor/lib");
|
||||
policy->AddPath(rdonly, "/system/bin/linker"); // (profiler only)
|
||||
|
||||
// Bug 1199866: EGL/WebGL.
|
||||
policy->AddPath(rdonly, "/system/lib/egl");
|
||||
policy->AddPath(rdonly, "/vendor/lib/egl");
|
||||
|
||||
// Bug 1198401: timezones. Yes, we need both of these; see bug.
|
||||
policy->AddTree(rdonly, "/system/usr/share/zoneinfo");
|
||||
policy->AddTree(rdonly, "/system//usr/share/zoneinfo");
|
||||
|
||||
policy->AddPath(rdonly, "/data/local/tmp/profiler.options",
|
||||
SandboxBroker::Policy::AddAlways); // bug 1029337
|
||||
|
||||
mCommonContentPolicy.reset(policy);
|
||||
#elif defined(MOZ_CONTENT_SANDBOX)
|
||||
SandboxBroker::Policy* policy = new SandboxBroker::Policy;
|
||||
policy->AddDir(rdonly, "/");
|
||||
policy->AddDir(rdwrcr, "/dev/shm");
|
||||
// Add write permissions on the temporary directory. This can come
|
||||
// from various environment variables (TMPDIR,TMP,TEMP,...) so
|
||||
// make sure to use the full logic.
|
||||
nsCOMPtr<nsIFile> tmpDir;
|
||||
nsresult rv = GetSpecialSystemDirectory(OS_TemporaryDirectory,
|
||||
getter_AddRefs(tmpDir));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
nsAutoCString tmpPath;
|
||||
rv = tmpDir->GetNativePath(tmpPath);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
policy->AddDir(rdwrcr, tmpPath.get());
|
||||
}
|
||||
}
|
||||
// If the above fails at any point, fall back to a very good guess.
|
||||
if (NS_FAILED(rv)) {
|
||||
policy->AddDir(rdwrcr, "/tmp");
|
||||
}
|
||||
|
||||
// Bug 1308851: NVIDIA proprietary driver when using WebGL
|
||||
policy->AddPrefix(rdwr, "/dev", "nvidia");
|
||||
|
||||
// Bug 1312678: radeonsi/Intel with DRI when using WebGL
|
||||
policy->AddDir(rdwr, "/dev/dri");
|
||||
|
||||
mCommonContentPolicy.reset(policy);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MOZ_CONTENT_SANDBOX
|
||||
UniquePtr<SandboxBroker::Policy>
|
||||
SandboxBrokerPolicyFactory::GetContentPolicy(int aPid)
|
||||
{
|
||||
// Policy entries that vary per-process (currently the only reason
|
||||
// that can happen is because they contain the pid) are added here.
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// File broker usage is controlled through a pref.
|
||||
if (Preferences::GetInt("security.sandbox.content.level") <= 1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mCommonContentPolicy);
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
// Allow overriding "unsupported"ness with a pref, for testing.
|
||||
if (!IsSystemSupported()) {
|
||||
return nullptr;
|
||||
}
|
||||
UniquePtr<SandboxBroker::Policy>
|
||||
policy(new SandboxBroker::Policy(*mCommonContentPolicy));
|
||||
|
||||
// Bug 1029337: where the profiler writes the data.
|
||||
nsPrintfCString profilerLogPath("/data/local/tmp/profile_%d_%d.txt",
|
||||
GeckoProcessType_Content, aPid);
|
||||
policy->AddPath(wrlog, profilerLogPath.get());
|
||||
|
||||
// Bug 1198550: the profiler's replacement for dl_iterate_phdr
|
||||
policy->AddPath(rdonly, nsPrintfCString("/proc/%d/maps", aPid).get());
|
||||
|
||||
// Bug 1198552: memory reporting.
|
||||
policy->AddPath(rdonly, nsPrintfCString("/proc/%d/statm", aPid).get());
|
||||
policy->AddPath(rdonly, nsPrintfCString("/proc/%d/smaps", aPid).get());
|
||||
|
||||
return policy;
|
||||
#else
|
||||
UniquePtr<SandboxBroker::Policy>
|
||||
policy(new SandboxBroker::Policy(*mCommonContentPolicy));
|
||||
// Return the common policy.
|
||||
return policy;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // MOZ_CONTENT_SANDBOX
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
|
|
@ -15,10 +15,6 @@ class SandboxBrokerPolicyFactory {
|
|||
public:
|
||||
SandboxBrokerPolicyFactory();
|
||||
|
||||
#ifdef MOZ_CONTENT_SANDBOX
|
||||
UniquePtr<SandboxBroker::Policy> GetContentPolicy(int aPid);
|
||||
#endif
|
||||
|
||||
private:
|
||||
UniquePtr<const SandboxBroker::Policy> mCommonContentPolicy;
|
||||
// B2G devices tend to have hardware-specific paths used by device
|
||||
|
|
|
|||
|
|
@ -90,130 +90,6 @@ SandboxBroker::LaunchApp(const wchar_t *aPath,
|
|||
return true;
|
||||
}
|
||||
|
||||
#if defined(MOZ_CONTENT_SANDBOX)
|
||||
void
|
||||
SandboxBroker::SetSecurityLevelForContentProcess(int32_t aSandboxLevel)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(mPolicy, "mPolicy must be set before this call.");
|
||||
|
||||
sandbox::JobLevel jobLevel;
|
||||
sandbox::TokenLevel accessTokenLevel;
|
||||
sandbox::IntegrityLevel initialIntegrityLevel;
|
||||
sandbox::IntegrityLevel delayedIntegrityLevel;
|
||||
|
||||
// The setting of these levels is pretty arbitrary, but they are a useful (if
|
||||
// crude) tool while we are tightening the policy. Gaps are left to try and
|
||||
// avoid changing their meaning.
|
||||
MOZ_RELEASE_ASSERT(aSandboxLevel >= 1, "Should not be called with aSandboxLevel < 1");
|
||||
if (aSandboxLevel >= 20) {
|
||||
jobLevel = sandbox::JOB_LOCKDOWN;
|
||||
accessTokenLevel = sandbox::USER_LOCKDOWN;
|
||||
initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
|
||||
delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_UNTRUSTED;
|
||||
} else if (aSandboxLevel >= 10) {
|
||||
jobLevel = sandbox::JOB_RESTRICTED;
|
||||
accessTokenLevel = sandbox::USER_LIMITED;
|
||||
initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
|
||||
delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
|
||||
} else if (aSandboxLevel >= 2) {
|
||||
jobLevel = sandbox::JOB_INTERACTIVE;
|
||||
accessTokenLevel = sandbox::USER_INTERACTIVE;
|
||||
initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
|
||||
delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
|
||||
} else if (aSandboxLevel == 1) {
|
||||
jobLevel = sandbox::JOB_NONE;
|
||||
accessTokenLevel = sandbox::USER_NON_ADMIN;
|
||||
initialIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
|
||||
delayedIntegrityLevel = sandbox::INTEGRITY_LEVEL_LOW;
|
||||
}
|
||||
|
||||
sandbox::ResultCode result = mPolicy->SetJobLevel(jobLevel,
|
||||
0 /* ui_exceptions */);
|
||||
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
||||
"Setting job level failed, have you set memory limit when jobLevel == JOB_NONE?");
|
||||
|
||||
// If the delayed access token is not restricted we don't want the initial one
|
||||
// to be either, because it can interfere with running from a network drive.
|
||||
sandbox::TokenLevel initialAccessTokenLevel =
|
||||
(accessTokenLevel == sandbox::USER_UNPROTECTED ||
|
||||
accessTokenLevel == sandbox::USER_NON_ADMIN)
|
||||
? sandbox::USER_UNPROTECTED : sandbox::USER_RESTRICTED_SAME_ACCESS;
|
||||
|
||||
result = mPolicy->SetTokenLevel(initialAccessTokenLevel, accessTokenLevel);
|
||||
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
||||
"Lockdown level cannot be USER_UNPROTECTED or USER_LAST if initial level was USER_RESTRICTED_SAME_ACCESS");
|
||||
|
||||
result = mPolicy->SetIntegrityLevel(initialIntegrityLevel);
|
||||
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
||||
"SetIntegrityLevel should never fail, what happened?");
|
||||
result = mPolicy->SetDelayedIntegrityLevel(delayedIntegrityLevel);
|
||||
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
||||
"SetDelayedIntegrityLevel should never fail, what happened?");
|
||||
|
||||
if (aSandboxLevel > 2) {
|
||||
result = mPolicy->SetAlternateDesktop(true);
|
||||
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
||||
"Failed to create alternate desktop for sandbox.");
|
||||
}
|
||||
|
||||
sandbox::MitigationFlags mitigations =
|
||||
sandbox::MITIGATION_BOTTOM_UP_ASLR |
|
||||
sandbox::MITIGATION_HEAP_TERMINATE |
|
||||
sandbox::MITIGATION_SEHOP |
|
||||
sandbox::MITIGATION_DEP_NO_ATL_THUNK |
|
||||
sandbox::MITIGATION_DEP;
|
||||
|
||||
result = mPolicy->SetProcessMitigations(mitigations);
|
||||
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
||||
"Invalid flags for SetProcessMitigations.");
|
||||
|
||||
mitigations =
|
||||
sandbox::MITIGATION_STRICT_HANDLE_CHECKS |
|
||||
sandbox::MITIGATION_DLL_SEARCH_ORDER;
|
||||
|
||||
result = mPolicy->SetDelayedProcessMitigations(mitigations);
|
||||
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
||||
"Invalid flags for SetDelayedProcessMitigations.");
|
||||
|
||||
// Add the policy for the client side of a pipe. It is just a file
|
||||
// in the \pipe\ namespace. We restrict it to pipes that start with
|
||||
// "chrome." so the sandboxed process cannot connect to system services.
|
||||
result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
|
||||
sandbox::TargetPolicy::FILES_ALLOW_ANY,
|
||||
L"\\??\\pipe\\chrome.*");
|
||||
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
||||
"With these static arguments AddRule should never fail, what happened?");
|
||||
|
||||
// Add the policy for the client side of the crash server pipe.
|
||||
result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_FILES,
|
||||
sandbox::TargetPolicy::FILES_ALLOW_ANY,
|
||||
L"\\??\\pipe\\gecko-crash-server-pipe.*");
|
||||
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
||||
"With these static arguments AddRule should never fail, what happened?");
|
||||
|
||||
// The content process needs to be able to duplicate named pipes back to the
|
||||
// broker process, which are File type handles.
|
||||
result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_HANDLES,
|
||||
sandbox::TargetPolicy::HANDLES_DUP_BROKER,
|
||||
L"File");
|
||||
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
||||
"With these static arguments AddRule should never fail, what happened?");
|
||||
|
||||
// The content process needs to be able to duplicate shared memory handles,
|
||||
// which are Section handles, to the broker process and other child processes.
|
||||
result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_HANDLES,
|
||||
sandbox::TargetPolicy::HANDLES_DUP_BROKER,
|
||||
L"Section");
|
||||
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
||||
"With these static arguments AddRule should never fail, what happened?");
|
||||
result = mPolicy->AddRule(sandbox::TargetPolicy::SUBSYS_HANDLES,
|
||||
sandbox::TargetPolicy::HANDLES_DUP_ANY,
|
||||
L"Section");
|
||||
MOZ_RELEASE_ASSERT(sandbox::SBOX_ALL_OK == result,
|
||||
"With these static arguments AddRule should never fail, what happened?");
|
||||
}
|
||||
#endif
|
||||
|
||||
#define SANDBOX_ENSURE_SUCCESS(result, message) \
|
||||
do { \
|
||||
MOZ_ASSERT(sandbox::SBOX_ALL_OK == result, message); \
|
||||
|
|
|
|||
|
|
@ -31,9 +31,6 @@ public:
|
|||
virtual ~SandboxBroker();
|
||||
|
||||
// Security levels for different types of processes
|
||||
#if defined(MOZ_CONTENT_SANDBOX)
|
||||
void SetSecurityLevelForContentProcess(int32_t aSandboxLevel);
|
||||
#endif
|
||||
bool SetSecurityLevelForPluginProcess(int32_t aSandboxLevel);
|
||||
enum SandboxLevel {
|
||||
LockDown,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue