зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1511560 - Move the socketpair handling into SandboxPolicyCommon. r=gcp
The sandbox broker uses socketpair to construct the per-request channels over which responses are sent; thus, if and only if the policy will be using brokering, it will allow socketpair as safely as possible (i.e., denying datagram sockets if possible). Depends on D14522 Differential Revision: https://phabricator.services.mozilla.com/D14523 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
2dfa36102d
Коммит
bb4d6b8630
|
@ -292,6 +292,24 @@ class SandboxPolicyCommon : public SandboxPolicyBase {
|
|||
return broker->Readlink(path, buf, size);
|
||||
}
|
||||
|
||||
static intptr_t SocketpairDatagramTrap(ArgsRef aArgs, void* aux) {
|
||||
auto fds = reinterpret_cast<int*>(aArgs.args[3]);
|
||||
// Return sequential packet sockets instead of the expected
|
||||
// datagram sockets; see bug 1355274 for details.
|
||||
return ConvertError(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
|
||||
}
|
||||
|
||||
static intptr_t SocketpairUnpackTrap(ArgsRef aArgs, void* aux) {
|
||||
#ifdef __NR_socketpair
|
||||
auto argsPtr = reinterpret_cast<unsigned long*>(aArgs.args[1]);
|
||||
return DoSyscall(__NR_socketpair, argsPtr[0], argsPtr[1], argsPtr[2],
|
||||
argsPtr[3]);
|
||||
#else
|
||||
MOZ_CRASH("unreachable?");
|
||||
return -ENOSYS;
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
ResultExpr InvalidSyscall() const override {
|
||||
return Trap(BlockedSyscallTrap, nullptr);
|
||||
|
@ -341,6 +359,39 @@ class SandboxPolicyCommon : public SandboxPolicyBase {
|
|||
case SYS_RECVMSG:
|
||||
case SYS_SENDMSG:
|
||||
return Some(Allow());
|
||||
|
||||
case SYS_SOCKETPAIR: {
|
||||
// Allow "safe" (always connected) socketpairs when using the
|
||||
// file broker.
|
||||
if (mBroker == nullptr) {
|
||||
return Nothing();
|
||||
}
|
||||
// See bug 1066750.
|
||||
if (!aHasArgs) {
|
||||
// If this is a socketcall(2) platform, but the kernel also
|
||||
// supports separate syscalls (>= 4.2.0), we can unpack the
|
||||
// arguments and filter them.
|
||||
if (HasSeparateSocketCalls()) {
|
||||
return Some(Trap(SocketpairUnpackTrap, nullptr));
|
||||
}
|
||||
// Otherwise, 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(domain == AF_UNIX,
|
||||
Switch(type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
|
||||
.Case(SOCK_STREAM, Allow())
|
||||
.Case(SOCK_SEQPACKET, Allow())
|
||||
// This is used only by content (and only for
|
||||
// direct PulseAudio, which is deprecated) but it
|
||||
// doesn't increase attack surface:
|
||||
.Case(SOCK_DGRAM, Trap(SocketpairDatagramTrap, nullptr))
|
||||
.Default(InvalidSyscall()))
|
||||
.Else(InvalidSyscall()));
|
||||
}
|
||||
|
||||
default:
|
||||
return Nothing();
|
||||
}
|
||||
|
@ -601,25 +652,6 @@ class ContentSandboxPolicy : public SandboxPolicyCommon {
|
|||
return AllowBelowLevel(aLevel, InvalidSyscall());
|
||||
}
|
||||
|
||||
// Returns true if the running kernel supports separate syscalls for
|
||||
// socket operations, or false if it supports only socketcall(2).
|
||||
static bool HasSeparateSocketCalls() {
|
||||
# ifdef __NR_socket
|
||||
// If there's no socketcall, then obviously there are separate syscalls.
|
||||
# ifdef __NR_socketcall
|
||||
int fd = syscall(__NR_socket, AF_LOCAL, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(errno == ENOSYS);
|
||||
return false;
|
||||
}
|
||||
close(fd);
|
||||
# endif // __NR_socketcall
|
||||
return true;
|
||||
# else // ifndef __NR_socket
|
||||
return false;
|
||||
# endif // __NR_socket
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -627,24 +659,6 @@ class ContentSandboxPolicy : public SandboxPolicyCommon {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static intptr_t SocketpairDatagramTrap(ArgsRef aArgs, void* aux) {
|
||||
auto fds = reinterpret_cast<int*>(aArgs.args[3]);
|
||||
// Return sequential packet sockets instead of the expected
|
||||
// datagram sockets; see bug 1355274 for details.
|
||||
return ConvertError(socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
|
||||
}
|
||||
|
||||
static intptr_t SocketpairUnpackTrap(ArgsRef aArgs, void* aux) {
|
||||
# ifdef __NR_socketpair
|
||||
auto argsPtr = reinterpret_cast<unsigned long*>(aArgs.args[1]);
|
||||
return DoSyscall(__NR_socketpair, argsPtr[0], argsPtr[1], argsPtr[2],
|
||||
argsPtr[3]);
|
||||
# else
|
||||
MOZ_CRASH("unreachable?");
|
||||
return -ENOSYS;
|
||||
# endif
|
||||
}
|
||||
|
||||
static intptr_t StatFsTrap(ArgsRef aArgs, void* aux) {
|
||||
// Warning: the kernel interface is not the C interface. The
|
||||
// structs are different (<asm/statfs.h> vs. <sys/statfs.h>), and
|
||||
|
@ -811,30 +825,6 @@ class ContentSandboxPolicy : public SandboxPolicyCommon {
|
|||
case SYS_SENDMMSG: // libresolv via libasyncns; see bug 1355274
|
||||
return Some(Allow());
|
||||
|
||||
case SYS_SOCKETPAIR: {
|
||||
// See bug 1066750.
|
||||
if (!aHasArgs) {
|
||||
// If this is a socketcall(2) platform, but the kernel also
|
||||
// supports separate syscalls (>= 4.2.0), we can unpack the
|
||||
// arguments and filter them.
|
||||
if (HasSeparateSocketCalls()) {
|
||||
return Some(Trap(SocketpairUnpackTrap, nullptr));
|
||||
}
|
||||
// Otherwise, 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(domain == AF_UNIX,
|
||||
Switch(type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK))
|
||||
.Case(SOCK_STREAM, Allow())
|
||||
.Case(SOCK_SEQPACKET, Allow())
|
||||
.Case(SOCK_DGRAM, Trap(SocketpairDatagramTrap, nullptr))
|
||||
.Default(InvalidSyscall()))
|
||||
.Else(InvalidSyscall()));
|
||||
}
|
||||
|
||||
# ifdef ANDROID
|
||||
case SYS_SOCKET:
|
||||
return Some(Error(EACCES));
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
# include <linux/ipc.h>
|
||||
#endif
|
||||
#include <linux/net.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "sandbox/linux/bpf_dsl/bpf_dsl.h"
|
||||
|
@ -120,4 +123,23 @@ sandbox::bpf_dsl::ResultExpr SandboxPolicyBase::EvaluateSyscall(
|
|||
}
|
||||
}
|
||||
|
||||
/* static */ bool SandboxPolicyBase::HasSeparateSocketCalls() {
|
||||
#ifdef __NR_socket
|
||||
// If there's no socketcall, then obviously there are separate syscalls.
|
||||
# ifdef __NR_socketcall
|
||||
// This could be memoized, but currently it's called at most once
|
||||
// per process.
|
||||
int fd = syscall(__NR_socket, AF_LOCAL, SOCK_STREAM, 0);
|
||||
if (fd < 0) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(errno == ENOSYS);
|
||||
return false;
|
||||
}
|
||||
close(fd);
|
||||
# endif // __NR_socketcall
|
||||
return true;
|
||||
#else // ifndef __NR_socket
|
||||
return false;
|
||||
#endif // __NR_socket
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -49,6 +49,10 @@ class SandboxPolicyBase : public sandbox::bpf_dsl::Policy {
|
|||
return Nothing();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Returns true if the running kernel supports separate syscalls for
|
||||
// socket operations, or false if it supports only socketcall(2).
|
||||
static bool HasSeparateSocketCalls();
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
Загрузка…
Ссылка в новой задаче