зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1425274 - Filter socketpair() in content sandbox on 32-bit x86 with new-enough kernels. r=gcp
This replaces the globals for whether socket calls (and ipc(2) calls, but we never used that) have real arguments with a parameter, which in hindsight should have been done in bug 1273852, which is when we started handling both socketcall(2) and separate socket calls in the same policy. This allows handling the two cases differently. MozReview-Commit-ID: 1pfckmCpJlW --HG-- extra : rebase_source : 4b8459f01e8748fea95cbcb6eeb689f01417ca5b
This commit is contained in:
Родитель
5fe1b2b553
Коммит
927e70c7a5
|
@ -177,7 +177,7 @@ public:
|
|||
.Default(InvalidSyscall());
|
||||
}
|
||||
|
||||
Maybe<ResultExpr> EvaluateSocketCall(int aCall) const override {
|
||||
Maybe<ResultExpr> EvaluateSocketCall(int aCall, bool aHasArgs) const override {
|
||||
switch (aCall) {
|
||||
case SYS_RECVMSG:
|
||||
case SYS_SENDMSG:
|
||||
|
@ -389,6 +389,26 @@ private:
|
|||
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
|
||||
}
|
||||
|
||||
// Trap handlers for filesystem brokering.
|
||||
// (The amount of code duplication here could be improved....)
|
||||
#ifdef __NR_open
|
||||
|
@ -557,6 +577,17 @@ private:
|
|||
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
|
||||
|
@ -601,7 +632,7 @@ public:
|
|||
|
||||
~ContentSandboxPolicy() override = default;
|
||||
|
||||
Maybe<ResultExpr> EvaluateSocketCall(int aCall) const override {
|
||||
Maybe<ResultExpr> EvaluateSocketCall(int aCall, bool aHasArgs) const override {
|
||||
switch(aCall) {
|
||||
case SYS_RECVFROM:
|
||||
case SYS_SENDTO:
|
||||
|
@ -610,8 +641,15 @@ public:
|
|||
|
||||
case SYS_SOCKETPAIR: {
|
||||
// See bug 1066750.
|
||||
if (!kSocketCallHasArgs) {
|
||||
// We can't filter the args if the platform passes them by pointer.
|
||||
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);
|
||||
|
@ -645,7 +683,7 @@ public:
|
|||
return Some(Allow());
|
||||
#endif
|
||||
default:
|
||||
return SandboxPolicyCommon::EvaluateSocketCall(aCall);
|
||||
return SandboxPolicyCommon::EvaluateSocketCall(aCall, aHasArgs);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ SandboxPolicyBase::EvaluateSyscall(int aSysno) const {
|
|||
Arg<int> call(0);
|
||||
UniquePtr<Caser<int>> acc(new Caser<int>(Switch(call)));
|
||||
for (int i = SYS_SOCKET; i <= SYS_SENDMMSG; ++i) {
|
||||
auto thisCase = EvaluateSocketCall(i);
|
||||
auto thisCase = EvaluateSocketCall(i, false);
|
||||
// Optimize out cases that are equal to the default.
|
||||
if (thisCase) {
|
||||
acc.reset(new Caser<int>(acc->Case(i, *thisCase)));
|
||||
|
@ -65,7 +65,7 @@ SandboxPolicyBase::EvaluateSyscall(int aSysno) const {
|
|||
#endif // __NR_socketcall
|
||||
#define DISPATCH_SOCKETCALL(sysnum, socketnum) \
|
||||
case sysnum: \
|
||||
return EvaluateSocketCall(socketnum).valueOr(InvalidSyscall())
|
||||
return EvaluateSocketCall(socketnum, true).valueOr(InvalidSyscall())
|
||||
#ifdef __NR_socket
|
||||
DISPATCH_SOCKETCALL(__NR_socket, SYS_SOCKET);
|
||||
DISPATCH_SOCKETCALL(__NR_bind, SYS_BIND);
|
||||
|
|
|
@ -23,7 +23,8 @@ namespace mozilla {
|
|||
// respectively; on most other architectures they're individual system
|
||||
// calls. It translates the syscalls into socketcall/ipc selector
|
||||
// values, because those are defined (even if not used) for all
|
||||
// architectures.
|
||||
// architectures. (As of kernel 4.2.0, x86 also has regular system
|
||||
// calls, but userland will typically still use socketcall.)
|
||||
//
|
||||
// This EvaluateSyscall() routine always returns InvalidSyscall() for
|
||||
// everything else. It's assumed that subclasses will be implementing
|
||||
|
@ -35,9 +36,13 @@ public:
|
|||
using ResultExpr = sandbox::bpf_dsl::ResultExpr;
|
||||
|
||||
virtual ResultExpr EvaluateSyscall(int aSysno) const override;
|
||||
virtual Maybe<ResultExpr> EvaluateSocketCall(int aCall) const {
|
||||
|
||||
// aHasArgs is true if this is a normal syscall, where the arguments
|
||||
// can be inspected by seccomp-bpf, rather than a case of socketcall().
|
||||
virtual Maybe<ResultExpr> EvaluateSocketCall(int aCall, bool aHasArgs) const {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
#ifndef ANDROID
|
||||
// Android doesn't use SysV IPC (and doesn't define the selector
|
||||
// constants in its headers), so this isn't implemented there.
|
||||
|
@ -45,17 +50,6 @@ public:
|
|||
return Nothing();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __NR_socketcall
|
||||
// socketcall(2) takes the actual call's arguments via a pointer, so
|
||||
// seccomp-bpf can't inspect them; ipc(2) takes them at different indices.
|
||||
static const bool kSocketCallHasArgs = false;
|
||||
static const bool kIpcCallNormalArgs = false;
|
||||
#else
|
||||
// Otherwise, the bpf_dsl Arg<> class can be used normally.
|
||||
static const bool kSocketCallHasArgs = true;
|
||||
static const bool kIpcCallNormalArgs = true;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
Загрузка…
Ссылка в новой задаче